diff --git a/android/app/src/main/res/drawable-mdpi/commands.png b/android/app/src/main/res/drawable-mdpi/commands.png index 9a8bea3728..8f3c94a4cd 100644 Binary files a/android/app/src/main/res/drawable-mdpi/commands.png and b/android/app/src/main/res/drawable-mdpi/commands.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/commands.png b/android/app/src/main/res/drawable-xhdpi/commands.png index 7c92378ef6..ea6226849c 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/commands.png and b/android/app/src/main/res/drawable-xhdpi/commands.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/commands.png b/android/app/src/main/res/drawable-xxhdpi/commands.png index 4141434551..e5ba4e2aa7 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/commands.png and b/android/app/src/main/res/drawable-xxhdpi/commands.png differ diff --git a/components/src/status_im/ui/components/react.cljs b/components/src/status_im/ui/components/react.cljs index 633d0037ce..bcbddf6b70 100644 --- a/components/src/status_im/ui/components/react.cljs +++ b/components/src/status_im/ui/components/react.cljs @@ -302,7 +302,13 @@ (defn create-main-screen-view [current-view] (fn [props & children] - (apply vector (adapt-class (object/get js-dependencies/safe-area-context "SafeAreaView")) props children))) + (apply + vector + (adapt-class (object/get js-dependencies/safe-area-context "SafeAreaView")) + (cond-> props + (= current-view :qr-scanner) + (assoc :background-color :black)) + children))) (defn main-screen-modal-view [current-view & components] ;; NOTE on Android we use Modal component and it manages statusbar area by itself diff --git a/ios/StatusIm/Images.xcassets/commands.imageset/commands.png b/ios/StatusIm/Images.xcassets/commands.imageset/commands.png index 9a8bea3728..8f3c94a4cd 100644 Binary files a/ios/StatusIm/Images.xcassets/commands.imageset/commands.png and b/ios/StatusIm/Images.xcassets/commands.imageset/commands.png differ diff --git a/ios/StatusIm/Images.xcassets/commands.imageset/commands@2x.png b/ios/StatusIm/Images.xcassets/commands.imageset/commands@2x.png index 7c92378ef6..ea6226849c 100644 Binary files a/ios/StatusIm/Images.xcassets/commands.imageset/commands@2x.png and b/ios/StatusIm/Images.xcassets/commands.imageset/commands@2x.png differ diff --git a/ios/StatusIm/Images.xcassets/commands.imageset/commands@3x.png b/ios/StatusIm/Images.xcassets/commands.imageset/commands@3x.png index ddd9b0c93b..e5ba4e2aa7 100644 Binary files a/ios/StatusIm/Images.xcassets/commands.imageset/commands@3x.png and b/ios/StatusIm/Images.xcassets/commands.imageset/commands@3x.png differ diff --git a/src/status_im/browser/permissions.cljs b/src/status_im/browser/permissions.cljs index 9413e0b3ab..2f0f11130f 100644 --- a/src/status_im/browser/permissions.cljs +++ b/src/status_im/browser/permissions.cljs @@ -26,8 +26,7 @@ (cond (= permission constants/dapp-permission-qr-code) (fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] true) - (qr-scanner/scan-qr-code {} - {:handler :browser.bridge.callback/qr-code-scanned + (qr-scanner/scan-qr-code {:handler :browser.bridge.callback/qr-code-scanned :cancel-handler :browser.bridge.callback/qr-code-canceled :data {:dapp-name dapp-name :permission permission diff --git a/src/status_im/core.cljs b/src/status_im/core.cljs index 91b1c6f5d5..28ad323a07 100644 --- a/src/status_im/core.cljs +++ b/src/status_im/core.cljs @@ -12,10 +12,9 @@ (if js/goog.DEBUG (.ignoreWarnings (.-YellowBox js-dependencies/react-native) - #js - ["re-frame: overwriting" - "Warning: componentWillMount is deprecated and will be removed in the next major version. Use componentDidMount instead. As a temporary workaround, you can rename to UNSAFE_componentWillMount." - "Warning: componentWillUpdate is deprecated and will be removed in the next major version. Use componentDidUpdate instead. As a temporary workaround, you can rename to UNSAFE_componentWillUpdate."]) + #js ["re-frame: overwriting" + "Warning: componentWillMount is deprecated and will be removed in the next major version. Use componentDidMount instead. As a temporary workaround, you can rename to UNSAFE_componentWillMount." + "Warning: componentWillUpdate is deprecated and will be removed in the next major version. Use componentDidUpdate instead. As a temporary workaround, you can rename to UNSAFE_componentWillUpdate."]) (aset js/console "disableYellowBox" true)) (defn init [app-root] diff --git a/src/status_im/ethereum/core.cljs b/src/status_im/ethereum/core.cljs index ef775304e9..7a5b965873 100644 --- a/src/status_im/ethereum/core.cljs +++ b/src/status_im/ethereum/core.cljs @@ -34,6 +34,10 @@ (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])) @@ -91,6 +95,9 @@ (defn network->chain-keyword [network] (chain-id->chain-keyword (network->chain-id network))) +(defn network->network-name [network] + (chain-id->chain-name (network->chain-id network))) + (defn network->chain-name [network] (-> network network->chain-keyword diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 203d170ce6..361f170f20 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -222,7 +222,7 @@ (handlers/register-handler-fx :mailserver.callback/qr-code-scanned - (fn [cofx [_ _ url]] + (fn [cofx [_ url _]] (mailserver/set-url-from-qr cofx url))) (handlers/register-handler-fx @@ -327,7 +327,7 @@ (handlers/register-handler-fx :bootnodes.callback/qr-code-scanned - (fn [cofx [_ _ url]] + (fn [cofx [_ url _]] (bootnodes/set-bootnodes-from-qr cofx url))) (handlers/register-handler-fx @@ -386,30 +386,32 @@ (handlers/register-handler-fx :browser.bridge.callback/qr-code-scanned - (fn [cofx [_ _ data qr-code-data]] + (fn [cofx [_ data qr-code-data]] (browser/handle-scanned-qr-code cofx data (:data qr-code-data)))) (handlers/register-handler-fx :browser.bridge.callback/qr-code-canceled - (fn [cofx [_ _ qr-code-data]] + (fn [cofx [_ qr-code-data _]] (browser/handle-canceled-qr-code cofx (:data qr-code-data)))) ;; qr-scanner module (handlers/register-handler-fx :qr-scanner.ui/scan-qr-code-pressed - (fn [cofx [_ identifier handler & [opts]]] - (qr-scanner/scan-qr-code cofx identifier (merge {:handler handler} opts)))) + (fn [cofx [_ opts]] + (qr-scanner/scan-qr-code cofx opts))) (handlers/register-handler-fx :qr-scanner.callback/scan-qr-code-success - (fn [cofx [_ context data]] - (qr-scanner/set-qr-code cofx context data))) + (fn [cofx [_ opts data]] + (qr-scanner/set-qr-code cofx opts data))) (handlers/register-handler-fx :qr-scanner.callback/scan-qr-code-cancel - (fn [cofx [_ context]] - (qr-scanner/set-qr-code-cancel cofx context))) + (fn [cofx [_ opts]] + (fx/merge cofx + (qr-scanner/set-qr-code-cancel opts) + (navigation/navigate-back)))) ;; privacy-policy module @@ -1268,7 +1270,7 @@ (handlers/register-handler-fx :contact/qr-code-scanned [(re-frame/inject-cofx :random-id-generator)] - (fn [{:keys [db] :as cofx} [_ _ contact-identity]] + (fn [{:keys [db] :as cofx} [_ contact-identity _]] (let [current-multiaccount (:multiaccount db) fx {:db (assoc db :contacts/new-identity contact-identity)} validation-result (new-chat.db/validate-pub-key db contact-identity)] @@ -1574,6 +1576,11 @@ (fn [] (react/dismiss-keyboard!))) +(handlers/register-handler-fx + :dismiss-keyboard + (fn [_] + {:dismiss-keyboard nil})) + (handlers/register-handler-fx :wallet-send-request (fn [{:keys [db] :as cofx} [_ public-key amount symbol decimals]] @@ -1585,4 +1592,4 @@ (commands.sending/send public-key request-command {:asset (name symbol) - :amount (str (money/internal->formatted amount symbol decimals))}))))) + :amount (str (money/internal->formatted amount symbol decimals))}))))) \ No newline at end of file diff --git a/src/status_im/qr_scanner/core.cljs b/src/status_im/qr_scanner/core.cljs index 734fc546f7..014bd6f751 100644 --- a/src/status_im/qr_scanner/core.cljs +++ b/src/status_im/qr_scanner/core.cljs @@ -5,33 +5,22 @@ [status-im.utils.fx :as fx])) (fx/defn scan-qr-code - [{:keys [db]} {:keys [deny-handler] :as identifier} qr-codes] - {:db (assoc-in db [:qr-codes identifier] qr-codes) - :request-permissions-fx {:permissions [:camera] - :on-allowed #(re-frame/dispatch - [:navigate-to :qr-scanner - {:current-qr-context identifier}]) - :on-denied (if (nil? deny-handler) - (fn [] - (utils/set-timeout - #(utils/show-popup (i18n/label :t/error) - (i18n/label :t/camera-access-error)) - 50)) - #(re-frame/dispatch [deny-handler qr-codes]))}}) + [_ opts] + {:request-permissions-fx + {:permissions [:camera] + :on-allowed #(re-frame/dispatch [:navigate-to :qr-scanner opts]) + :on-denied (fn [] + (utils/set-timeout + #(utils/show-popup (i18n/label :t/error) + (i18n/label :t/camera-access-error)) + 50))}}) (fx/defn set-qr-code - [{:keys [db]} context data] - (merge {:db (-> db - (update :qr-codes dissoc context) - (dissoc :current-qr-context))} - (when-let [qr-codes (get-in db [:qr-codes context])] - {:dispatch [(:handler qr-codes) context data (dissoc qr-codes :handler)]}))) + [{:keys [db]} opts data] + (when-let [handler (:handler opts)] + {:dispatch [handler data opts]})) (fx/defn set-qr-code-cancel - [{:keys [db]} context] - (merge {:db (-> db - (update :qr-codes dissoc context) - (dissoc :current-qr-context))} - (when-let [qr-codes (get-in db [:qr-codes context])] - (when-let [handler (:cancel-handler qr-codes)] - {:dispatch [handler context qr-codes]})))) + [_ opts] + (when-let [handler (:cancel-handler opts)] + {:dispatch [handler opts]})) diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 96bc9a1f59..c411448187 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -166,6 +166,7 @@ (reg-root-key-sub :prices-loading? :prices-loading?) (reg-root-key-sub :wallet.transactions :wallet.transactions) (reg-root-key-sub :wallet/custom-token-screen :wallet/custom-token-screen) +(reg-root-key-sub :wallet/prepare-transaction :wallet/prepare-transaction) ;;ethereum (reg-root-key-sub :ethereum/current-block :ethereum/current-block) @@ -284,6 +285,12 @@ (fn [network] (ethereum/network->chain-name network))) +(re-frame/reg-sub + :network-name + :<- [:current-network] + (fn [network] + (ethereum/network->network-name network))) + (re-frame/reg-sub :chain-id :<- [:current-network] @@ -488,6 +495,12 @@ (fn [[macc acc]] (some #(when (= (:address %) (:address acc)) %) (:accounts macc)))) +(re-frame/reg-sub + :account-by-address + :<- [:multiaccount] + (fn [macc [_ address]] + (some #(when (= (:address %) address) %) (:accounts macc)))) + (re-frame/reg-sub :multiple-multiaccounts? :<- [:multiaccounts/multiaccounts] @@ -539,7 +552,7 @@ :<- [:chats/current-chat-ui-prop :input-height] :<- [:chats/current-chat-ui-prop :input-focused?] :<- [:keyboard-height] - :<- [:chats/current-chat-ui-prop :show-stickers?] + :<- [:chats/current-chat-ui-prop :input-bottom-sheet] (fn [[home-content-layout-height input-height input-focused? kheight stickers?]] (- (+ home-content-layout-height tabs.styles/tabs-height) (if platform/iphone-x? @@ -2070,21 +2083,27 @@ (get-sufficient-gas-error balance nil nil gas gasPrice)))) (re-frame/reg-sub - :wallet.send/transaction - :<- [::send-transaction] + :wallet.send/prepare-transaction-with-balance + :<- [:wallet/prepare-transaction] :<- [:wallet] :<- [:offline?] :<- [:wallet/all-tokens] :<- [:ethereum/chain-keyword] - (fn [[{:keys [amount symbol from to amount-error] :as transaction} + (fn [[{:keys [symbol from to amount-text] :as transaction} wallet offline? all-tokens chain]] - (let [balance (get-in wallet [:accounts from :balance]) - token (tokens/asset-for all-tokens chain symbol)] - (assoc (merge transaction - (when amount - (get-sufficient-funds-error balance symbol amount))) + (let [balance (get-in wallet [:accounts (:address from) :balance]) + {:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol) + {:keys [value error]} (wallet.db/parse-amount amount-text decimals) + amount (money/formatted->internal value symbol decimals) + {:keys [amount-error] :as transaction-new} + (merge transaction + {:amount-error error} + (when amount + (get-sufficient-funds-error balance symbol amount)))] + (assoc transaction-new + :amount amount :balance balance - :token token + :token (assoc token :amount (get balance (:symbol token))) :sign-enabled? (and to (nil? amount-error) (not (nil? amount)) diff --git a/src/status_im/ui/components/bottom_panel/views.cljs b/src/status_im/ui/components/bottom_panel/views.cljs new file mode 100644 index 0000000000..e35f606402 --- /dev/null +++ b/src/status_im/ui/components/bottom_panel/views.cljs @@ -0,0 +1,67 @@ +(ns status-im.ui.components.bottom-panel.views + (:require-macros [status-im.utils.views :as views]) + (:require [status-im.ui.components.react :as react] + [status-im.ui.components.animation :as anim] + [reagent.core :as reagent])) + +(defn hide-panel-anim + [bottom-anim-value alpha-value window-height] + (anim/start + (anim/parallel + [(anim/spring bottom-anim-value {:toValue (- window-height) + :useNativeDriver true}) + (anim/timing alpha-value {:toValue 0 + :duration 500 + :useNativeDriver true})]))) + +(defn show-panel-anim + [bottom-anim-value alpha-value] + (anim/start + (anim/parallel + [(anim/spring bottom-anim-value {:toValue 40 + :useNativeDriver true}) + (anim/timing alpha-value {:toValue 0.4 + :duration 500 + :useNativeDriver true})]))) + +(defn bottom-panel [obj render window-height] + (let [bottom-anim-value (anim/create-value window-height) + alpha-value (anim/create-value 0) + clear-timeout (atom nil) + update? (atom nil) + current-obj (reagent/atom nil)] + (reagent/create-class + {:component-will-update (fn [_ [_ obj _ _]] + (when @clear-timeout (js/clearTimeout @clear-timeout)) + (when (or (not= obj @current-obj) @update?) + (cond + @update? + (do (reset! update? false) + (show-panel-anim bottom-anim-value alpha-value)) + + (and @current-obj obj) + (do (reset! update? true) + (js/setTimeout #(reset! current-obj obj) 600) + (hide-panel-anim bottom-anim-value alpha-value (- window-height))) + + obj + (do (reset! current-obj obj) + (show-panel-anim bottom-anim-value alpha-value)) + + :else + (do (reset! clear-timeout (js/setTimeout #(reset! current-obj nil) 600)) + (hide-panel-anim bottom-anim-value alpha-value (- window-height)))))) + :reagent-render (fn [] + (when @current-obj + [react/keyboard-avoiding-view {:style {:position :absolute :top 0 :bottom 0 :left 0 :right 0}} + [react/view {:flex 1} + [react/animated-view {:flex 1 :background-color :black :opacity alpha-value}] + [react/animated-view {:style {:position :absolute + :transform [{:translateY bottom-anim-value}] + :bottom 0 :left 0 :right 0}} + [react/view {:flex 1} + [render @current-obj]]]]]))}))) + +(views/defview animated-bottom-panel [val signing-view] + (views/letsubs [{window-height :height} [:dimensions/window]] + [bottom-panel (when val (select-keys val [:from :contact :amount :token :approve? :message])) signing-view window-height])) \ No newline at end of file diff --git a/src/status_im/ui/components/button.cljs b/src/status_im/ui/components/button.cljs index b94f8bb4a6..b7ade91562 100644 --- a/src/status_im/ui/components/button.cljs +++ b/src/status_im/ui/components/button.cljs @@ -16,7 +16,7 @@ (= :previous type) {:padding-right 20 :padding-left 12} :else nil) - {:padding-vertical 11 :border-radius 8 + {:height 44 :border-radius 8 :align-items :center :justify-content :center :background-color (cond (#{:secondary :next :previous} type) @@ -51,7 +51,7 @@ Spec: https://www.figma.com/file/cb4p8AxLtTF3q1L6JYDnKN15/Index?node-id=858%3A0" - [{:keys [label type theme disabled? on-press accessibility-label style] :or {type :main theme :blue}}] + [{:keys [label type theme disabled? on-press accessibility-label style container-style] :or {type :main theme :blue}}] (let [label (utils.label/stringify label)] [react/touchable-opacity (cond-> {:on-press on-press :active-opacity 0.5 @@ -61,7 +61,7 @@ (assoc :disabled (boolean disabled?)) accessibility-label (assoc :accessibility-label accessibility-label)) - [react/view {:style (style-container type disabled? theme)} + [react/view {:style (merge (style-container type disabled? theme) container-style)} [react/view {:flex-direction :row :align-items :center} (when (= type :previous) [vector-icons/icon :main-icons/back {:container-style {:width 24 :height 24 :margin-right 4} diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs index affa975ec3..ed8439ddef 100644 --- a/src/status_im/ui/components/colors.cljs +++ b/src/status_im/ui/components/colors.cljs @@ -49,11 +49,14 @@ (def green "#44d058") ;; icon for successful inboud transaction (def green-transparent-10 (alpha green 0.1)) ;; icon for successful inboud transaction +(def purple "#887af9") +(def orange "#FE8F59") + (def chat-colors ["#fa6565" "#7cda00" - "#887af9" + purple "#51d0f0" - "#fe8f59" + orange "#d37ef4"]) (def account-colors ["#9B832F" @@ -61,7 +64,7 @@ "#1D806F" "#FA6565" "#7CDA00" - "#887AF9" + purple "#8B3131"]) (def text black) diff --git a/src/status_im/ui/components/list_item/styles.cljs b/src/status_im/ui/components/list_item/styles.cljs index 754b7670ee..512a368f88 100644 --- a/src/status_im/ui/components/list_item/styles.cljs +++ b/src/status_im/ui/components/list_item/styles.cljs @@ -196,5 +196,4 @@ (def error {:bottom-value 0 - :color colors/red-light :font-size 12}) diff --git a/src/status_im/ui/components/status_bar/styles.cljs b/src/status_im/ui/components/status_bar/styles.cljs index 15e334b365..7c72f71ff4 100644 --- a/src/status_im/ui/components/status_bar/styles.cljs +++ b/src/status_im/ui/components/status_bar/styles.cljs @@ -14,6 +14,6 @@ :android (create-status-bar-style {:translucent? true :bar-style "dark-content"})}) -(styles/def status-bar-transparent +(styles/def status-bar-black {:ios (create-status-bar-style {:background-color colors/transparent}) - :android (create-status-bar-style {:translucent? true})}) \ No newline at end of file + :android (create-status-bar-style {:background-color colors/black})}) \ No newline at end of file diff --git a/src/status_im/ui/components/status_bar/view.cljs b/src/status_im/ui/components/status_bar/view.cljs index 46b95ca4cd..12abe8855f 100644 --- a/src/status_im/ui/components/status_bar/view.cljs +++ b/src/status_im/ui/components/status_bar/view.cljs @@ -4,7 +4,7 @@ [status-im.utils.platform :as platform])) (defn get-config [view-id] - (or (get {:recipient-qr-code {:type :transparent}} + (or (get {:qr-scanner {:type :black}} view-id) {:type :main})) @@ -26,12 +26,12 @@ network-activity-indicator-visible translucent]} (case type - :transparent styles/status-bar-transparent + :black styles/status-bar-black styles/status-bar-default)] + (when bar-style + (.setBarStyle react/status-bar-class (clj->js bar-style)) true) (when (and background-color platform/android?) (.setBackgroundColor react/status-bar-class (clj->js background-color))) - (when bar-style - (.setBarStyle react/status-bar-class (clj->js bar-style))) (when hidden (.setHidden react/status-bar-class (clj->js hidden))) (when network-activity-indicator-visible diff --git a/src/status_im/ui/components/tabbar/core.cljs b/src/status_im/ui/components/tabbar/core.cljs index ba876f0c42..9aae967916 100644 --- a/src/status_im/ui/components/tabbar/core.cljs +++ b/src/status_im/ui/components/tabbar/core.cljs @@ -31,7 +31,7 @@ (def tabs-list-data (->> [{:nav-stack :chat-stack - :content {:title (i18n/label :t/chats) + :content {:title (i18n/label :t/chat) :icon :main-icons/message} :count-subscription :chats/unread-messages-number :accessibility-label :home-tab-button} diff --git a/src/status_im/ui/components/toolbar/view.cljs b/src/status_im/ui/components/toolbar/view.cljs index e97bc472b7..c99875de9a 100644 --- a/src/status_im/ui/components/toolbar/view.cljs +++ b/src/status_im/ui/components/toolbar/view.cljs @@ -33,10 +33,10 @@ (defn nav-text ([text] (nav-text nil text)) ([{:keys [handler] :as props} text] - [react/text (utils/deep-merge {:style styles/item-text - :on-press (or handler #(re-frame/dispatch [:navigate-back]))} - props) - text])) + [react/touchable-highlight {:on-press (or handler #(re-frame/dispatch [:navigate-back]))} + [react/text (utils/deep-merge {:style styles/item-text} + props) + text]])) (defn nav-clear-text ([text] (nav-clear-text nil text)) diff --git a/src/status_im/ui/components/tooltip/styles.cljs b/src/status_im/ui/components/tooltip/styles.cljs index 472eefc922..0b51c6814a 100644 --- a/src/status_im/ui/components/tooltip/styles.cljs +++ b/src/status_im/ui/components/tooltip/styles.cljs @@ -3,11 +3,12 @@ [status-im.utils.styles :as styles])) (def tooltip-container - {:position :absolute - :align-items :center - :left 0 - :right 0 - :top 0}) + {:position :absolute + :align-items :center + :pointer-events :none + :left 0 + :right 0 + :top 0}) (styles/def bottom-tooltip-container {:position :absolute @@ -28,10 +29,14 @@ (defn tooltip-text-container [color] {:padding-horizontal 16 - :padding-vertical 9 + :padding-vertical 6 + :elevation 3 :background-color color - :elevation 2 - :border-radius 8}) + :border-radius 8 + :shadow-radius 12 + :shadow-offset {:width 0 :height 4} + :shadow-opacity 0.16 + :shadow-color "rgba(0, 34, 51)"}) (def bottom-tooltip-text-container {:flex-direction :row @@ -43,8 +48,9 @@ :border-radius 8}) (defn tooltip-text [font-size] - {:color colors/red - :font-size font-size}) + {:color colors/red + :line-height 15 + :font-size font-size}) (def bottom-tooltip-text {:color colors/white}) diff --git a/src/status_im/ui/components/tooltip/views.cljs b/src/status_im/ui/components/tooltip/views.cljs index 6e4c28835e..e660d205c2 100644 --- a/src/status_im/ui/components/tooltip/views.cljs +++ b/src/status_im/ui/components/tooltip/views.cljs @@ -18,9 +18,9 @@ (when label [react/view (styles/tooltip-text-container color) [react/text {:style (styles/tooltip-text font-size)} label]]) - [vector-icons/icon :icons/tooltip-triangle (assoc - styles/tooltip-triangle - :color color)]]])) + #_[vector-icons/icon :icons/tooltip-triangle (assoc + styles/tooltip-triangle + :color color)]]])) (views/defview bottom-tooltip-info [label on-close] (views/letsubs [bottom-anim-value (animation/create-value 150) diff --git a/src/status_im/ui/screens/add_new/events.cljs b/src/status_im/ui/screens/add_new/events.cljs index 1f7b50e4c7..ff0372abdf 100644 --- a/src/status_im/ui/screens/add_new/events.cljs +++ b/src/status_im/ui/screens/add_new/events.cljs @@ -5,6 +5,5 @@ (handlers/register-handler-fx :handle-qr-code - (fn [cofx [_ _ data]] - (log/debug "qr code scanned with data " data) + (fn [cofx [_ data _]] (models/handle-qr-code cofx data))) diff --git a/src/status_im/ui/screens/add_new/new_chat/views.cljs b/src/status_im/ui/screens/add_new/new_chat/views.cljs index 52c8626034..63c0be5eb7 100644 --- a/src/status_im/ui/screens/add_new/new_chat/views.cljs +++ b/src/status_im/ui/screens/add_new/new_chat/views.cljs @@ -10,7 +10,6 @@ [status-im.ui.screens.add-new.styles :as add-new.styles] [status-im.ui.screens.add-new.new-chat.styles :as styles] [status-im.utils.platform :as platform] - [reagent.core :as reagent] [status-im.ui.components.list-item.views :as list-item] [status-im.ui.components.chat-icon.screen :as chat-icon] [status-im.multiaccounts.core :as multiaccounts])) @@ -21,9 +20,6 @@ :accessories [:chevron] :on-press #(re-frame/dispatch [:chat.ui/start-chat (:public-key row) {:navigation-reset? true}])}]) -;;TODO workaround for https://github.com/facebook/react-native/issues/23653 (https://github.com/status-im/status-react/issues/8548) -(def tw (reagent/atom "95%")) - (views/defview new-chat [] (views/letsubs [contacts [:contacts/active] new-identity [:contacts/new-identity] @@ -32,12 +28,11 @@ [toolbar.view/simple-toolbar (i18n/label :t/new-chat) true] [react/view add-new.styles/new-chat-container [react/view add-new.styles/new-chat-input-container - [react/text-input {:ref (fn [v] (js/setTimeout #(reset! tw (if v "100%" "95%")) 100)) - :on-change-text #(re-frame/dispatch [:new-chat/set-new-identity %]) + [react/text-input {:on-change-text #(re-frame/dispatch [:new-chat/set-new-identity %]) :on-submit-editing #(when (and new-identity (not error-message)) (re-frame/dispatch [:contact.ui/contact-code-submitted])) :placeholder (i18n/label :t/enter-contact-code) - :style (add-new.styles/input @tw) + :style add-new.styles/input ;; This input is fine to preserve inputs ;; so its contents will not be erased ;; in onWillBlur navigation event handler @@ -46,8 +41,8 @@ :return-key-type :go}]] (when-not platform/desktop? [react/touchable-highlight {:on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed - {:toolbar-title (i18n/label :t/new-contact)} - :contact/qr-code-scanned]) + {:title (i18n/label :t/new-contact) + :handler :contact/qr-code-scanned}]) :style add-new.styles/button-container :accessibility-label :scan-contact-code-button} [react/view diff --git a/src/status_im/ui/screens/add_new/styles.cljs b/src/status_im/ui/screens/add_new/styles.cljs index 7e9dc07502..81d5992d7a 100644 --- a/src/status_im/ui/screens/add_new/styles.cljs +++ b/src/status_im/ui/screens/add_new/styles.cljs @@ -26,9 +26,8 @@ :padding-horizontal 16 :height 52}) -(styles/defn input [w] +(styles/def input {:padding-horizontal 14 - :width w :desktop {:height 30 :width "100%"} :android {:padding 0}}) diff --git a/src/status_im/ui/screens/add_new/views.cljs b/src/status_im/ui/screens/add_new/views.cljs index e3a8f5fed7..eaeba49f4d 100644 --- a/src/status_im/ui/screens/add_new/views.cljs +++ b/src/status_im/ui/screens/add_new/views.cljs @@ -45,8 +45,8 @@ :accessibility-label :scan-qr-code-button :icon :main-icons/qr :on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed - {:toolbar-title (i18n/label :t/scan-qr)} - :handle-qr-code])}])]) + {:title (i18n/label :t/scan-qr) + :handler :handle-qr-code}])}])]) (defn add-new [] [react/view {:flex 1 :background-color :white} diff --git a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs index f2d9ae2de6..8bbb584d77 100644 --- a/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs +++ b/src/status_im/ui/screens/bootnodes_settings/edit_bootnode/views.cljs @@ -26,8 +26,8 @@ (def qr-code [react/touchable-highlight {:on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed - {:toolbar-title (i18n/label :t/add-bootnode)} - :bootnodes.callback/qr-code-scanned]) + {:title (i18n/label :t/add-bootnode) + :handler :bootnodes.callback/qr-code-scanned}]) :style styles/qr-code} [react/view [vector-icons/icon :main-icons/qr {:color colors/blue}]]]) diff --git a/src/status_im/ui/screens/chat/extensions/views.cljs b/src/status_im/ui/screens/chat/extensions/views.cljs new file mode 100644 index 0000000000..2c0a52c104 --- /dev/null +++ b/src/status_im/ui/screens/chat/extensions/views.cljs @@ -0,0 +1,59 @@ +(ns status-im.ui.screens.chat.extensions.views + (:require-macros [status-im.utils.views :as views]) + (:require [status-im.ui.components.react :as react] + [re-frame.core :as re-frame] + [status-im.utils.platform :as platform] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.icons.vector-icons :as icons] + [status-im.ui.components.animation :as anim] + [status-im.i18n :as i18n])) + +(def panel-height 264) + +(defn button [showing?] + [react/touchable-highlight + {:on-press (fn [_] + (re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-bottom-sheet (when-not showing? :extensions)}]) + (when-not platform/desktop? (js/setTimeout #(react/dismiss-keyboard!) 100))) + :accessibility-label :show-extensions-icon} + [icons/icon :main-icons/commands {:container-style {:margin 14 :margin-right 10} + :color (if showing? colors/blue colors/gray)}]]) + +(defn show-panel-anim + [bottom-anim-value alpha-value] + (anim/start + (anim/parallel + [(anim/spring bottom-anim-value {:toValue 0 + :useNativeDriver true}) + (anim/timing alpha-value {:toValue 1 + :duration 500 + :useNativeDriver true})]))) + +(views/defview extensions-view [] + (views/letsubs [bottom-anim-value (anim/create-value panel-height) + alpha-value (anim/create-value 0)] + {:component-did-mount #(show-panel-anim bottom-anim-value alpha-value)} + [react/animated-view {:style {:background-color :white + :height panel-height + :transform [{:translateY bottom-anim-value}] + :opacity alpha-value}} + [react/view + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:wallet/prepare-transaction-from-chat])} + [react/view {:width 128 :height 128 :justify-content :space-between + :padding-horizontal 10 :padding-vertical 12 + :background-color (colors/alpha colors/purple 0.2) :border-radius 16 :margin-left 8} + [react/view {:background-color colors/purple :width 40 :height 40 :border-radius 20 :align-items :center + :justify-content :center} + [icons/icon :main-icons/send {:color colors/white}]] + [react/text {:typography :medium} (i18n/label :t/send-transaction)]]] + ;;TODO not implemented yet + #_[react/touchable-highlight + {:on-press #(re-frame/dispatch [:wallet/prepare-transaction-from-chat])} + [react/view {:width 128 :height 128 :justify-content :space-between + :padding-horizontal 10 :padding-vertical 12 :margin-top 8 + :background-color (colors/alpha colors/orange 0.2) :border-radius 16 :margin-left 8} + [react/view {:background-color colors/orange :width 40 :height 40 :border-radius 20 :align-items :center + :justify-content :center} + [icons/icon :main-icons/receive {:color colors/white}]] + [react/text {:typography :medium} (i18n/label :t/request-transaction)]]]]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/input/input.cljs b/src/status_im/ui/screens/chat/input/input.cljs index 32c6e5ffde..fe196f744b 100644 --- a/src/status_im/ui/screens/chat/input/input.cljs +++ b/src/status_im/ui/screens/chat/input/input.cljs @@ -21,7 +21,8 @@ [status-im.utils.utils :as utils] [status-im.utils.config :as config] [taoensso.timbre :as log] - [status-im.ui.screens.chat.stickers.views :as stickers])) + [status-im.ui.screens.chat.stickers.views :as stickers] + [status-im.ui.screens.chat.extensions.views :as extensions])) (defview basic-text-input [{:keys [set-container-width-fn height single-line-input?]}] (letsubs [input-text [:chats/current-chat-input-text] @@ -35,7 +36,7 @@ :editable (not cooldown-enabled?) :blur-on-submit false :on-focus #(re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-focused? true - :show-stickers? false + :input-bottom-sheet nil :messages-focused? false}]) :on-blur #(re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-focused? false}]) :on-submit-editing #(when single-line-input? @@ -66,7 +67,7 @@ :editable (not cooldown-enabled?) :blur-on-submit false :on-focus #(re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-focused? true - :show-stickers? false + :input-bottom-sheet nil :messages-focused? false}]) :on-blur #(re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-focused? false}]) :submit-shortcut {:key "Enter"} @@ -187,14 +188,13 @@ mainnet? [:mainnet?] input-text [:chats/current-chat-input-text] result-box [:chats/current-chat-ui-prop :result-box] - show-stickers? [:chats/current-chat-ui-prop :show-stickers?] - state-text (reagent/atom "")] + input-bottom-sheet [:chats/current-chat-ui-prop :input-bottom-sheet] + state-text (reagent/atom "")] {:component-will-unmount #(when platform/desktop? (re-frame/dispatch [:chat.ui/set-chat-input-text @state-text])) :component-did-mount #(when-not (string/blank? input-text) (reset! state-text input-text))} (let [single-line-input? (:singleLineInput result-box) - component (reagent/current-component) set-text #(reset! state-text %) input-text-empty? (if platform/desktop? (string/blank? state-text) @@ -209,9 +209,10 @@ [react/view {:style style/input-container} [input-view {:single-line-input? single-line-input? :set-text set-text :state-text state-text}] (when (and input-text-empty? mainnet?) - [stickers/button show-stickers?]) - (if input-text-empty? - [commands-button] + [stickers/button (= :stickers input-bottom-sheet)]) + (when (and input-text-empty?) ;;TODO show only for 1-1 chats? + [extensions/button (= :extensions input-bottom-sheet)]) + (when-not input-text-empty? (if platform/desktop? [send-button/send-button-view {:input-text @state-text} #(do diff --git a/src/status_im/ui/screens/chat/message/datemark.cljs b/src/status_im/ui/screens/chat/message/datemark.cljs index a400e1cb1c..b692eb3673 100644 --- a/src/status_im/ui/screens/chat/message/datemark.cljs +++ b/src/status_im/ui/screens/chat/message/datemark.cljs @@ -15,7 +15,7 @@ {:on-press (fn [_] (re-frame/dispatch [:chat.ui/set-chat-ui-props {:messages-focused? true - :show-stickers? false}]) + :input-bottom-sheet nil}]) (react/dismiss-keyboard!))} [react/view style/datemark-mobile [react/text {:style style/datemark-text} diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index 6d1131aee4..483c69bf94 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -296,7 +296,7 @@ (when (and (= content-type constants/content-type-sticker) (:pack content)) (re-frame/dispatch [:stickers/open-sticker-pack (:pack content)])) (re-frame/dispatch [:chat.ui/set-chat-ui-props {:messages-focused? true - :show-stickers? false}]) + :input-bottom-sheet nil}]) (when-not platform/desktop? (react/dismiss-keyboard!))))) :on-long-press #(when (or (= content-type constants/content-type-text) diff --git a/src/status_im/ui/screens/chat/stickers/views.cljs b/src/status_im/ui/screens/chat/stickers/views.cljs index ff10cdc153..306c230257 100644 --- a/src/status_im/ui/screens/chat/stickers/views.cljs +++ b/src/status_im/ui/screens/chat/stickers/views.cljs @@ -19,14 +19,14 @@ (def icon-container (+ (* icon-horizontal-margin 2) icon-size)) (def scroll-x (reagent/atom 0)) -(defn button [show-stickers?] +(defn button [stickers-showing?] [react/touchable-highlight {:on-press (fn [_] - (re-frame/dispatch [:chat.ui/set-chat-ui-props {:show-stickers? (not show-stickers?)}]) + (re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-bottom-sheet (when-not stickers-showing? :stickers)}]) (when-not platform/desktop? (js/setTimeout #(react/dismiss-keyboard!) 100))) :accessibility-label :show-stickers-icon} [vector-icons/icon :main-icons/stickers {:container-style {:margin 14 :margin-right 6} - :color (if show-stickers? colors/blue colors/gray)}]]) + :color (if stickers-showing? colors/blue colors/gray)}]]) (defn- no-stickers-yet-panel [] [react/view {:style {:flex 1 :align-items :center :justify-content :center}} diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs index 3745aebc5f..49f433ca79 100644 --- a/src/status_im/ui/screens/chat/views.cljs +++ b/src/status_im/ui/screens/chat/views.cljs @@ -26,7 +26,8 @@ [status-im.ui.screens.profile.tribute-to-talk.views :as tribute-to-talk.views] - [status-im.utils.platform :as platform]) + [status-im.utils.platform :as platform] + [status-im.ui.screens.chat.extensions.views :as extensions]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) (defn add-contact-bar @@ -287,7 +288,7 @@ :on-press (fn [_] (re-frame/dispatch [:chat.ui/set-chat-ui-props {:messages-focused? true - :show-stickers? false}]) + :input-bottom-sheet nil}]) (react/dismiss-keyboard!))} [react/view (style/intro-header-container height intro-status no-messages) ;; Icon section @@ -396,7 +397,7 @@ (letsubs [{:keys [public? chat-id chat-name show-input? group-chat contact] :as current-chat} [:chats/current-chat] current-chat-id [:chats/current-chat-id] - show-stickers? [:chats/current-chat-ui-prop :show-stickers?] + input-bottom-sheet [:chats/current-chat-ui-prop :input-bottom-sheet] two-pane-ui-enabled? [:two-pane-ui-enabled?] anim-translate-y (animation/create-value (if two-pane-ui-enabled? 0 connectivity/neg-connectivity-bar-height))] @@ -432,8 +433,12 @@ [messages-view current-chat modal?])]] (when show-input? [input/container]) - (when show-stickers? - [stickers/stickers-view])])) + (case input-bottom-sheet + :stickers + [stickers/stickers-view] + :extensions + [extensions/extensions-view] + nil)])) (defview chat [] [chat-root false]) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index a0606a49e2..53eae068d0 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -6,7 +6,6 @@ status-im.transport.db status-im.multiaccounts.db status-im.contact.db - status-im.ui.screens.qr-scanner.db status-im.ui.screens.group.db status-im.chat.specs status-im.ui.screens.profile.db @@ -183,6 +182,8 @@ (spec/def :popover/popover (spec/nilable map?)) +(spec/def :wallet/prepare-transaction (spec/nilable map?)) + (spec/def ::db (spec/keys :opt [:contacts/contacts :contacts/new-identity :contacts/new-identity-error @@ -248,6 +249,7 @@ :bottom-sheet/view :bottom-sheet/options :wallet/custom-token-screen + :wallet/prepare-transaction :signing/in-progress? :signing/queue :signing/sign @@ -282,9 +284,6 @@ :navigation/navigation-stack :navigation/prev-tab-view-id :navigation/prev-view-id - :qr/qr-codes - :qr/qr-modal - :qr/current-qr-context :chat/chats :chat/current-chat-id :chat/chat-id diff --git a/src/status_im/ui/screens/group/views.cljs b/src/status_im/ui/screens/group/views.cljs index ee1f561e60..685be25596 100644 --- a/src/status_im/ui/screens/group/views.cljs +++ b/src/status_im/ui/screens/group/views.cljs @@ -27,7 +27,7 @@ :on-change-text #(re-frame/dispatch [:set :new-chat-name %]) :default-value new-group-name :placeholder (i18n/label :t/set-a-topic) - :style (add-new.styles/input "100%") + :style add-new.styles/input :accessibility-label :chat-name-input}]]) (defn- render-contact [contact] diff --git a/src/status_im/ui/screens/home/sheet/views.cljs b/src/status_im/ui/screens/home/sheet/views.cljs index f8797e1fed..4ed0a36f36 100644 --- a/src/status_im/ui/screens/home/sheet/views.cljs +++ b/src/status_im/ui/screens/home/sheet/views.cljs @@ -40,8 +40,8 @@ :accessibility-label :scan-qr-code-button :icon :main-icons/qr :on-press #(hide-sheet-and-dispatch [:qr-scanner.ui/scan-qr-code-pressed - {:toolbar-title (i18n/label :t/scan-qr)} - :handle-qr-code])}] + {:title (i18n/label :t/scan-qr) + :handler :handle-qr-code}])}] [list-item/list-item {:theme :action :title :t/invite-friends diff --git a/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs b/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs index 8d739435ba..365b84cec3 100644 --- a/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs +++ b/src/status_im/ui/screens/offline_messaging_settings/edit_mailserver/views.cljs @@ -34,8 +34,8 @@ (def qr-code [react/touchable-highlight {:on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed - {:toolbar-title (i18n/label :t/add-mailserver)} - :mailserver.callback/qr-code-scanned]) + {:title (i18n/label :t/add-mailserver) + :handler :mailserver.callback/qr-code-scanned}]) :style styles/qr-code} [react/view [vector-icons/icon :main-icons/qr {:color colors/blue}]]]) diff --git a/src/status_im/ui/screens/qr_scanner/db.cljs b/src/status_im/ui/screens/qr_scanner/db.cljs deleted file mode 100644 index 868e3935ae..0000000000 --- a/src/status_im/ui/screens/qr_scanner/db.cljs +++ /dev/null @@ -1,8 +0,0 @@ -(ns status-im.ui.screens.qr-scanner.db - (:require [cljs.spec.alpha :as s])) - -;;on scan qr -(s/def :qr/qr-codes (s/nilable map?)) -;;used in qr modal screen -(s/def :qr/qr-modal (s/nilable map?)) -(s/def :qr/current-qr-context (s/nilable map?)) \ No newline at end of file diff --git a/src/status_im/ui/screens/qr_scanner/styles.cljs b/src/status_im/ui/screens/qr_scanner/styles.cljs index fc7736790d..51efafddfa 100644 --- a/src/status_im/ui/screens/qr_scanner/styles.cljs +++ b/src/status_im/ui/screens/qr_scanner/styles.cljs @@ -1,77 +1,11 @@ -(ns status-im.ui.screens.qr-scanner.styles - (:require-macros [status-im.utils.styles :as styles]) - (:require [status-im.ui.components.colors :as colors] - [status-im.ui.components.toolbar.styles :as toolbar.styles])) +(ns status-im.ui.screens.qr-scanner.styles) -(def barcode-scanner-container - {:flex 1 - :background-color :white}) - -(styles/def barcode-scanner - {:flex 1 - :elevation -10 - :android {:marginTop 10}}) - -(def rectangle-container - {:position :absolute - :left 0 - :top toolbar.styles/toolbar-height - :bottom 0 - :right 0 - :flex 1 - :align-items :center - :justify-content :center - :background-color :transparent}) - -(def rectangle - {:height 250 - :width 250 - :background-color :transparent}) - -(def corner-left-top - {:position :absolute - :left 0 - :top 0 - :width 56 - :height 56}) - -(def corner-right-top - {:position :absolute - :right 0 - :top 0 - :width 56 - :height 56}) - -(def corner-right-bottom - {:position :absolute - :right 0 - :bottom 0 - :width 56 - :height 56}) - -(def corner-left-bottom - {:position :absolute - :left 0 - :bottom 0 - :width 56 - :height 56}) - -(def import-button - {:position :absolute - :right 16 - :flex 1 - :height 50 - :align-items :center}) - -(def import-button-content - {:flex 1 - :flex-direction :row - :height 50 - :align-items :center - :align-self :center}) - -(def import-text - {:flex 1 - :flex-direction :column - :color colors/white - :margin-left 8}) +(def viewfinder-port + {:position :absolute + :left 0 + :top 0 + :bottom 0 + :right 0 + :align-items :center + :justify-content :center + :flex 1}) \ No newline at end of file diff --git a/src/status_im/ui/screens/qr_scanner/views.cljs b/src/status_im/ui/screens/qr_scanner/views.cljs index d07c455c58..3cdcc8c9c4 100644 --- a/src/status_im/ui/screens/qr_scanner/views.cljs +++ b/src/status_im/ui/screens/qr_scanner/views.cljs @@ -1,51 +1,58 @@ (ns status-im.ui.screens.qr-scanner.views (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [reagent.core :as reagent] - [re-frame.core :as re-frame] + (:require [re-frame.core :as re-frame] [status-im.i18n :as i18n] - [status-im.ui.components.react :as react] [status-im.ui.components.camera :as camera] - [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.components.react :as react] + [status-im.ui.components.toolbar.view :as topbar] [status-im.ui.screens.qr-scanner.styles :as styles] - [status-im.ui.components.toolbar.actions :as actions])) + [status-im.ui.components.colors :as colors])) -(defview qr-scanner-toolbar [title identifier] - [react/view - [toolbar/toolbar {:style {:background-color :white}} - [toolbar/nav-button (actions/back - #(do - (re-frame/dispatch [:qr-scanner.callback/scan-qr-code-cancel identifier]) - (re-frame/dispatch [:navigate-back])))] - [toolbar/content-title title]]]) +(defn- topbar [camera-flashlight {:keys [title] :as opts}] + [topbar/toolbar + {:transparent? true} + [topbar/nav-text + {:style {:color colors/white :margin-left 16} + :handler #(re-frame/dispatch [:qr-scanner.callback/scan-qr-code-cancel opts])} + (i18n/label :t/cancel)] + [topbar/content-title {:color :white} + (or title (i18n/label :t/scan-qr))] + #_[topbar/actions [{:icon (if (= :on camera-flashlight) + :main-icons/flash-active + :main-icons/flash-inactive) + :icon-opts {:color :white} + :handler #(re-frame/dispatch [:wallet/toggle-flashlight])}]]]) -(defn on-barcode-read [identifier data] - (re-frame/dispatch [:qr-scanner.callback/scan-qr-code-success identifier (camera/get-qr-code-data data)])) +(defn corner [border1 border2 corner] + [react/view (assoc {:border-color :white :width 60 :height 60} border1 5 border2 5 corner 32)]) -;; identifier is passed via navigation params instead of subs in order to ensure -;; that two separate instances of `qr-scanner` screen can work simultaneously -(defview qr-scanner [{identifier :current-qr-context} screen-focused?] - (letsubs [camera-initialized? (reagent/atom false) - barcode-read? (reagent/atom false)] - [react/view styles/barcode-scanner-container - [qr-scanner-toolbar (or (:toolbar-title identifier) (i18n/label :t/scan-qr)) identifier] - ;; camera component should be hidden if screen is not shown - ;; otherwise another screen with camera from a different stack - ;; will not work properly - (when @screen-focused? - [camera/camera {:onBarCodeRead #(if (:multiple? identifier) - (on-barcode-read identifier %) - (when-not @barcode-read? - (do (reset! barcode-read? true) - (on-barcode-read identifier %)))) - :ref #(reset! camera-initialized? true) - :style styles/barcode-scanner}]) - [react/view styles/rectangle-container - [react/view styles/rectangle - [react/image {:source {:uri :corner_left_top} - :style styles/corner-left-top}] - [react/image {:source {:uri :corner_right_top} - :style styles/corner-right-top}] - [react/image {:source {:uri :corner_right_bottom} - :style styles/corner-right-bottom}] - [react/image {:source {:uri :corner_left_bottom} - :style styles/corner-left-bottom}]]]])) +(defn- viewfinder [size] + [react/view {:style styles/viewfinder-port} + [react/view {:width size :height size :justify-content :space-between} + [react/view {:flex-direction :row :justify-content :space-between} + [corner :border-top-width :border-left-width :border-top-left-radius] + [corner :border-top-width :border-right-width :border-top-right-radius]] + [react/view {:flex-direction :row :justify-content :space-between} + [corner :border-bottom-width :border-left-width :border-bottom-left-radius] + [corner :border-bottom-width :border-right-width :border-bottom-right-radius]]]]) + +(defn on-barcode-read [opts data] + (re-frame/dispatch [:qr-scanner.callback/scan-qr-code-success opts (camera/get-qr-code-data data)])) + +(defview qr-scanner [] + (letsubs [read-once? (atom false) + {:keys [height width]} [:dimensions/window] + camera-flashlight [:wallet.send/camera-flashlight] + opts [:get-screen-params]] + [react/view {:style {:flex 1 :background-color colors/black}} + [topbar camera-flashlight opts] + [react/with-activity-indicator + {} + [camera/camera + {:style {:flex 1} + ;:torchMode (camera/set-torch camera-flashlight) + :captureAudio false + :onBarCodeRead #(when-not @read-once? + (reset! read-once? true) + (on-barcode-read opts %))}]] + [viewfinder (int (* 2 (/ (min height width) 3)))]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/routing/browser_stack.cljs b/src/status_im/ui/screens/routing/browser_stack.cljs index 445c1ebcf3..f4f2a60cbc 100644 --- a/src/status_im/ui/screens/routing/browser_stack.cljs +++ b/src/status_im/ui/screens/routing/browser_stack.cljs @@ -3,6 +3,5 @@ (def browser-stack {:name :browser-stack :screens [:open-dapp - :browser - :qr-scanner] + :browser] :config {:initialRouteName :open-dapp}}) diff --git a/src/status_im/ui/screens/routing/chat_stack.cljs b/src/status_im/ui/screens/routing/chat_stack.cljs index 619b03bb44..fbedbdd4e1 100644 --- a/src/status_im/ui/screens/routing/chat_stack.cljs +++ b/src/status_im/ui/screens/routing/chat_stack.cljs @@ -7,7 +7,6 @@ :select-chat :profile :new - :qr-scanner :take-picture :new-group :add-participants-toggle-list diff --git a/src/status_im/ui/screens/routing/modals.cljs b/src/status_im/ui/screens/routing/modals.cljs index 4aeb95cb68..3f2ce74cd8 100644 --- a/src/status_im/ui/screens/routing/modals.cljs +++ b/src/status_im/ui/screens/routing/modals.cljs @@ -11,4 +11,6 @@ :welcome :keycard-welcome :new-chat - :new-public-chat]) + :new-public-chat + :contact-code + :qr-scanner]) diff --git a/src/status_im/ui/screens/routing/profile_stack.cljs b/src/status_im/ui/screens/routing/profile_stack.cljs index 047b231a3e..8ee24b3e1e 100644 --- a/src/status_im/ui/screens/routing/profile_stack.cljs +++ b/src/status_im/ui/screens/routing/profile_stack.cljs @@ -35,7 +35,6 @@ :mobile-network-settings :backup-seed :tribute-to-talk - :qr-scanner :my-profile-ext-settings] config/hardwallet-enabled? diff --git a/src/status_im/ui/screens/routing/screens.cljs b/src/status_im/ui/screens/routing/screens.cljs index 23f0bcdb86..2269d10dd2 100644 --- a/src/status_im/ui/screens/routing/screens.cljs +++ b/src/status_im/ui/screens/routing/screens.cljs @@ -1,7 +1,6 @@ (ns status-im.ui.screens.routing.screens (:require [status-im.ui.screens.about-app.views :as about-app] [status-im.ui.screens.multiaccounts.login.views :as login] - [status-im.ui.screens.multiaccounts.recover.views :as multiaccounts.recover] [status-im.ui.screens.multiaccounts.views :as multiaccounts] [status-im.ui.screens.add-new.new-chat.views :as new-chat] [status-im.ui.screens.add-new.new-public-chat.view :as new-public-chat] @@ -59,8 +58,6 @@ [status-im.ui.screens.stickers.views :as stickers] [status-im.ui.screens.wallet.collectibles.views :as collectibles] [status-im.ui.screens.wallet.components.views :as wallet.components] - [status-im.ui.screens.wallet.request.views :as request] - [status-im.ui.screens.wallet.send.views :as send] [status-im.ui.screens.wallet.settings.views :as wallet-settings] [status-im.ui.screens.wallet.transactions.views :as wallet-transactions] [status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens] @@ -124,7 +121,7 @@ :profile profile.contact/profile :new add-new/add-new :new-chat [:modal new-chat/new-chat] - :qr-scanner qr-scanner/qr-scanner + :qr-scanner [:modal qr-scanner/qr-scanner] :new-group group/new-group :add-participants-toggle-list group/add-participants-toggle-list :contact-toggle-list group/contact-toggle-list @@ -140,14 +137,7 @@ :wallet wallet.accounts/accounts-overview :wallet-account wallet.account/account :collectibles-list collectibles/collectibles-list - :contact-code wallet.components/contact-code - :wallet-send-transaction send/send-transaction - :recent-recipients wallet.components/recent-recipients - :select-account wallet.components/accounts - :recipient-qr-code wallet.components/recipient-qr-code - :wallet-send-assets wallet.components/send-assets - :wallet-send-transaction-request request/send-transaction-request - :wallet-request-assets wallet.components/request-assets + :contact-code [:modal wallet.components/contact-code] :wallet-transaction-details wallet-transactions/transaction-details :wallet-settings-hook wallet-settings/settings-hook :wallet-settings-assets wallet-settings/manage-assets diff --git a/src/status_im/ui/screens/routing/wallet_stack.cljs b/src/status_im/ui/screens/routing/wallet_stack.cljs index 97c626373e..e7ec008b5a 100644 --- a/src/status_im/ui/screens/routing/wallet_stack.cljs +++ b/src/status_im/ui/screens/routing/wallet_stack.cljs @@ -10,19 +10,6 @@ :account-settings :collectibles-list :wallet-onboarding-setup - :contact-code - {:name :send-transaction-stack - :screens [:wallet-send-transaction - :recent-recipients - :select-account - :enter-pin-sign - :hardwallet-connect-sign - :recipient-qr-code - :wallet-send-assets]} - {:name :request-transaction-stack - :screens [:wallet-send-transaction-request - :wallet-request-assets - :recent-recipients]} :wallet-transaction-details :wallet-settings-hook :wallet-settings-assets diff --git a/src/status_im/ui/screens/signing/styles.cljs b/src/status_im/ui/screens/signing/styles.cljs index 08e52e6b18..31e7d724b8 100644 --- a/src/status_im/ui/screens/signing/styles.cljs +++ b/src/status_im/ui/screens/signing/styles.cljs @@ -7,7 +7,6 @@ :justify-content :space-between :padding-top 16 :padding-left 16 - :padding-right 24 :margin-bottom 11}) (def message-header diff --git a/src/status_im/ui/screens/signing/views.cljs b/src/status_im/ui/screens/signing/views.cljs index 7d8c76074e..3027c00a67 100644 --- a/src/status_im/ui/screens/signing/views.cljs +++ b/src/status_im/ui/screens/signing/views.cljs @@ -4,8 +4,6 @@ [re-frame.core :as re-frame] [status-im.multiaccounts.core :as multiaccounts] [status-im.ui.components.colors :as colors] - [status-im.ui.components.animation :as anim] - [reagent.core :as reagent] [status-im.ui.components.list-item.views :as list-item] [status-im.ui.components.button :as button] [status-im.ui.components.copyable-text :as copyable-text] @@ -22,55 +20,31 @@ [status-im.ui.screens.signing.styles :as styles] [status-im.react-native.resources :as resources] [status-im.ui.screens.hardwallet.pin.views :as pin.views] + [status-im.ui.components.bottom-panel.views :as bottom-panel] [status-im.utils.utils :as utils])) -(defn hide-panel-anim - [bottom-anim-value alpha-value window-height] - (anim/start - (anim/parallel - [(anim/spring bottom-anim-value {:toValue (- window-height) - :useNativeDriver true}) - (anim/timing alpha-value {:toValue 0 - :duration 500 - :useNativeDriver true})]))) - -(defn show-panel-anim - [bottom-anim-value alpha-value] - (anim/start - (anim/parallel - [(anim/spring bottom-anim-value {:toValue 40 - :useNativeDriver true}) - (anim/timing alpha-value {:toValue 0.4 - :duration 500 - :useNativeDriver true})]))) - (defn separator [] [react/view {:height 1 :background-color colors/gray-lighter}]) (defn displayed-name [contact] (if (or (:preferred-name contact) (:name contact)) (multiaccounts/displayed-name contact) - (:address contact))) + (utils/get-shortened-checksum-address (:address contact)))) (defn contact-item [title contact] [list-item/list-item - {:title-prefix title + {:title title :title-prefix-width 45 :type :small - :title - [copyable-text/copyable-text-view - {:copied-text (displayed-name contact)} - [react/text - {:ellipsize-mode :middle - :number-of-lines 1 - :style {:color colors/gray - :font-family "monospace" - ;; since this goes in list-item title - ;; which has design constraints - ;; specified in figma spec, - ;; better to do this - :line-height 22}} - (displayed-name contact)]]}]) + :accessories + [[copyable-text/copyable-text-view + {:copied-text (displayed-name contact)} + [react/text + {:ellipsize-mode :middle + :number-of-lines 1 + :style {:font-family "monospace" + :line-height 22}} + (displayed-name contact)]]]}]) (defn token-item [{:keys [icon color] :as token} display-symbol] (when token @@ -107,9 +81,10 @@ [{:style {:color colors/black}} (displayed-name contact)]] [react/text {:style {:margin-top 6 :color colors/gray}} (str fee " " fee-display-symbol " " (string/lower-case (i18n/label :t/network-fee)))])] - [react/touchable-highlight (when-not in-progress? {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])}) - [react/view {:padding 6} - [react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]]) + [button/button (merge {:type :secondary + :container-style {:padding-horizontal 24} + :label (i18n/label :t/cancel)} + (when-not in-progress? {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])}))]]) (views/defview keycard-pin-view [] (views/letsubs [pin [:hardwallet/pin] @@ -268,6 +243,13 @@ {:content (fn [] [sheets/fee-bottom-sheet fee-display-symbol]) :content-height 270}])}])) +(views/defview network-item [] + (views/letsubs [network-name [:network-name]] + [list-item/list-item + {:title :t/network + :type :small + :accessories [[react/text network-name]]}])) + (views/defview sheet [{:keys [from contact amount token approve?] :as tx}] (views/letsubs [fee [:signing/fee] sign [:signing/sign] @@ -275,7 +257,8 @@ {:keys [amount-error gas-error]} [:signing/amount-errors (:address from)] keycard-multiaccount? [:keycard-multiaccount?] prices [:prices] - wallet-currency [:wallet/currency]] + wallet-currency [:wallet/currency] + mainnet? [:mainnet?]] (let [display-symbol (wallet.utils/display-symbol token) fee-display-symbol (wallet.utils/display-symbol (tokens/native-currency chain))] [react/view styles/sheet @@ -285,6 +268,10 @@ [react/view {:padding-top 20} [password-view sign]] [react/view + (when-not mainnet? + [react/view + [network-item] + [separator]]) [contact-item (i18n/label :t/from) from] [separator] [contact-item (i18n/label :t/to) contact] @@ -300,47 +287,11 @@ :disabled? (or amount-error gas-error) :label :t/sign-with-password}])]])]))) -(defn signing-view [tx window-height] - (let [bottom-anim-value (anim/create-value window-height) - alpha-value (anim/create-value 0) - clear-timeout (atom nil) - current-tx (reagent/atom nil) - update? (reagent/atom nil)] - (reagent/create-class - {:component-will-update (fn [_ [_ tx _]] - (when @clear-timeout (js/clearTimeout @clear-timeout)) - (cond - @update? - (do (reset! update? false) - (show-panel-anim bottom-anim-value alpha-value)) - - (and @current-tx tx) - (do (reset! update? true) - (js/setTimeout #(reset! current-tx tx) 600) - (hide-panel-anim bottom-anim-value alpha-value (- window-height))) - - tx - (do (reset! current-tx tx) - (show-panel-anim bottom-anim-value alpha-value)) - - :else - (do (reset! clear-timeout (js/setTimeout #(reset! current-tx nil) 500)) - (hide-panel-anim bottom-anim-value alpha-value (- window-height))))) - :reagent-render (fn [] - (when @current-tx - [react/keyboard-avoiding-view {:style {:position :absolute :top 0 :bottom 0 :left 0 :right 0}} - [react/view {:flex 1} - [react/animated-view {:flex 1 :background-color :black :opacity alpha-value}] - [react/animated-view {:style {:position :absolute - :transform [{:translateY bottom-anim-value}] - :bottom 0 :left 0 :right 0}} - [react/view {:flex 1} - (if (:message @current-tx) - [message-sheet] - [sheet @current-tx])]]]]))}))) - (views/defview signing [] - (views/letsubs [tx [:signing/tx] - {window-height :height} [:dimensions/window]] - ;;we use select-keys here because we don't want to update view if other keys in map is changed - [signing-view (when tx (select-keys tx [:from :contact :amount :token :approve? :message])) window-height])) + (views/letsubs [tx [:signing/tx]] + [bottom-panel/animated-bottom-panel + ;;we use select-keys here because we don't want to update view if other keys in map are changed + (when tx (select-keys tx [:from :contact :amount :token :approve? :message])) + #(if (:message %) + [message-sheet] + [sheet %])])) \ No newline at end of file diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 35737d1c42..ec76e4cb39 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -20,6 +20,7 @@ [status-im.ui.screens.popover.views :as popover] [status-im.ui.screens.multiaccounts.recover.views :as recover.views] [status-im.utils.dimensions :as dimensions] + [status-im.ui.screens.wallet.send.views :as wallet] status-im.ui.screens.wallet.collectibles.etheremon.views status-im.ui.screens.wallet.collectibles.cryptostrikers.views status-im.ui.screens.wallet.collectibles.cryptokitties.views @@ -167,6 +168,7 @@ ;; see https://reactnavigation.org/docs/en/state-persistence.html#development-mode :persistNavigationState (when js/goog.DEBUG persist-state) :loadNavigationState (when js/goog.DEBUG load-state)}] + [wallet/prepare-transaction] [signing/signing] [bottom-sheet] [popover/popover]]]))}))) diff --git a/src/status_im/ui/screens/wallet/account/views.cljs b/src/status_im/ui/screens/wallet/account/views.cljs index 0cedec2187..b59f637978 100644 --- a/src/status_im/ui/screens/wallet/account/views.cljs +++ b/src/status_im/ui/screens/wallet/account/views.cljs @@ -39,7 +39,7 @@ [icons/icon icon {:color colors/white}] [react/text {:style {:margin-left 8 :color colors/white}} label]]]]) -(views/defview account-card [{:keys [address color]}] +(views/defview account-card [{:keys [address color] :as account}] (views/letsubs [currency [:wallet/currency] portfolio-value [:account-portfolio-value address] window-width [:dimensions/window-width]] @@ -62,9 +62,15 @@ :accessibility-label :share-wallet-address-icon}]]] [react/view {:height 52 :background-color colors/black-transparent-20 :border-bottom-right-radius 8 :border-bottom-left-radius 8 :flex-direction :row} - [button (i18n/label :t/wallet-send) :main-icons/send #(re-frame/dispatch [:navigate-to :wallet-send-transaction address])] + [button + (i18n/label :t/wallet-send) + :main-icons/send + #(re-frame/dispatch [:wallet/prepare-transaction-from-wallet account])] [react/view {:style styles/divider}] - [button (i18n/label :t/receive) :main-icons/receive #(re-frame/dispatch [:show-popover {:view :share-account :address address}])]]])) + [button + (i18n/label :t/receive) + :main-icons/receive + #(re-frame/dispatch [:show-popover {:view :share-account :address address}])]]])) (defn render-collectible [address] (fn [{:keys [name icon amount] :as collectible}] diff --git a/src/status_im/ui/screens/wallet/accounts/sheets.cljs b/src/status_im/ui/screens/wallet/accounts/sheets.cljs index b028543ae8..363169a067 100644 --- a/src/status_im/ui/screens/wallet/accounts/sheets.cljs +++ b/src/status_im/ui/screens/wallet/accounts/sheets.cljs @@ -35,20 +35,22 @@ :accessibility-label :wallet-backup-recovery-title :on-press #(hide-sheet-and-dispatch [:navigate-to :backup-seed])}])])) -(defn send-receive [address] +(defn send-receive [account] [react/view [list-item/list-item {:theme :action :title :t/wallet-send :icon :main-icons/send :accessibility-label :send-transaction-button - :on-press #(hide-sheet-and-dispatch [:navigate-to :wallet-send-transaction address])}] + :on-press #(hide-sheet-and-dispatch [:wallet/prepare-transaction-from-wallet account])}] [list-item/list-item {:theme :action :title :t/receive :icon :main-icons/receive :accessibility-label :receive-transaction-button - :on-press #(hide-sheet-and-dispatch [:show-popover {:view :share-account :address address}])}]]) + :on-press #(hide-sheet-and-dispatch + [:show-popover {:view :share-account + :address (:address account)}])}]]) (defn add-account [] [react/view diff --git a/src/status_im/ui/screens/wallet/accounts/views.cljs b/src/status_im/ui/screens/wallet/accounts/views.cljs index 33f58fe164..2b82212c2e 100644 --- a/src/status_im/ui/screens/wallet/accounts/views.cljs +++ b/src/status_im/ui/screens/wallet/accounts/views.cljs @@ -22,7 +22,7 @@ portfolio-value [:account-portfolio-value address]] [react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :wallet-account account]) :on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet - {:content (fn [] [sheets/send-receive address]) + {:content (fn [] [sheets/send-receive account]) :content-height 130}])} [react/view {:style (styles/card color)} [react/view {:flex-direction :row :align-items :center :justify-content :space-between} @@ -61,16 +61,18 @@ (when active? [react/view {:width 24 :height 3 :border-radius 4 :background-color colors/blue}])]) -(defn render-asset [currency] +(defn render-asset [currency & [on-press]] (fn [{:keys [icon decimals amount color value] :as token}] [list-item/list-item - {:title-prefix (wallet.utils/format-amount amount decimals) - :title (wallet.utils/display-symbol token) - :title-color-override colors/gray - :subtitle (str (if value value 0) " " currency) - :icon (if icon - [list/item-image icon] - [chat-icon/custom-icon-view-list (:name token) color])}])) + (cond-> {:title-prefix (wallet.utils/format-amount amount decimals) + :title (wallet.utils/display-symbol token) + :title-color-override colors/gray + :subtitle (str (if value value 0) " " currency) + :icon (if icon + [list/item-image icon] + [chat-icon/custom-icon-view-list (:name token) color])} + on-press + (assoc :on-press #(on-press token)))])) (views/defview assets [] (views/letsubs [{:keys [tokens nfts]} [:wallet/all-visible-assets-with-values] diff --git a/src/status_im/ui/screens/wallet/choose_recipient/styles.cljs b/src/status_im/ui/screens/wallet/choose_recipient/styles.cljs deleted file mode 100644 index 7934ae7334..0000000000 --- a/src/status_im/ui/screens/wallet/choose_recipient/styles.cljs +++ /dev/null @@ -1,90 +0,0 @@ -(ns status-im.ui.screens.wallet.choose-recipient.styles - (:require [status-im.ui.components.colors :as colors])) - -(def wallet-container - {:flex 1 - :background-color colors/blue}) - -(def recipient-button - {:flex-direction :row - :justify-content :space-between - :margin-vertical 10 - :margin-left 20}) - -(def recipient-button-text - {:color :white - :align-self :center - :font-size 14}) - -(def qr-container - {:position :absolute - :top 0 - :left 0 - :right 0 - :bottom 0}) - -(def preview - {:flex 1}) - -(def corner-dimensions - {:position :absolute - :width 40 - :height 40}) - -(defn corner-left-bottom [height width size] - (merge corner-dimensions {:bottom (int (/ (- height size) 2)) - :left (int (/ (- width size) 2))})) - -(defn corner-right-bottom [height width size] - (merge corner-dimensions {:right (int (/ (- width size) 2)) - :bottom (int (/ (- height size) 2))})) - -(defn corner-left-top [height width size] - (merge corner-dimensions {:top (int (/ (- height size) 2)) - :left (int (/ (- width size) 2))})) - -(defn corner-right-top [height width size] - (merge corner-dimensions {:top (int (/ (- height size) 2)) - :right (int (/ (- width size) 2))})) - -(def viewfinder-port {:position :absolute - :left 0 - :top 0 - :bottom 0 - :right 0 - :flex 1}) - -(defn viewfinder-translucent [height width size side] - (let [top-bottom-width width - top-bottom-height (int (/ (- height size) 2)) - left-right-width (int (/ (- width size) 2)) - left-right-height (- height (* 2 top-bottom-height))] - (cond-> {:position :absolute - :background-color :black - :opacity 0.7} - (= :top side) (assoc :height top-bottom-height - :width top-bottom-width) - (= :right side) (assoc :height left-right-height - :width left-right-width - :top top-bottom-height - :right 0) - (= :bottom side) (assoc :height top-bottom-height - :width top-bottom-width - :bottom 0 - :left 0) - (= :left side) (assoc :height left-right-height - :width left-right-width - :top top-bottom-height - :left 0)))) - -(def qr-code - {:flex 1 - :background-color colors/white-transparent - :align-items :stretch}) - -(defn qr-code-text [dimensions] - {:zIndex 1 - :padding-top 16 - :color :white - :text-align :center - :padding-vertical 16}) diff --git a/src/status_im/ui/screens/wallet/choose_recipient/views.cljs b/src/status_im/ui/screens/wallet/choose_recipient/views.cljs deleted file mode 100644 index 534808acf2..0000000000 --- a/src/status_im/ui/screens/wallet/choose_recipient/views.cljs +++ /dev/null @@ -1,69 +0,0 @@ -(ns status-im.ui.screens.wallet.choose-recipient.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [re-frame.core :as re-frame] - [status-im.i18n :as i18n] - [status-im.ui.components.toolbar :as toolbar] - [status-im.ui.components.camera :as camera] - [status-im.ui.components.react :as react] - [status-im.ui.components.toolbar.actions :as actions] - [status-im.ui.components.toolbar.view :as topbar] - [status-im.ui.screens.wallet.choose-recipient.styles :as styles] - [status-im.utils.platform :as platform])) - -(defn- topbar [camera-flashlight] - [topbar/toolbar - {:transparent? true} - [topbar/nav-button (actions/back-white actions/default-handler)] - [topbar/content-title {:color :white} - (i18n/label :t/wallet-choose-recipient)] - [topbar/actions [{:icon (if (= :on camera-flashlight) - :main-icons/flash-active - :main-icons/flash-inactive) - :icon-opts {:color :white} - :handler #(re-frame/dispatch [:wallet/toggle-flashlight])}]]]) - -(defn- viewfinder [{:keys [height width]} size] - (let [height (cond-> height - platform/iphone-x? (- 78))] - [react/view {:style styles/viewfinder-port} - [react/view {:style (styles/viewfinder-translucent height width size :top)}] - [react/view {:style (styles/viewfinder-translucent height width size :right)}] - [react/view {:style (styles/viewfinder-translucent height width size :bottom)}] - [react/view {:style (styles/viewfinder-translucent height width size :left)}] - [react/image {:source {:uri :corner_left_top} - :style (styles/corner-left-top height width size)}] - [react/image {:source {:uri :corner_right_top} - :style (styles/corner-right-top height width size)}] - [react/image {:source {:uri :corner_left_bottom} - :style (styles/corner-left-bottom height width size)}] - [react/image {:source {:uri :corner_right_bottom} - :style (styles/corner-right-bottom height width size)}]])) - -(defn- size [{:keys [height width]}] - (int (* 2 (/ (min height width) 3)))) - -(defview choose-recipient [] - (letsubs [read-once? (atom false) - dimensions [:dimensions/window] - camera-flashlight [:wallet.send/camera-flashlight]] - [react/view {:style styles/qr-code} - [topbar camera-flashlight] - [react/text {:style (styles/qr-code-text dimensions) - :accessibility-label :scan-qr-code-with-wallet-address-text} - (i18n/label :t/scan-qr-code)] - [react/view {:style styles/qr-container - :pointer-events :none} - [react/with-activity-indicator - {} - [camera/camera {:style styles/preview - ;:torchMode (camera/set-torch camera-flashlight) - :onBarCodeRead #(when-not @read-once? - (reset! read-once? true) - (re-frame/dispatch [:wallet/fill-request-from-url (camera/get-qr-code-data %) :qr]))}]] - [viewfinder dimensions (size dimensions)]] - [toolbar/toolbar - {:center {:type :secondary - :disabled? false - :on-press #(re-frame/dispatch [:navigate-back]) - :accessibility-label :cancel-button - :label :t/cancel}}]])) diff --git a/src/status_im/ui/screens/wallet/components/styles.cljs b/src/status_im/ui/screens/wallet/components/styles.cljs index 9329e7c868..809c8fe5ee 100644 --- a/src/status_im/ui/screens/wallet/components/styles.cljs +++ b/src/status_im/ui/screens/wallet/components/styles.cljs @@ -1,178 +1,10 @@ (ns status-im.ui.screens.wallet.components.styles - (:require [status-im.ui.components.colors :as colors] - [status-im.ui.components.styles :as components.styles])) - -(def cartouche-container - {:flex 1 - :margin-top 16 - :margin-horizontal 16}) - -(defn cartouche-content-wrapper [disabled?] - (merge - {:flex-direction :row - :margin-top 8 - :border-radius components.styles/border-radius - :padding-left 14 - :padding-right 8} - (if disabled? - {:border-width 1 - :border-color colors/gray-lighter} - {:background-color colors/gray-lighter}))) - -(def cartouche-icon-wrapper - {:flex 1 - :flex-direction :row - :justify-content :space-between - :align-items :center}) - -(def text-content - {:color colors/black}) - -(def text-secondary-content - {:color colors/gray}) - -(def text - {:margin-right 10}) - -(def text-input - (merge text-content - {:flex 1 - :padding-bottom 0 - :padding-top 0 - :height 52})) - -(defn contact-code-text-input [w] - {:text-align-vertical :top - :padding-top 16 - :padding-left 2 - :padding-right 8 - :width w - :height 72}) - -(def label - {:color colors/white}) - -(def network - {:color colors/white - :font-size 13}) - -(def network-container - {:flex-direction :row - :padding-horizontal 13 - :padding-vertical 11 - :align-items :center}) - -(def asset-container-read-only - {:margin-top 8 - :height 52 - :border-color colors/white-transparent-10 - :border-width 1 - :justify-content :center - :padding-left 14 - :padding-vertical 14 - :padding-right 8 - :border-radius 8}) - -(def asset-content-container - {:flex-direction :row - :align-items :center - :margin-vertical 11}) - -(def asset-icon - {:background-color colors/gray-lighter - :border-radius 50}) - -(def asset-text-content - {:flex 1 - :flex-direction :row - :justify-content :space-between - :align-items :center - :flex-wrap :wrap - :margin-left 10}) - -(def asset-label-content - {:flex-direction :row - :margin-right 10}) - -(def asset-label - {:margin-right 10}) - -(def asset-text - {:color colors/white}) - -(def container-disabled - {:border-width 1 - :border-color colors/white-transparent-10 - :border-radius 8}) - -(def wallet-container - {:flex-direction :row - :margin-top 8 - :height 52 - :border-width 1 - :border-color colors/white-transparent-10 - :align-items :center - :padding 14 - :border-radius 8}) - -(def wallet-name - {:color colors/white}) - -(defn participant [address?] - {:color (if address? colors/black colors/gray) - :flex-shrink 1}) - -(def recipient-container - {:flex-direction :row}) - -(def recipient-icon - {:margin-top 11}) - -(def recipient-name - {:flex 1 - :flex-direction :column - :margin-horizontal 12 - :margin-vertical 16}) - -(def recipient-address - {:margin-vertical 17}) - -(def recipient-no-address - {:color colors/gray}) + (:require [status-im.ui.components.colors :as colors])) (def recent-recipients {:flex 1 :background-color colors/white}) -(def wallet-value-container - {:flex 1 - :flex-direction :row}) - -(def wallet-value - {:padding-left 6 - :color colors/white-transparent}) - -(def wallet-value-amount - {:flex -1}) - (def separator - {:height 1 - :margin-horizontal 15 - :background-color colors/white-transparent-10}) - -(def button-text - {:color colors/white}) - -(def network-text - {:flex 1 - :color colors/black - :font-size 14 - :margin-left 16}) - -(def network-icon - {:width 40 - :height 40 - :border-radius (/ 40 2) - :background-color colors/green - :align-items :center - :justify-content :center}) + {:height 1 + :background-color colors/gray-lighter}) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/components/views.cljs b/src/status_im/ui/screens/wallet/components/views.cljs index e9b5ffd6ca..02d7f44226 100644 --- a/src/status_im/ui/screens/wallet/components/views.cljs +++ b/src/status_im/ui/screens/wallet/components/views.cljs @@ -2,341 +2,45 @@ (:require [clojure.string :as string] [re-frame.core :as re-frame] [reagent.core :as reagent] - [status-im.ethereum.core :as ethereum] - [status-im.ethereum.eip55 :as eip55] - [status-im.ethereum.tokens :as tokens] [status-im.i18n :as i18n] - [status-im.multiaccounts.core :as multiaccounts] - [status-im.ui.components.toolbar :as toolbar] - [status-im.ui.components.chat-icon.screen :as chat-icon] - [status-im.ui.components.colors :as colors] - [status-im.ui.components.icons.vector-icons :as vector-icons] - [status-im.ui.components.list-selection :as list-selection] - [status-im.ui.components.list.styles :as list.styles] - [status-im.ui.components.list.views :as list] [status-im.ui.components.react :as react] [status-im.ui.components.styles :as components.styles] - [status-im.ui.components.toolbar.actions :as actions] [status-im.ui.components.toolbar.view :as topbar] - [status-im.ui.components.tooltip.views :as tooltip] - [status-im.ui.screens.chat.photos :as photos] - [status-im.ui.screens.wallet.choose-recipient.views - :as - choose-recipient] [status-im.ui.screens.wallet.components.styles :as styles] - [status-im.wallet.utils :as wallet.utils] - [status-im.utils.core :as utils.core] - [status-im.utils.money :as money] - [status-im.utils.utils :as utils.utils]) + [status-im.ui.components.text-input.view :as text-input] + [status-im.ui.components.colors :as colors]) (:require-macros [status-im.utils.views :as views])) -;; Wallet tab has a different coloring scheme (dark) that forces color changes (background, text) -;; It might be replaced by some theme mechanism - -(defn text-input [props text] - [react/text-input (utils.core/deep-merge {:placeholder-text-color colors/gray - :selection-color colors/black - :style {:color colors/black - :height 52}} - props) - text]) - -(def default-action (actions/back-white actions/default-handler)) - -(defn topbar [title] - [topbar/simple-toolbar title]) - -(defn- top-view [avoid-keyboard?] - (if avoid-keyboard? - react/keyboard-avoiding-view - react/view)) - -(defn simple-screen - ([toolbar content] (simple-screen nil toolbar content)) - ([{:keys [avoid-keyboard?]} toolbar content] - [(top-view avoid-keyboard?) {:flex 1} - toolbar - content])) - -(defn- cartouche-content [{:keys [disabled?]} content] - [react/view {:style (styles/cartouche-content-wrapper disabled?)} - [react/view {:flex 1} - content]]) - -(defn cartouche [{:keys [disabled? on-press icon icon-opts] :or {icon :main-icons/next} :as m} header content] - [react/view {:style styles/cartouche-container} - [react/text - header] - (if (or disabled? (nil? on-press)) - [cartouche-content m content] - [react/touchable-highlight {:on-press on-press} - [react/view - [cartouche-content m - (if-not (true? disabled?) - [react/view styles/cartouche-icon-wrapper - [react/view {:flex 1} ;; Let content shrink if needed - content] - [vector-icons/icon icon icon-opts]] - content)]]])]) - -(defn view-asset [symbol] - [react/view - [react/i18n-text {:style styles/label :key :wallet-asset}] - [react/view styles/asset-container-read-only - [react/text {:style styles/asset-text} - (name symbol)]]]) - -(defn- type->handler [k] - (case k - :send :wallet.send/set-symbol - :request :wallet.request/set-symbol - (throw (str "Unknown type: " k)))) - -(defn- render-token [{:keys [symbol name icon decimals amount color] :as token} type] - [list/touchable-item #(do (re-frame/dispatch [(type->handler type) symbol]) - (re-frame/dispatch [:navigate-back])) - [react/view - [list/item - (if icon - [list/item-image icon] - [chat-icon/custom-icon-view-list name color]) - [list/item-content - [react/view {:flex-direction :row} - [react/text {:style styles/text} - name] - [react/text {:style {:text-transform :uppercase}} - (wallet.utils/display-symbol token)]] - [list/item-secondary (wallet.utils/format-amount amount decimals)]]]]]) - -(views/defview assets [type address] - (views/letsubs [assets [:wallet/transferrable-assets-with-amount address]] - [simple-screen - [topbar (i18n/label :t/wallet-assets)] - [react/view {:style (assoc components.styles/flex :background-color :white)} - [list/flat-list {:default-separator? true - :data assets - :key-fn (comp str :symbol) - :render-fn #(render-token % type)}]]])) - -(views/defview send-assets [] - (views/letsubs [address [:get-screen-params]] - [assets :send address])) - -(views/defview request-assets [] - (views/letsubs [address [:get-screen-params]] - [assets :request address])) - -(defn- type->view [k] - (case k - :send :wallet-send-assets - :request :wallet-request-assets - (throw (str "Unknown type: " k)))) - -(views/defview asset-selector [{:keys [disabled? type symbol error address]}] - (views/letsubs [balance [:balance address] - chain [:ethereum/chain-keyword] - all-tokens [:wallet/all-tokens]] - (let [{:keys [name icon decimals color] :as token} (tokens/asset-for all-tokens chain symbol)] - (when name - [react/view - [cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type) address])} - (i18n/label :t/wallet-asset) - [react/view {:style styles/asset-content-container - :accessibility-label :choose-asset-button} - (if icon - [list/item-image (assoc icon :style styles/asset-icon :image-style {:width 32 :height 32})] - [chat-icon/custom-icon-view-list name color 32]) - [react/view styles/asset-text-content - [react/view styles/asset-label-content - [react/text {:style (merge styles/text-content styles/asset-label)} - name] - [react/text {:style styles/text-secondary-content} - (wallet.utils/display-symbol token)]] - [react/text {:style (merge styles/text-secondary-content styles/asset-label)} - (str (wallet.utils/format-amount (get balance symbol) decimals))]]]] - (when error - [tooltip/tooltip error {}])])))) - -(defn- recipient-address [address modal?] - [react/text {:style (merge styles/recipient-address (when-not address styles/recipient-no-address)) - :accessibility-label :recipient-address-text} - (or (eip55/address->checksum (ethereum/normalized-address address)) - (if modal? - (i18n/label :t/new-contract) - (i18n/label :t/specify-recipient)))]) - -(views/defview recipient-contact [address name request?] - (views/letsubs [contact [:contacts/contact-by-address address]] - (let [address? (and (not (nil? address)) (not= address ""))] - [react/view styles/recipient-container - [react/view styles/recipient-icon - (when contact - [photos/photo - ;;TODO this should be done in a subscription - (multiaccounts/displayed-photo contact) - {:size list.styles/image-size}])] - [react/view {:style styles/recipient-name} - [react/text {:style (styles/participant true) - :accessibility-label (if request? :contact-name-text :recipient-name-text) - :number-of-lines 1} - name] - [react/text {:style (styles/participant (and (not name) address?)) - :accessibility-label (if request? :contact-address-text :recipient-address-text)} - (eip55/address->checksum (ethereum/normalized-address address))]]]))) - -(defn render-contact [contact request?] - [list/touchable-item #(re-frame/dispatch [:wallet/fill-request-from-contact contact request?]) - [list/item - [photos/photo - ;;TODO this should be done in a subscription - (multiaccounts/displayed-photo contact) - {:size list.styles/image-size}] - [list/item-content - [list/item-primary {:accessibility-label :contact-name-text} - (multiaccounts/displayed-name contact)] - [react/text {:style list.styles/secondary-text - :accessibility-label :contact-address-text} - (eip55/address->checksum (ethereum/normalized-address (:address contact)))]]]]) - -(defn render-account [account] - [list/touchable-item #(re-frame/dispatch [:wallet/fill-request-from-contact account false]) - [list/item - [chat-icon/custom-icon-view-list (:name account) (:color account)] - [list/item-content - [list/item-primary {:accessibility-label :contact-name-text} - (:name account)] - [react/text {:style list.styles/secondary-text - :accessibility-label :contact-address-text} - (eip55/address->checksum (ethereum/normalized-address (:address account)))]]]]) - -(views/defview recent-recipients [] - (views/letsubs [contacts [:contacts/active] - {:keys [request?]} [:get-screen-params :recent-recipients]] - [simple-screen - [topbar (i18n/label :t/recipient)] - [react/view styles/recent-recipients - [list/flat-list {:data contacts - :key-fn :address - :render-fn #(render-contact % request?)}]]])) - -(views/defview accounts [] - (views/letsubs [{:keys [accounts]} [:multiaccount]] - [simple-screen - [topbar (i18n/label :t/accounts)] - [react/view styles/recent-recipients - [list/flat-list {:data accounts - :key-fn :address - :render-fn render-account}]]])) - -;;TODO workaround for https://github.com/facebook/react-native/issues/23653 (https://github.com/status-im/status-react/issues/8548) -(def tw (reagent/atom "95%")) - -(views/defview contact-code [] - (views/letsubs [content (reagent/atom nil)] - [simple-screen {:avoid-keyboard? true} - [topbar (i18n/label :t/recipient)] - [react/view components.styles/flex - [cartouche {} - (i18n/label :t/recipient) - [text-input {:ref (fn [v] (js/setTimeout #(reset! tw (if v "100%" "95%")) 100)) - :multiline true - :style (styles/contact-code-text-input @tw) - :placeholder (i18n/label :t/recipient-code) - :on-change-text #(reset! content %) - :accessibility-label :recipient-address-input}]] - [toolbar/toolbar {:center {:type :secondary - :disabled? (string/blank? @content) - :on-press #(re-frame/dispatch [:wallet.send/set-recipient @content]) - :label :t/done}}]]])) - -(defn recipient-qr-code [] - [choose-recipient/choose-recipient]) - -(defn- request-camera-permissions [] - (re-frame/dispatch [:request-permissions {:permissions [:camera] - :on-allowed #(re-frame/dispatch [:navigate-to :recipient-qr-code]) - :on-denied #(utils.utils/set-timeout - (fn [] - (utils.utils/show-popup (i18n/label :t/error) - (i18n/label :t/camera-access-error))) - 50)}])) - -(defn- on-choose-recipient [contact-only? request?] - (list-selection/show {:title (i18n/label :t/wallet-choose-recipient) - ;;TODO temporary hide for v1 - #_(concat - [{:label (i18n/label :t/recent-recipients) - :action #(re-frame/dispatch [:navigate-to :recent-recipients {:request? request?}])}] - (when-not contact-only?)) - :options [{:label (i18n/label :t/accounts) - :action #(re-frame/dispatch [:navigate-to :select-account])} - {:label (i18n/label :t/scan-qr) - :action request-camera-permissions} - {:label (i18n/label :t/recipient-code) - :action #(re-frame/dispatch [:navigate-to :contact-code])}]})) - -(defn recipient-selector [{:keys [name address disabled? contact-only? request? modal?]}] - [cartouche {:on-press #(on-choose-recipient contact-only? request?) - :disabled? disabled? - :icon :main-icons/more - :icon-opts {:accessibility-label :choose-contact-button}} - (i18n/label :t/wallet-choose-recipient) - [react/view {:accessibility-label :choose-recipient-button} - (if name - [recipient-contact address name request?] - [recipient-address address modal?])]]) - -(defn amount-input [{:keys [input-options amount amount-text disabled?]} - {:keys [symbol decimals]}] - [react/view {:style components.styles/flex - :accessibility-label :specify-amount-button} - [text-input - (merge - input-options - ;; We only auto-correct and prettify user's input when it is valid and positive. - ;; Otherwise, user might want to fix his input and autocorrection will give more harm than good. - ;; Positive check is because we don't want to replace unfinished 0.000 with just plain 0, that is annoying and - ;; potentially dangerous on this screen (e.g. sending 7 ETH instead of 0.0007) - {:default-value (if (empty? amount-text) - (str (money/to-fixed (money/internal->formatted amount symbol decimals))) - amount-text)} - (if disabled? - {:editable false - :placeholder ""} - {:keyboard-type :numeric - :placeholder (i18n/label :t/amount-placeholder) - :style components.styles/flex - :accessibility-label :amount-input}))]]) - -(defn amount-selector [{:keys [error disabled?] :as m} token] - [react/view - [cartouche {:disabled? disabled?} - (i18n/label :t/amount) - [amount-input m token]] - (when error - [tooltip/tooltip error])]) - (defn separator [] [react/view styles/separator]) -(defn button-text [label] - [react/text {:style styles/button-text} - label]) +(defn- recipient-topbar [content] + [topbar/toolbar {:transparent? true} + [topbar/nav-text + {:style {:margin-left 16} + :handler #(do + (re-frame/dispatch [:set-in [:wallet/prepare-transaction :modal-opened?] false]) + (re-frame/dispatch [:navigate-back]))} + (i18n/label :t/cancel)] + [topbar/content-title {} + (i18n/label :t/recipient)] + [topbar/text-action + {:disabled? (string/blank? content) + :style {:margin-right 16} + :handler #(re-frame/dispatch [:wallet.send/set-recipient content])} + (i18n/label :t/done)]]) -(views/defview network-info [] - (views/letsubs [network-id [:chain-id]] - [react/view - [react/view styles/network-container - [react/view styles/network-icon - [vector-icons/icon :main-icons/network {:color :white}]] - [react/text - {:style {:flex 1 - :padding-left 16}} - (cond (ethereum/testnet? network-id) - (i18n/label :t/testnet-text {:testnet (get-in ethereum/chains [(ethereum/chain-id->chain-keyword network-id) :name] "Unknown")}) - - (ethereum/sidechain? network-id) - (i18n/label :t/sidechain-text {:sidechain (get-in ethereum/chains [(ethereum/chain-id->chain-keyword network-id) :name] "Unknown")}) - - :else - (i18n/label :t/mainnet-text))]]])) +(views/defview contact-code [] + (views/letsubs [content (reagent/atom nil)] + [react/view {:flex 1} + [recipient-topbar @content] + [react/view + [text-input/text-input-with-label + {:multiline true + :container {:margin 16 :padding-vertical 16 :height 72} + :style {:text-align-vertical :top :height 42} + :placeholder "0x... or username.domain.eth" ;(i18n/label :t/recipient-code) + :on-change-text #(reset! content %) + :accessibility-label :recipient-address-input}] + [react/text {:style {:color colors/gray :margin-horizontal 16}} + "Enter address or username of the recepient"]]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/navigation.cljs b/src/status_im/ui/screens/wallet/navigation.cljs index 96ee4818e8..73d55a1339 100644 --- a/src/status_im/ui/screens/wallet/navigation.cljs +++ b/src/status_im/ui/screens/wallet/navigation.cljs @@ -1,13 +1,7 @@ (ns status-im.ui.screens.wallet.navigation - (:require [status-im.constants :as constants] - [status-im.ui.screens.navigation :as navigation] + (:require [status-im.ui.screens.navigation :as navigation] [status-im.ui.screens.wallet.signing-phrase.views :as signing-phrase])) -(defn transaction-send-default [address] - {:method constants/web3-send-transaction - :from address - :symbol :ETH}) - (defmethod navigation/preload-data! :wallet-stack [db [event]] (let [wallet-set-up-passed? (get-in db [:multiaccount :wallet-set-up-passed?])] @@ -15,20 +9,6 @@ db (assoc db :popover/popover {:view [signing-phrase/signing-phrase]})))) -(defmethod navigation/preload-data! :wallet-send-transaction-request - [db [event _ address]] - (if (= event :navigate-back) - db - (-> db - (assoc-in [:wallet :request-transaction] {:symbol :ETH}) - (assoc-in [:wallet :send-transaction] (transaction-send-default address))))) - -(defmethod navigation/preload-data! :wallet-send-transaction - [db [event _ address]] - (if (= event :navigate-back) - db - (assoc-in db [:wallet :send-transaction] (transaction-send-default address)))) - (defmethod navigation/preload-data! :wallet-add-custom-token [db [event]] (dissoc db :wallet/custom-token-screen)) diff --git a/src/status_im/ui/screens/wallet/request/db.cljs b/src/status_im/ui/screens/wallet/request/db.cljs deleted file mode 100644 index 5b4a53eb43..0000000000 --- a/src/status_im/ui/screens/wallet/request/db.cljs +++ /dev/null @@ -1,10 +0,0 @@ -(ns status-im.ui.screens.wallet.request.db - (:require [cljs.spec.alpha :as spec] - [status-im.utils.money :as money])) - -(spec/def ::amount (spec/nilable money/valid?)) -(spec/def ::amount-error (spec/nilable string?)) -(spec/def ::amount-text (spec/nilable string?)) -(spec/def ::symbol (spec/nilable keyword?)) - -(spec/def :wallet/request-transaction (spec/keys :opt-un [::amount ::amount-error ::amount-text ::symbol])) diff --git a/src/status_im/ui/screens/wallet/request/styles.cljs b/src/status_im/ui/screens/wallet/request/styles.cljs deleted file mode 100644 index e74a03adb4..0000000000 --- a/src/status_im/ui/screens/wallet/request/styles.cljs +++ /dev/null @@ -1,28 +0,0 @@ -(ns status-im.ui.screens.wallet.request.styles - (:require [status-im.ui.components.colors :as colors])) - -(def hint - {:color colors/white-transparent}) - -(def footer - {:color colors/white - :border-color colors/white-transparent-10}) - -(def bottom-buttons - {:background-color colors/blue}) - -(def request-wrapper - {:flex 1 - :flex-direction :column}) - -;; Request panel - -(def request-details-wrapper - {:padding-bottom 60}) - -(def send-request - {:background-color colors/black-transparent - :margin-top 12 - :margin-bottom 16 - :margin-horizontal 16 - :height 42}) diff --git a/src/status_im/ui/screens/wallet/request/views.cljs b/src/status_im/ui/screens/wallet/request/views.cljs index dbae2eef50..243f817625 100644 --- a/src/status_im/ui/screens/wallet/request/views.cljs +++ b/src/status_im/ui/screens/wallet/request/views.cljs @@ -3,61 +3,12 @@ [reagent.core :as reagent] [status-im.ethereum.eip55 :as eip55] [status-im.ethereum.eip681 :as eip681] - [status-im.ethereum.tokens :as tokens] - [status-im.i18n :as i18n] [status-im.ui.components.button :as button] [status-im.ui.components.copyable-text :as copyable-text] [status-im.ui.components.qr-code-viewer.views :as qr-code-viewer] - [status-im.ui.components.react :as react] - [status-im.ui.components.styles :as components.styles] - [status-im.ui.components.toolbar :as toolbar] - [status-im.ui.screens.wallet.components.views :as wallet.components] - [status-im.ui.screens.wallet.request.styles :as styles] - [status-im.utils.utils :as utils] - [status-im.wallet.utils :as wallet.utils]) + [status-im.ui.components.react :as react]) (:require-macros [status-im.utils.views :as views])) -;;TODO DEPRECATED -(views/defview send-transaction-request [] - ;; TODO(jeluard) both send and request flows should be merged - (views/letsubs [chain [:ethereum/chain-keyword] - {:keys [amount amount-error amount-text symbol to - to-name public-key]} [:wallet.request/transaction] - network-status [:network-status] - all-tokens [:wallet/all-tokens] - scroll (atom nil)] - (let [{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)] - [wallet.components/simple-screen {:avoid-keyboard? true} - [wallet.components/topbar (i18n/label :t/new-request)] - [react/view components.styles/flex - [wallet.components/network-info] - [react/scroll-view {:ref #(reset! scroll %) :keyboardShouldPersistTaps :always} - [react/view styles/request-details-wrapper - [wallet.components/recipient-selector - {:contact-only? true - :address to - :name to-name - :request? true}] - [wallet.components/asset-selector - {:disabled? false - :type :request - :symbol symbol}] - [wallet.components/amount-selector - {:error amount-error - :disabled? (= :offline network-status) - :amount amount - :amount-text amount-text - :input-options {:on-focus (fn [] (when @scroll (utils/set-timeout #(.scrollToEnd @scroll) 100))) - :on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount % symbol decimals])}} - token]]] - [toolbar/toolbar - {:right {:type :next - :disabled? (or amount-error (not (and to amount))) - :on-press #(re-frame/dispatch [:wallet-send-request public-key amount - (wallet.utils/display-symbol token) decimals]) - :accessibility-label :sent-request-button - :label :t/send-request}}]]]))) - (views/defview share-address [] (views/letsubs [{:keys [address]} [:popover/popover] chain-id [:chain-id] diff --git a/src/status_im/ui/screens/wallet/send/db.cljs b/src/status_im/ui/screens/wallet/send/db.cljs deleted file mode 100644 index 5d2d1b9887..0000000000 --- a/src/status_im/ui/screens/wallet/send/db.cljs +++ /dev/null @@ -1,42 +0,0 @@ -(ns status-im.ui.screens.wallet.send.db - (:require [cljs.spec.alpha :as spec] - [status-im.utils.money :as money] - [status-im.utils.security :as security])) - -; transaction -(spec/def ::from (spec/nilable string?)) -(spec/def ::to (spec/nilable string?)) -(spec/def ::amount (spec/nilable money/valid?)) -(spec/def ::gas (spec/nilable money/valid?)) -(spec/def ::original-gas (spec/nilable money/valid?)) -(spec/def ::gas-price (spec/nilable money/valid?)) -; dapp transaction -(spec/def ::data (spec/nilable string?)) -(spec/def ::nonce (spec/nilable string?)) - -(spec/def ::to-name (spec/nilable string?)) -(spec/def ::amount-error (spec/nilable string?)) -(spec/def ::asset-error (spec/nilable string?)) -(spec/def ::amount-text (spec/nilable string?)) -(spec/def ::password (spec/nilable #(instance? security/MaskedData %))) -(spec/def ::wrong-password? (spec/nilable boolean?)) -(spec/def ::id (spec/nilable string?)) -(spec/def ::show-password-input? (spec/nilable boolean?)) -(spec/def ::height double?) -(spec/def ::width double?) -(spec/def ::camera-flashlight #{:on :off}) -(spec/def ::in-progress? boolean?) -(spec/def ::from-chat? (spec/nilable boolean?)) -(spec/def ::symbol (spec/nilable keyword?)) -(spec/def ::advanced? boolean?) -(spec/def ::public-key (spec/nilable string?)) -(spec/def ::method (spec/nilable string?)) -(spec/def ::tx-hash (spec/nilable string?)) -(spec/def ::on-result (spec/nilable any?)) -(spec/def ::on-error (spec/nilable any?)) - -(spec/def :wallet/send-transaction (spec/keys :opt-un [::amount ::to ::to-name ::amount-error ::asset-error ::amount-text - ::password ::show-password-input? ::id ::from ::data ::nonce - ::camera-flashlight ::in-progress? ::on-result ::on-error - ::wrong-password? ::from-chat? ::symbol ::advanced? - ::gas ::gas-price ::original-gas ::public-key ::method ::tx-hash])) diff --git a/src/status_im/ui/screens/wallet/send/sheets.cljs b/src/status_im/ui/screens/wallet/send/sheets.cljs new file mode 100644 index 0000000000..96c58c2811 --- /dev/null +++ b/src/status_im/ui/screens/wallet/send/sheets.cljs @@ -0,0 +1,70 @@ +(ns status-im.ui.screens.wallet.send.sheets + (:require-macros [status-im.utils.views :refer [defview letsubs] :as views]) + (:require [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.ui.components.react :as react] + [status-im.ui.components.list-item.views :as list-item] + [status-im.ui.components.chat-icon.screen :as chat-icon] + [status-im.ui.components.list.views :as list] + [status-im.ui.screens.wallet.accounts.views :as wallet.accounts] + [status-im.utils.utils :as utils.utils])) + +(views/defview assets [address] + (views/letsubs [{:keys [tokens]} [:wallet/visible-assets-with-values address] + currency [:wallet/currency]] + [list/flat-list + {:data tokens + :key-fn (comp str :symbol) + :render-fn (wallet.accounts/render-asset + (:code currency) + #(re-frame/dispatch [:wallet.send/set-symbol (:symbol %)]))}])) + +(defn render-account [field] + (fn [account] + [list-item/list-item + {:icon [chat-icon/custom-icon-view-list (:name account) (:color account)] + :title (:name account) + :on-press #(re-frame/dispatch [:wallet.send/set-field field account])}])) + +(views/defview accounts-list [field] + (views/letsubs [{:keys [accounts]} [:multiaccount]] + [list/flat-list {:data accounts + :key-fn :address + :render-fn (render-account field)}])) + +(defn- request-camera-permissions [] + (let [options {:handler :wallet.send/qr-scanner-result + :cancel-handler :wallet.send/qr-scanner-cancel}] + (re-frame/dispatch + [:request-permissions + {:permissions [:camera] + :on-allowed #(re-frame/dispatch [:wallet.send/qr-scanner-allowed options]) + :on-denied + #(utils.utils/set-timeout + (fn [] + (utils.utils/show-popup (i18n/label :t/error) + (i18n/label :t/camera-access-error))) + 50)}]))) + +(defn show-accounts-list [] + (re-frame/dispatch [:bottom-sheet/hide-sheet]) + (js/setTimeout #(re-frame/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [accounts-list :to]) + :content-height 300}]) 400)) + +(defn choose-recipient [] + [react/view + (for [item [{:title (i18n/label :t/accounts) + :icon :main-icons/profile + :theme :action + :on-press show-accounts-list} + {:title (i18n/label :t/scan-qr) + :icon :main-icons/qr + :theme :action + :on-press request-camera-permissions} + {:title (i18n/label :t/recipient-code) + :icon :main-icons/address + :theme :action + :on-press #(re-frame/dispatch [:wallet.send/navigate-to-recipient-code])}]] + ^{:key item} + [list-item/list-item item])]) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/send/styles.cljs b/src/status_im/ui/screens/wallet/send/styles.cljs index e00763e1e7..4e5876c8b6 100644 --- a/src/status_im/ui/screens/wallet/send/styles.cljs +++ b/src/status_im/ui/screens/wallet/send/styles.cljs @@ -1,56 +1,14 @@ -(ns status-im.ui.screens.wallet.send.styles - (:require [status-im.ui.components.colors :as colors] - [status-im.ui.screens.wallet.components.styles :as wallet.components.styles])) +(ns status-im.ui.screens.wallet.send.styles) -(def send-transaction-form - {:flex 1 - :padding-bottom 60}) +(defn sheet [small-screen?] + {:background-color :white + :border-top-right-radius 16 + :border-top-left-radius 16 + :padding-bottom (if small-screen? 40 60)}) -(def signing-phrase-description - {:padding-top 8}) - -(def password-container - {:flex 1 - :padding-vertical 20}) - -(def password - {:padding 0 - :height 20}) - -(def processing-view - {:position :absolute - :top 0 - :bottom 0 - :right 0 - :left 0 - :align-items :center - :justify-content :center - :background-color (str colors/black "1A")}) - -(def empty-text - {:text-align :center - :margin-top 22 - :margin-horizontal 92}) - -(def advanced-button - {:flex-direction :row - :background-color colors/black-transparent - :border-radius 50 - :padding 8 - :align-items :center}) - -(def advanced-label - {:text-align-vertical :center - :margin-left 4}) - -(def transaction-fee-info - {:flex-direction :row - :margin 15}) - -(def transaction-fee-input - {:keyboard-type :numeric - :auto-capitalize "none" - :placeholder "0.000" - :placeholder-text-color colors/white-transparent - :selection-color colors/white - :style wallet.components.styles/text-input}) +(defn header [small-screen?] + {:flex-direction :row + :align-items :center + :justify-content :space-between + :padding-top (when-not small-screen? 16) + :padding-left 16}) \ No newline at end of file diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index 7d680ebd89..e2362136bf 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -1,67 +1,122 @@ (ns status-im.ui.screens.wallet.send.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require-macros [status-im.utils.views :refer [defview letsubs] :as views]) (:require [re-frame.core :as re-frame] - [reagent.core :as reagent] [status-im.i18n :as i18n] [status-im.ui.components.react :as react] - [status-im.ui.components.styles :as components.styles] - [status-im.ui.components.toolbar.view :as topbar] [status-im.ui.components.toolbar :as toolbar] - [status-im.ui.screens.wallet.components.views :as wallet.components] - [status-im.ui.screens.wallet.send.styles :as styles])) + [status-im.ui.screens.wallet.send.styles :as styles] + [status-im.ui.components.bottom-panel.views :as bottom-panel] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.list-item.views :as list-item] + [status-im.ui.components.tooltip.views :as tooltip] + [status-im.ui.components.chat-icon.screen :as chat-icon] + [status-im.ui.components.list.views :as list] + [status-im.wallet.utils :as wallet.utils] + [status-im.ui.components.icons.vector-icons :as icons] + [status-im.multiaccounts.core :as multiaccounts] + [status-im.ui.screens.wallet.send.sheets :as sheets] + [status-im.ui.screens.wallet.components.views :as components] + [status-im.utils.utils :as utils] + [status-im.ui.components.button :as button])) -(defn- sign-transaction-button [sign-enabled?] - [toolbar/toolbar - {:right {:type :next - :disabled? (not sign-enabled?) - :on-press #(re-frame/dispatch [:wallet.ui/sign-transaction-button-clicked]) - :accessibility-label :sign-transaction-button - :label :t/transactions-sign-transaction}}]) +(defn header [small-screen?] + [react/view (styles/header small-screen?) + [react/view {:flex 1} + [react/text {:style (merge {:typography :title-bold} (when small-screen? {:font-size 15}))} + (i18n/label :t/send-transaction)]] + [button/button {:type :secondary + :container-style {:padding-horizontal 24} + :label (i18n/label :t/cancel) + :on-press #(re-frame/dispatch [:set :wallet/prepare-transaction nil])}]]) -;;TODO DEPRECATED -(defn- render-send-transaction-view - [{:keys [transaction scroll amount-input]}] - (let [{:keys [from amount amount-text amount-error token sign-enabled? - asset-error to to-name symbol]} transaction] - [wallet.components/simple-screen {:avoid-keyboard? true} - [topbar/simple-toolbar (i18n/label :t/send-transaction)] - [react/view components.styles/flex - [wallet.components/network-info] - [react/scroll-view {:keyboard-should-persist-taps :never - :keyboard-dismiss-mode :on-drag - :ref #(reset! scroll %) - :on-content-size-change #(when (and scroll @scroll) - (.scrollToEnd @scroll))} - [react/view styles/send-transaction-form - [wallet.components/recipient-selector - {:address to - :name to-name}] - [wallet.components/asset-selector - {:error asset-error - :address from - :type :send - :symbol symbol}] - [wallet.components/amount-selector - {:error amount-error - :amount amount - :amount-text amount-text - :input-options {:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount %]) - :ref (partial reset! amount-input)}} token]]] - [sign-transaction-button sign-enabled?]]])) +(defn asset-selector [{:keys [token from]}] + (let [{:keys [name icon color]} token] + [react/touchable-highlight + {:on-press #(do + (re-frame/dispatch [:dismiss-keyboard]) + (re-frame/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [sheets/assets (:address from)]) + :content-height 300}]))} + [react/view {:style {:flex-direction :row + :align-items :center + :margin-left 16} + :accessibility-label :choose-asset-button} + (if icon + [list/item-image (assoc icon :style {:background-color colors/gray-lighter + :border-radius 50} :image-style {:width 32 :height 32})] + [chat-icon/custom-icon-view-list name color 32]) + [react/text {:style {:margin-left 8}} + (wallet.utils/display-symbol token)] + [icons/icon :main-icons/dropdown {:color colors/gray}]]])) -(defn- send-transaction-view [{:keys [scroll]}] - (let [amount-input (atom nil) - handler #(when (and scroll @scroll @amount-input (.isFocused @amount-input)) (.scrollToEnd @scroll))] - (reagent/create-class - {:component-did-mount (fn [_] - ;;NOTE(goranjovic): keyboardDidShow is for android and keyboardWillShow for ios - (.addListener react/keyboard "keyboardDidShow" handler) - (.addListener react/keyboard "keyboardWillShow" handler)) - :reagent-render (fn [opts] (render-send-transaction-view - (assoc opts :amount-input amount-input)))}))) +(defn render-account [account {:keys [amount decimals] :as token}] + [list-item/list-item + {:icon [chat-icon/custom-icon-view-list (:name account) (:color account)] + :title (:name account) + :subtitle (str (wallet.utils/format-amount amount decimals) + " " + (wallet.utils/display-symbol token)) + :accessories [:chevron] + :on-press #(do + (re-frame/dispatch [:dismiss-keyboard]) + (re-frame/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [sheets/accounts-list :from]) + :content-height 300}]))}]) -(defview send-transaction [] - (letsubs [transaction [:wallet.send/transaction] - scroll (atom nil)] - [send-transaction-view {:transaction transaction - :scroll scroll}])) +(defn render-contact [contact from-chat?] + (if from-chat? + [list-item/list-item {:title (multiaccounts/displayed-name contact) + :icon (multiaccounts/displayed-photo contact)}] + [list-item/list-item + {:title (utils/get-shortened-checksum-address + (if (string? contact) contact (:address contact))) + :subtitle (when-not contact (i18n/label :t/wallet-choose-recipient)) + :on-press #(do + (re-frame/dispatch [:dismiss-keyboard]) + (re-frame/dispatch [:bottom-sheet/show-sheet + {:content sheets/choose-recipient + :content-height 200}])) + :accessories [:chevron]}])) + +(views/defview sheet [_] + (views/letsubs [{:keys [amount-error amount-text from token to sign-enabled? from-chat?] :as tx} + [:wallet.send/prepare-transaction-with-balance] + small-screen? [:dimensions/small-screen?]] + [react/view (styles/sheet small-screen?) + [header small-screen?] + [react/view (merge {:flex-direction :row :padding-horizontal 24 :align-items :center} + (when-not small-screen? + {:margin-top 16 :margin-bottom 16})) + [react/text-input + {:style {:font-size (if small-screen? 24 38) + :color (when amount-error colors/red) + :flex-shrink 1} + :keyboard-type :numeric + :accessibility-label :amount-input + :default-value amount-text + :auto-focus true + :on-change-text #(re-frame/dispatch [:wallet.send/set-amount-text %]) + :placeholder "0.0 "}] + [asset-selector tx] + (when amount-error + [tooltip/tooltip amount-error {:bottom-value 2 + :font-size 12}])] + [components/separator] + [list-item/list-item {:type :section-header :title :t/from}] + [render-account from token] + [list-item/list-item {:type :section-header :title :t/to}] + [render-contact to from-chat?] + [toolbar/toolbar + {:center {:label :t/wallet-send + :disabled? (not sign-enabled?) + :on-press #(re-frame/dispatch [:wallet.ui/sign-transaction-button-clicked tx])}}]])) + +(defview prepare-transaction [] + (letsubs [tx [:wallet/prepare-transaction]] + [bottom-panel/animated-bottom-panel + ;;we use select-keys here because we don't want to update view if other keys in map are changed + ;; and because modal screen (qr code scanner) can't be opened over bottom sheet we have to use :modal-opened? + ;; to hide our transaction panel + (when (and tx (not (:modal-opened? tx))) + (select-keys tx [:from-chat?])) + sheet])) \ No newline at end of file diff --git a/src/status_im/utils/universal_links/core.cljs b/src/status_im/utils/universal_links/core.cljs index d3c31e19c4..336c8b1dd5 100644 --- a/src/status_im/utils/universal_links/core.cljs +++ b/src/status_im/utils/universal_links/core.cljs @@ -81,8 +81,8 @@ (navigation/navigate-to-cofx (assoc-in cofx [:db :contacts/identity] public-key) :profile nil)))) (fx/defn handle-eip681 [cofx url] - {:dispatch-n [[:navigate-to :wallet-send-transaction] - [:wallet/fill-request-from-url url :deep-link]]}) + {:dispatch-n [[:navigate-to :wallet] + [:wallet/fill-request-from-url url]]}) (defn handle-not-found [full-url] (log/info "universal-links: no handler for " full-url)) diff --git a/src/status_im/wallet/choose_recipient/core.cljs b/src/status_im/wallet/choose_recipient/core.cljs index 72b528400b..fb9f902220 100644 --- a/src/status_im/wallet/choose_recipient/core.cljs +++ b/src/status_im/wallet/choose_recipient/core.cljs @@ -8,7 +8,8 @@ [status-im.ethereum.ens :as ens] [status-im.i18n :as i18n] [status-im.utils.money :as money] - [status-im.utils.fx :as fx])) + [status-im.utils.fx :as fx] + [status-im.ui.screens.navigation :as navigation])) (fx/defn toggle-flashlight {:events [:wallet/toggle-flashlight]} @@ -23,21 +24,27 @@ (defn- fill-request-details [db {:keys [address name value symbol gas gasPrice public-key from-chat?]} request?] {:pre [(not (nil? address))]} (let [name (or name (find-address-name db address)) + ;;TODO request isn't implemented data-path (if request? - [:wallet :request-transaction] - [:wallet :send-transaction])] - (update-in db data-path - (fn [{old-symbol :symbol :as old-transaction}] - (let [symbol-changed? (not= old-symbol symbol)] - (cond-> (assoc old-transaction :to address :to-name name :public-key public-key) - value (assoc :amount value) - symbol (assoc :symbol symbol) - (and gas symbol-changed?) (assoc :gas (money/bignumber gas)) - from-chat? (assoc :from-chat? from-chat?) - (and gasPrice symbol-changed?) - (assoc :gas-price (money/bignumber gasPrice)) - (and symbol (not gasPrice) symbol-changed?) - (assoc :gas-price (ethereum/estimate-gas symbol)))))))) + :wallet/prepare-transaction + :wallet/prepare-transaction)] + (update db data-path + (fn [{old-symbol :symbol :as old-transaction}] + (let [symbol-changed? (not= old-symbol symbol)] + (cond-> (assoc old-transaction + :to address :to-name name :public-key public-key + :gas (money/bignumber gas) + :gas-price (money/bignumber gasPrice)) + value (assoc :amount value) + symbol (assoc :symbol symbol) + from-chat? (assoc :from-chat? from-chat?))))))) + +;;TODO request isn't implemented +(fx/defn fill-request-from-contact + {:events [:wallet/fill-request-from-contact]} + [{db :db} {:keys [address name public-key]} request?] + {:db (fill-request-details db {:address address :name name :public-key public-key} request?) + :dispatch [:navigate-back]}) (defn- extract-details "First try to parse as EIP681 URI, if not assume this is an address directly. @@ -51,16 +58,13 @@ ;; NOTE(janherich) - whenever changing assets, we want to clear the previusly set amount/amount-text (defn changed-asset [{:keys [db] :as fx} old-symbol new-symbol] (-> fx - (merge {:wallet/update-gas-price - {:success-event :wallet/update-gas-price-success - :edit? false}}) - (assoc-in [:db :wallet :send-transaction :amount] nil) - (assoc-in [:db :wallet :send-transaction :amount-text] nil) - (assoc-in [:db :wallet :send-transaction :asset-error] + (assoc-in [:db :wallet/prepare-transaction :amount] nil) + (assoc-in [:db :wallet/prepare-transaction :amount-text] nil) + (assoc-in [:db :wallet/prepare-transaction :asset-error] (i18n/label :t/changed-asset-warning {:old old-symbol :new new-symbol})))) (defn changed-amount-warning [fx old-amount new-amount] - (assoc-in fx [:db :wallet :send-transaction :amount-error] + (assoc-in fx [:db :wallet/prepare-transaction :amount-error] (i18n/label :t/changed-amount-warning {:old old-amount :new new-amount}))) (defn use-default-eth-gas [fx] @@ -84,41 +88,48 @@ (let [checksum (eip55/address->checksum recipient)] (if (eip55/valid-address-checksum? checksum) {:db (-> db - (assoc-in [:wallet :send-transaction :to] checksum) - (assoc-in [:wallet :send-transaction :to-name] nil)) + (assoc-in [:wallet/prepare-transaction :to] checksum) + (assoc-in [:wallet/prepare-transaction :modal-opened?] false)) :dispatch [:navigate-back]} {:ui/show-error (i18n/label :t/wallet-invalid-address-checksum {:data recipient})})) {:ui/show-error (i18n/label :t/wallet-invalid-address {:data recipient})})))) (fx/defn fill-request-from-url {:events [:wallet/fill-request-from-url]} - [{{:networks/keys [current-network] :wallet/keys [all-tokens] :as db} :db} data origin] - (let [current-chain-id (get-in constants/default-networks [current-network :config :NetworkId]) + [{{:networks/keys [current-network] :wallet/keys [all-tokens] :as db} :db} data] + (let [current-chain-id (get-in constants/default-networks [current-network :config :NetworkId]) {:keys [address chain-id] :as details} (extract-details data current-chain-id all-tokens) - valid-network? (boolean (= current-chain-id chain-id)) - previous-state (get-in db [:wallet :send-transaction]) - old-symbol (:symbol previous-state) - new-symbol (:symbol details) - old-amount (:amount previous-state) - new-amount (:value details) - new-gas (:gas details) - symbol-changed? (and old-symbol new-symbol (not= old-symbol new-symbol))] + valid-network? (boolean (= current-chain-id chain-id)) + previous-state (get db :wallet/prepare-transaction) + old-symbol (:symbol previous-state) + new-symbol (:symbol details) + old-amount (:amount previous-state) + new-amount (:value details) + symbol-changed? (and old-symbol new-symbol (not= old-symbol new-symbol)) + amount-changed? (and old-amount new-amount (not= old-amount new-amount))] (cond-> {:db db} - (not= :deep-link origin) (assoc :dispatch [:navigate-back]) ;; Only navigate-back when called from within wallet (and address valid-network?) (update :db #(fill-request-details % details false)) symbol-changed? (changed-asset old-symbol new-symbol) - (and old-amount new-amount (not= old-amount new-amount)) (changed-amount-warning old-amount new-amount) - ;; NOTE(goranjovic) - the next line is there is because QR code scanning switches the amount to ETH - ;; automatically, so we need to update the gas limit accordingly. The check for origin screen is there - ;; so that we wouldn't also switch gas limit to ETH specific if the user pastes address as text. - ;; We need to check if address is defined so that we wouldn't trigger this behavior when invalid QR is scanned - ;; (e.g. public-key) - (and address (= origin :qr) (not new-gas) symbol-changed?) (use-default-eth-gas) + amount-changed? (changed-amount-warning old-amount new-amount) + (not (:from previous-state)) + (update :db assoc-in [:wallet/prepare-transaction :from] + (ethereum/get-default-account (get-in db [:multiaccount :accounts]))) + (not old-symbol) + (update :db assoc-in [:wallet/prepare-transaction :symbol] (or new-symbol :ETH)) (not address) (assoc :ui/show-error (i18n/label :t/wallet-invalid-address {:data data})) - (and address (not valid-network?)) (assoc :ui/show-error (i18n/label :t/wallet-invalid-chain-id {:data data :chain current-chain-id}))))) + (and address (not valid-network?)) + (assoc :ui/show-error (i18n/label :t/wallet-invalid-chain-id + {:data data :chain current-chain-id}))))) -(fx/defn fill-request-from-contact - {:events [:wallet/fill-request-from-contact]} - [{db :db} {:keys [address name public-key]} request?] - {:db (fill-request-details db {:address address :name name :public-key public-key} request?) - :dispatch [:navigate-back]}) +(fx/defn qr-scanner-result + {:events [:wallet.send/qr-scanner-result]} + [{db :db :as cofx} data opts] + (fx/merge cofx + {:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] false)} + (navigation/navigate-back) + (fill-request-from-url data))) + +(fx/defn qr-scanner-cancel + {:events [:wallet.send/qr-scanner-cancel]} + [{db :db} _] + {:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] false)}) \ No newline at end of file diff --git a/src/status_im/wallet/core.cljs b/src/status_im/wallet/core.cljs index d0595f73df..93a303627a 100644 --- a/src/status_im/wallet/core.cljs +++ b/src/status_im/wallet/core.cljs @@ -20,7 +20,9 @@ [status-im.wallet.db :as wallet.db] [status-im.ethereum.abi-spec :as abi-spec] [status-im.signing.core :as signing] - [clojure.string :as string])) + [clojure.string :as string] + [status-im.contact.db :as contact.db] + [status-im.ui.components.bottom-sheet.core :as bottom-sheet])) (re-frame/reg-fx :wallet/get-balance @@ -342,17 +344,9 @@ (multiaccounts.update/update-settings cofx new-settings {}))) (fx/defn set-and-validate-amount - {:events [:wallet.send/set-and-validate-amount]} + {:events [:wallet.send/set-amount-text]} [{:keys [db]} amount] - (let [chain (ethereum/chain-keyword db) - all-tokens (:wallet/all-tokens db) - symbol (get-in db [:wallet :send-transaction :symbol]) - {:keys [decimals]} (tokens/asset-for all-tokens chain symbol) - {:keys [value error]} (wallet.db/parse-amount amount decimals)] - {:db (-> db - (assoc-in [:wallet :send-transaction :amount] (money/formatted->internal value symbol decimals)) - (assoc-in [:wallet :send-transaction :amount-text] amount) - (assoc-in [:wallet :send-transaction :amount-error] error))})) + {:db (assoc-in db [:wallet/prepare-transaction :amount-text] amount)}) (fx/defn set-symbol {:events [:wallet.send/set-symbol]} @@ -365,21 +359,27 @@ (fx/defn sign-transaction-button-clicked {:events [:wallet.ui/sign-transaction-button-clicked]} - [{:keys [db] :as cofx}] - (let [{:keys [to symbol amount from]} (get-in cofx [:db :wallet :send-transaction]) - {:keys [symbol address]} (tokens/asset-for (:wallet/all-tokens db) - (ethereum/chain-keyword db) - symbol) + [{:keys [db] :as cofx} {:keys [to amount from token from-chat? gas gasPrice]}] + (let [{:keys [symbol address]} token amount-hex (str "0x" (abi-spec/number-to-hex amount)) - to-norm (ethereum/normalized-address to)] - (signing/sign cofx {:tx-obj (if (= symbol :ETH) - {:to to-norm - :from from - :value amount-hex} - {:to (ethereum/normalized-address address) - :from from - :data (abi-spec/encode "transfer(address,uint256)" [to-norm amount-hex])}) - :on-result [:navigate-back]}))) + to-norm (ethereum/normalized-address (if (string? to) to (:address to))) + from-address (:address from)] + (fx/merge cofx + {:db (dissoc db :wallet/prepare-transaction)} + #(if from-chat? + nil;;TODO from chat, send request message or if ens name sign tx and send tx message + (signing/sign % {:tx-obj (if (= symbol :ETH) + {:to to-norm + :from from-address + :value amount-hex} + {:to (ethereum/normalized-address address) + :from from-address + :data (abi-spec/encode + "transfer(address,uint256)" + [to-norm amount-hex]) + ;;Note: data from qr (eip681) + :gas gas + :gasPrice gasPrice})}))))) (fx/defn set-and-validate-amount-request {:events [:wallet.request/set-and-validate-amount]} @@ -390,8 +390,60 @@ (assoc-in [:wallet :request-transaction :amount-text] amount) (assoc-in [:wallet :request-transaction :amount-error] error))})) +;;TODO request isn't implemented (fx/defn set-symbol-request {:events [:wallet.request/set-symbol]} [{:keys [db]} symbol] - {:db (-> db - (assoc-in [:wallet :request-transaction :symbol] symbol))}) + {:db (assoc-in db [:wallet :request-transaction :symbol] symbol)}) + +(fx/defn prepare-transaction-from-chat + {:events [:wallet/prepare-transaction-from-chat]} + [{:keys [db]}] + (let [identity (:current-chat-id db)] + {:db (assoc db :wallet/prepare-transaction + {:from (ethereum/get-default-account (get-in db [:multiaccount :accounts])) + :to (or (get-in db [:contacts/contacts identity]) + (-> identity + contact.db/public-key->new-contact + contact.db/enrich-contact)) + :symbol :ETH + :from-chat? true})})) + +(fx/defn prepare-transaction-from-wallet + {:events [:wallet/prepare-transaction-from-wallet]} + [{:keys [db]} account] + {:db (assoc db :wallet/prepare-transaction + {:from account + :to nil + :symbol :ETH + :from-chat? false})}) + +(fx/defn qr-scanner-allowed + {:events [:wallet.send/qr-scanner-allowed]} + [{:keys [db] :as cofx} options] + (fx/merge cofx + {:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] true)} + (bottom-sheet/hide-bottom-sheet) + (navigation/navigate-to-cofx :qr-scanner options))) + +(fx/defn wallet-send-set-symbol + {:events [:wallet.send/set-symbol]} + [{:keys [db] :as cofx} symbol] + (fx/merge cofx + {:db (assoc-in db [:wallet/prepare-transaction :symbol] symbol)} + (bottom-sheet/hide-bottom-sheet))) + +(fx/defn wallet-send-set-field + {:events [:wallet.send/set-field]} + [{:keys [db] :as cofx} field value] + (fx/merge cofx + {:db (assoc-in db [:wallet/prepare-transaction field] value)} + (bottom-sheet/hide-bottom-sheet))) + +(fx/defn navigate-to-recipient-code + {:events [:wallet.send/navigate-to-recipient-code]} + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (assoc-in db [:wallet/prepare-transaction :modal-opened?] true)} + (bottom-sheet/hide-bottom-sheet) + (navigation/navigate-to-cofx :contact-code nil))) \ No newline at end of file diff --git a/src/status_im/wallet/db.cljs b/src/status_im/wallet/db.cljs index 49014f2243..c705352814 100644 --- a/src/status_im/wallet/db.cljs +++ b/src/status_im/wallet/db.cljs @@ -1,8 +1,6 @@ (ns status-im.wallet.db (:require [cljs.spec.alpha :as spec] [status-im.i18n :as i18n] - status-im.ui.screens.wallet.request.db - status-im.ui.screens.wallet.send.db [status-im.utils.money :as money] [status-im.utils.priority-map :refer [empty-transaction-map]])) @@ -25,9 +23,7 @@ (spec/def :wallet/balance any?) (spec/def :wallet/filters set?) -(spec/def :wallet/wallet (spec/keys :opt-un [:wallet/send-transaction - :wallet/request-transaction - :wallet/transactions-queue +(spec/def :wallet/wallet (spec/keys :opt-un [:wallet/transactions-queue :wallet/balance-loading? :wallet/errors :wallet/transactions diff --git a/src/status_im/wallet/utils.cljs b/src/status_im/wallet/utils.cljs index a197ee922f..fbb1ac0f1a 100644 --- a/src/status_im/wallet/utils.cljs +++ b/src/status_im/wallet/utils.cljs @@ -9,9 +9,9 @@ ;;NOTE(goranjovic) - we are internally using symbol ETH for native currencies of any ethereum network ;; some sidechains have different names for this native currency, which we handle with `symbol-display` override. -(defn display-symbol [{:keys [symbol-display symbol] :as token}] - (when token - (clojure.core/name (or symbol-display symbol)))) +(defn display-symbol [{:keys [symbol-display symbol]}] + (when-let [name (or symbol-display symbol)] + (clojure.core/name name))) ;;NOTE(goranjovic) - in addition to custom symbol display, some sidechain native currencies are listed under a different ;; ticker on exchange networks. We handle that with `symbol-exchange` override. diff --git a/translations/en.json b/translations/en.json index 7bc485c3e9..87a811ef71 100644 --- a/translations/en.json +++ b/translations/en.json @@ -463,7 +463,7 @@ "finishing-card-setup-steps": "> Loading keys to the card\n> Generating multiaccount", "fleet": "Fleet", "fleet-settings": "Fleet settings", - "follow-your-interests": "Follow your interests in one of the many Public Chats.", + "follow-your-interests": "Follow your interests in one of the many Public Chat.", "free": "↓ Free", "from": "From", "gas-limit": "Gas limit",