diff --git a/resources/images/icons2/16x16/remove@2x.png b/resources/images/icons2/16x16/remove@2x.png new file mode 100644 index 0000000000..b21daa5846 Binary files /dev/null and b/resources/images/icons2/16x16/remove@2x.png differ diff --git a/resources/images/icons2/16x16/remove@3x.png b/resources/images/icons2/16x16/remove@3x.png new file mode 100644 index 0000000000..e5c482ae83 Binary files /dev/null and b/resources/images/icons2/16x16/remove@3x.png differ diff --git a/src/quo/components/numbered_keyboard/keyboard_key/view.cljs b/src/quo/components/numbered_keyboard/keyboard_key/view.cljs index a53ee76ccc..337b7e938a 100644 --- a/src/quo/components/numbered_keyboard/keyboard_key/view.cljs +++ b/src/quo/components/numbered_keyboard/keyboard_key/view.cljs @@ -15,9 +15,9 @@ [{:keys [disabled? blur? on-press on-long-press type]} label] (let [theme (quo.theme/use-theme-value) [pressed? set-pressed?] (rn/use-state false) - on-press (rn/use-callback #(when on-press (on-press label)) [label]) + on-press (rn/use-callback #(when on-press (on-press label)) [on-press label]) on-long-press (rn/use-callback #(when (fn? on-long-press) (on-long-press label)) - [label]) + [on-long-press label]) on-press-in (rn/use-callback #(set-pressed? true)) on-press-out (rn/use-callback #(set-pressed? false)) label-color (style/get-label-color disabled? theme blur?) diff --git a/src/quo/components/profile/expanded_collectible/style.cljs b/src/quo/components/profile/expanded_collectible/style.cljs index 798970dad7..1d76283af7 100644 --- a/src/quo/components/profile/expanded_collectible/style.cljs +++ b/src/quo/components/profile/expanded_collectible/style.cljs @@ -4,8 +4,7 @@ (def container (merge (shadows/get 2) - {:flex 1 - :align-items :center + {:align-items :center :justify-content :center :border-radius 16})) diff --git a/src/quo/components/profile/expanded_collectible/view.cljs b/src/quo/components/profile/expanded_collectible/view.cljs index 53893ee155..01c5e60cd6 100644 --- a/src/quo/components/profile/expanded_collectible/view.cljs +++ b/src/quo/components/profile/expanded_collectible/view.cljs @@ -55,7 +55,7 @@ {:label (i18n/label :t/cant-fetch-info) :counter counter :theme theme}] - [rn/view {:style {:flex 1}} + [rn/view [rn/image {:style (style/image square? (:aspect-ratio image-size)) :source image-src}] @@ -66,7 +66,7 @@ [:catn [:props [:map {:closed true} - [:image-src {:optional true} string?] + [:image-src {:optional true} [:maybe string?]] [:container-style {:optional true} [:maybe :map]] [:square? {:optional true} [:maybe boolean?]] [:counter {:optional true} [:maybe string?]] diff --git a/src/quo/components/tags/network_tags/view.cljs b/src/quo/components/tags/network_tags/view.cljs index f30093bde0..cb9d9a412a 100644 --- a/src/quo/components/tags/network_tags/view.cljs +++ b/src/quo/components/tags/network_tags/view.cljs @@ -7,11 +7,12 @@ [react-native.core :as rn])) (defn- view-internal - [{:keys [title networks status theme blur?] :or {status :default}}] + [{:keys [title networks status theme blur? container-style] :or {status :default}}] [rn/view - {:style (style/container {:status status - :theme theme - :blur? blur?})} + {:style (merge (style/container {:status status + :theme theme + :blur? blur?}) + container-style)} [preview-list/view {:type :network :number (count networks) diff --git a/src/quo/components/wallet/amount_input/component_spec.cljs b/src/quo/components/wallet/amount_input/component_spec.cljs index 062aab9007..276bd23312 100644 --- a/src/quo/components/wallet/amount_input/component_spec.cljs +++ b/src/quo/components/wallet/amount_input/component_spec.cljs @@ -12,32 +12,24 @@ (h/describe "Amount input component" (h/test "Renders with default value" (let [text-expected 0] - (render [amount-input/view {:init-value text-expected}]) - (h/is-truthy (h/query-by-label-text :amount-input)) - (h/is-equal (oops/oget (h/get-by-label-text :amount-input) "props" "value") - (str text-expected)))) + (render [amount-input/view {:value text-expected}]) + (h/is-truthy (h/query-by-label-text :amount-input)))) (h/test "When the value = minimum dec button is disabled" (render [amount-input/view - {:init-value 0 - :min-value 0}]) + {:value 0 + :min-value 0}]) (h/is-truthy (oops/oget (h/get-by-label-text :amount-input-dec-button) "props" "accessibilityState" "disabled"))) (h/test "When the value = maximum inc button is disabled" (render [amount-input/view - {:init-value 100 - :max-value 100}]) + {:value 100 + :max-value 100}]) (h/is-truthy (oops/oget (h/get-by-label-text :amount-input-inc-button) "props" "accessibilityState" "disabled"))) (h/test "Renders the error state" - (render [amount-input/view {:status :error}]) + (render [amount-input/view {:status :error :value 10}]) (h/is-equal (colors/resolve-color :danger :light) - (oops/oget (h/get-by-label-text :amount-input) "props" "style" "color"))) - - (h/test "on-change-text function is fired" - (let [on-change-text (h/mock-fn)] - (render [amount-input/view {:on-change-text on-change-text}]) - (h/fire-event :change-text (h/get-by-label-text :amount-input) "100") - (h/was-called on-change-text)))) + (oops/oget (h/get-by-label-text :amount-input) "props" "style" "color")))) diff --git a/src/quo/components/wallet/amount_input/schema.cljs b/src/quo/components/wallet/amount_input/schema.cljs index 4923c11dcf..9510a2bdee 100644 --- a/src/quo/components/wallet/amount_input/schema.cljs +++ b/src/quo/components/wallet/amount_input/schema.cljs @@ -1,9 +1,5 @@ (ns quo.components.wallet.amount-input.schema) -(def return-key-types - [:enum :done :go :next :search :send :none :previous :default - :emergency-call :google :join :route :yahoo]) - (def ?schema [:=> [:catn @@ -11,11 +7,10 @@ [:map {:closed true} [:status {:optional true} [:maybe [:enum :default :error]]] [:theme :schema.common/theme] - [:on-change-text {:optional true} [:maybe fn?]] + [:on-inc-press {:optional true} [:maybe fn?]] + [:on-dec-press {:optional true} [:maybe fn?]] [:container-style {:optional true} [:maybe :map]] - [:auto-focus? {:optional true} [:maybe :boolean]] [:min-value {:optional true} [:maybe :int]] [:max-value {:optional true} [:maybe :int]] - [:return-key-type {:optional true} [:maybe return-key-types]] - [:init-value {:optional true} [:maybe :int]]]]] + [:value [:maybe :int]]]]] :any]) diff --git a/src/quo/components/wallet/amount_input/style.cljs b/src/quo/components/wallet/amount_input/style.cljs index 873299c729..5832d7c79f 100644 --- a/src/quo/components/wallet/amount_input/style.cljs +++ b/src/quo/components/wallet/amount_input/style.cljs @@ -12,6 +12,7 @@ (defn input-text [theme type] {:padding 0 + :align :center :color (if (= type :error) (colors/resolve-color :danger theme) (colors/theme-colors colors/neutral-100 colors/white theme))}) diff --git a/src/quo/components/wallet/amount_input/view.cljs b/src/quo/components/wallet/amount_input/view.cljs index 2d21862bbf..c1b2cca8bf 100644 --- a/src/quo/components/wallet/amount_input/view.cljs +++ b/src/quo/components/wallet/amount_input/view.cljs @@ -6,7 +6,6 @@ [quo.components.wallet.amount-input.style :as style] [quo.theme :as quo.theme] [react-native.core :as rn] - [reagent.core :as reagent] [schema.core :as schema])) (defn- amount-button @@ -21,60 +20,35 @@ :on-press on-press} icon]) -(defn- process-amount - [input-value min-value max-value] - (let [parsed-input-value (parse-double input-value)] - (cond - (nil? parsed-input-value) min-value - (>= input-value max-value) max-value - (<= input-value min-value) min-value - :else parsed-input-value))) - (defn- view-internal - [{:keys [init-value]}] - (let [init-value (or init-value 0) - value (reagent/atom init-value) - on-dec-press #(swap! value dec) - on-inc-press #(swap! value inc)] - (fn [{:keys [theme status min-value max-value auto-focus? - return-key-type container-style on-change-text]}] - (let [min-value (or min-value 0) - max-value (or max-value 999999999)] - [rn/view - {:style (merge style/container container-style)} - [amount-button - {:theme theme - :accessibility-label :amount-input-dec-button - :icon :i/remove - :on-press on-dec-press - :disabled? (>= min-value @value)}] - [rn/view {:style style/input-container} - [rn/text-input - {:style - (text/text-style - {:size :heading-1 - :weight :semi-bold - :align :center - :style (style/input-text theme (or status :default))}) - :accessibility-label :amount-input - :editable true - :auto-focus (or auto-focus? false) - :value (str @value) - :keyboard-appearance (quo.theme/theme-value :light :dark theme) - :return-key-type (or return-key-type :done) - :input-mode :numeric - :on-change-text (fn [input-value] - (let [processed-amount (process-amount input-value min-value max-value)] - (reset! value processed-amount) - (when on-change-text - (on-change-text processed-amount)) - (reagent/flush)))}]] ; Fixes the input flickering issue when typing. - [amount-button - {:theme theme - :icon :i/add - :accessibility-label :amount-input-inc-button - :on-press on-inc-press - :disabled? (>= @value max-value)}]])))) + [{:keys [on-inc-press on-dec-press theme status value min-value max-value + container-style] + :or {value 0 + min-value 0 + max-value 999999999}}] + [rn/view + {:style (merge style/container container-style)} + [amount-button + {:theme theme + :accessibility-label :amount-input-dec-button + :icon :i/remove + :on-press on-dec-press + :disabled? (>= min-value value)}] + [rn/view {:style style/input-container} + [text/text + {:number-of-lines 1 + :accessibility-label :amount-input + :weight :semi-bold + :size :heading-1 + :align-self :center + :style (style/input-text theme (or status :default))} + value]] + [amount-button + {:theme theme + :icon :i/add + :accessibility-label :amount-input-inc-button + :on-press on-inc-press + :disabled? (>= value max-value)}]]) (def view (quo.theme/with-theme diff --git a/src/status_im/contexts/preview/quo/wallet/amount_input.cljs b/src/status_im/contexts/preview/quo/wallet/amount_input.cljs index 6e94d96845..8038d44dc4 100644 --- a/src/status_im/contexts/preview/quo/wallet/amount_input.cljs +++ b/src/status_im/contexts/preview/quo/wallet/amount_input.cljs @@ -9,7 +9,7 @@ :type :number} {:key :min-value :type :number} - {:key :init-value + {:key :value :type :number} {:type :select :key :status @@ -18,12 +18,18 @@ (defn view [] - (let [state (reagent/atom {:max-value 10000 - :min-value 0 - :init-value 1 - :status :default})] + (let [state (reagent/atom {:max-value 10000 + :min-value 0 + :value 1 + :status :default}) + on-inc-press (fn [] (swap! state #(assoc % :value (inc (:value %))))) + on-dec-press (fn [] (swap! state #(assoc % :value (dec (:value %)))))] (fn [] [preview/preview-container {:state state :descriptor descriptor} - [quo/amount-input @state]]))) + [quo/amount-input + (merge + @state + {:on-dec-press on-dec-press + :on-inc-press on-inc-press})]]))) diff --git a/src/status_im/contexts/wallet/collectible/utils.cljs b/src/status_im/contexts/wallet/collectible/utils.cljs new file mode 100644 index 0000000000..3d85a152d9 --- /dev/null +++ b/src/status_im/contexts/wallet/collectible/utils.cljs @@ -0,0 +1,9 @@ +(ns status-im.contexts.wallet.collectible.utils) + +(defn collectible-balance + [collectible] + (-> collectible + :ownership + first + :balance + js/parseInt)) diff --git a/src/status_im/contexts/wallet/send/events.cljs b/src/status_im/contexts/wallet/send/events.cljs index 57d56db29c..7b08ba6da1 100644 --- a/src/status_im/contexts/wallet/send/events.cljs +++ b/src/status_im/contexts/wallet/send/events.cljs @@ -101,16 +101,24 @@ :amount (when (= transaction-type :collecible) :tx-type))}))) -(rf/reg-event-fx :wallet/send-select-collectible - (fn [{:keys [db]} [{:keys [collectible stack-id]}]] +(rf/reg-event-fx :wallet/send-collectibles-amount + (fn [{:keys [db]} [{:keys [collectible stack-id amount]}]] {:db (-> db (update-in [:wallet :ui :send] dissoc :token) (assoc-in [:wallet :ui :send :collectible] collectible) (assoc-in [:wallet :ui :send :tx-type] :collectible) - (assoc-in [:wallet :ui :send :amount] 1)) - :fx [[:dispatch [:wallet/get-suggested-routes {:amount 1}]] + (assoc-in [:wallet :ui :send :amount] amount)) + :fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]] [:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]})) +(rf/reg-event-fx :wallet/select-collectibles-amount + (fn [{:keys [db]} [{:keys [collectible stack-id]}]] + {:db (-> db + (update-in [:wallet :ui :send] dissoc :token) + (assoc-in [:wallet :ui :send :collectible] collectible) + (assoc-in [:wallet :ui :send :tx-type] :collectible)) + :fx [[:navigate-to-within-stack [:screen/wallet.select-collectible-amount stack-id]]]})) + (rf/reg-event-fx :wallet/send-select-amount (fn [{:keys [db]} [{:keys [amount stack-id start-flow?]}]] {:db (assoc-in db [:wallet :ui :send :amount] amount) diff --git a/src/status_im/contexts/wallet/send/select_asset/view.cljs b/src/status_im/contexts/wallet/send/select_asset/view.cljs index 212c7f3d75..c88f05a89f 100644 --- a/src/status_im/contexts/wallet/send/select_asset/view.cljs +++ b/src/status_im/contexts/wallet/send/select_asset/view.cljs @@ -5,6 +5,7 @@ [quo.theme :as quo.theme] [react-native.core :as rn] [reagent.core :as reagent] + [status-im.contexts.wallet.collectible.utils :as utils] [status-im.contexts.wallet.common.account-switcher.view :as account-switcher] [status-im.contexts.wallet.common.asset-list.view :as asset-list] [status-im.contexts.wallet.common.collectibles-tab.view :as collectibles-tab] @@ -34,9 +35,15 @@ {:collectibles collectibles :filtered? search-performed? :on-end-reached #(rf/dispatch [:wallet/request-collectibles-for-current-viewing-account]) - :on-collectible-press #(rf/dispatch [:wallet/send-select-collectible - {:collectible % - :stack-id :screen/wallet.select-asset}])}])) + :on-collectible-press #(let [collectibles-count (utils/collectible-balance %)] + (if (> collectibles-count 1) + (rf/dispatch [:wallet/select-collectibles-amount + {:collectible % + :stack-id :screen/wallet.select-asset}]) + (rf/dispatch [:wallet/send-collectibles-amount + {:collectible % + :amount 1 + :stack-id :screen/wallet.select-asset}])))}])) (defn- tab-view [search-text selected-tab on-change-text] (let [unfiltered-collectibles (rf/sub [:wallet/current-viewing-account-collectibles]) diff --git a/src/status_im/contexts/wallet/send/select_collectible_amount/style.cljs b/src/status_im/contexts/wallet/send/select_collectible_amount/style.cljs new file mode 100644 index 0000000000..ebb5a58b73 --- /dev/null +++ b/src/status_im/contexts/wallet/send/select_collectible_amount/style.cljs @@ -0,0 +1,13 @@ +(ns status-im.contexts.wallet.send.select-collectible-amount.style) + +(def collectible-container + {:margin-vertical 12 + :margin-horizontal 56}) + +(def network-tags-container + {:align-self :center}) + +(def amount-input-container + {:padding-left 20 + :padding-right 20 + :margin-vertical 12}) diff --git a/src/status_im/contexts/wallet/send/select_collectible_amount/view.cljs b/src/status_im/contexts/wallet/send/select_collectible_amount/view.cljs new file mode 100644 index 0000000000..7582e7c926 --- /dev/null +++ b/src/status_im/contexts/wallet/send/select_collectible_amount/view.cljs @@ -0,0 +1,67 @@ +(ns status-im.contexts.wallet.send.select-collectible-amount.view + (:require + [quo.core :as quo] + [react-native.core :as rn] + [status-im.contexts.wallet.collectible.utils :as utils] + [status-im.contexts.wallet.common.account-switcher.view :as account-switcher] + [status-im.contexts.wallet.send.select-collectible-amount.style :as style] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn view + [] + (let [on-close (rn/use-callback #(rf/dispatch [:navigate-back])) + [value set-value] (rn/use-state 1) + inc-value (rn/use-callback (fn [] (set-value (inc value))) + [value]) + dec-value (rn/use-callback (fn [] (set-value (dec value))) + [value]) + add-digit (rn/use-callback (fn [digit] + (set-value (+ (js/parseInt digit) + (* value 10)))) + [value]) + delete-digit (rn/use-callback (fn [] + (set-value (Math/floor (/ value 10)))) + [value]) + + send-transaction-data (rf/sub [:wallet/wallet-send]) + collectible (:collectible send-transaction-data) + balance (utils/collectible-balance collectible) + preview-uri (get-in collectible [:preview-url :uri]) + incorrect-value? (or (< value 1) (> value balance))] + [rn/view + [account-switcher/view + {:icon-name :i/arrow-left + :on-press on-close + :switcher-type :select-account}] + [quo/expanded-collectible + {:image-src preview-uri + :square? true + :container-style style/collectible-container}] + [quo/network-tags + {:title (i18n/label :t/max {:number balance}) + :status (if incorrect-value? :error :default) + :container-style style/network-tags-container}] + + [quo/amount-input + {:max-value (if (integer? balance) balance 0) + :min-value 1 + :value value + :on-inc-press inc-value + :on-dec-press dec-value + :container-style style/amount-input-container + :status (if incorrect-value? :error :default)}] + [quo/bottom-actions + {:actions :one-action + :button-one-props {:on-press #(rf/dispatch [:wallet/send-collectibles-amount + {:collectible collectible + :amount value + :stack-id :screen/wallet.select-asset}]) + :disabled? incorrect-value?} + :button-one-label (i18n/label :t/confirm)}] + [quo/numbered-keyboard + {:left-action :none + :delete-key? true + :on-press add-digit + :on-delete delete-digit}]])) + diff --git a/src/status_im/navigation/screens.cljs b/src/status_im/navigation/screens.cljs index 95c307d24e..a7035889d8 100644 --- a/src/status_im/navigation/screens.cljs +++ b/src/status_im/navigation/screens.cljs @@ -77,6 +77,7 @@ [status-im.contexts.wallet.send.save-address.view :as wallet-save-address] [status-im.contexts.wallet.send.select-address.view :as wallet-select-address] [status-im.contexts.wallet.send.select-asset.view :as wallet-select-asset] + [status-im.contexts.wallet.send.select-collectible-amount.view :as wallet-select-collectible-amount] [status-im.contexts.wallet.send.send-amount.view :as wallet-send-input-amount] [status-im.contexts.wallet.send.transaction-confirmation.view :as wallet-transaction-confirmation] [status-im.contexts.wallet.send.transaction-progress.view :as wallet-transaction-progress] @@ -428,6 +429,10 @@ {:name :screen/wallet.transaction-confirmation :component wallet-transaction-confirmation/view} + {:name :screen/wallet.select-collectible-amount + :options {:insets {:top? true}} + :component wallet-select-collectible-amount/view} + {:name :screen/wallet.transaction-progress :component wallet-transaction-progress/view} diff --git a/translations/en.json b/translations/en.json index 0b8f906f2e..465af28497 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2561,5 +2561,6 @@ "address-count": { "one": "1 address", "other": "{{count}} addresses" - } + }, + "max": "Max: {{number}}" }