[ISSUE #2881] Updated wallet / send transaction to latest design
Signed-off-by: Oskar Thoren <ot@oskarthoren.com>
This commit is contained in:
parent
1046560498
commit
d958c96d67
|
@ -7885,9 +7885,9 @@
|
|||
"integrity": "sha1-v74cRNilsUpvOjpAXYrab1R6UW4="
|
||||
},
|
||||
"react-native-popup-menu": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-popup-menu/-/react-native-popup-menu-0.8.3.tgz",
|
||||
"integrity": "sha1-HbsLT4iclBC2myKKidV7Vq6lzC4="
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-popup-menu/-/react-native-popup-menu-0.12.2.tgz",
|
||||
"integrity": "sha1-ZWi1LPZFZj8GClUPIyQfoVUr+g4="
|
||||
},
|
||||
"react-native-qrcode": {
|
||||
"version": "0.2.6",
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
"react-native-linear-gradient": "2.4.0",
|
||||
"react-native-orientation": "3.1.0",
|
||||
"react-native-os": "1.1.0",
|
||||
"react-native-popup-menu": "0.8.3",
|
||||
"react-native-popup-menu": "0.12.2",
|
||||
"react-native-qrcode": "0.2.6",
|
||||
"react-native-randombytes": "3.0.0",
|
||||
"react-native-sortable-listview": "0.2.6",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
(ns status-im.android.platform
|
||||
(:require [status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
(ns status-im.android.platform)
|
||||
|
||||
(def fonts
|
||||
{:light {:font-family "Roboto-Light"}
|
||||
|
@ -9,21 +8,10 @@
|
|||
:toolbar-title {:font-family "Roboto-Regular"}
|
||||
:roboto-mono {:font-family "RobotoMono-Medium"}})
|
||||
|
||||
;; Dialogs
|
||||
|
||||
(defn show-dialog [{:keys [title options callback]}]
|
||||
(let [dialog (new rn-dependencies/dialogs)]
|
||||
(.set dialog (clj->js {:title title
|
||||
:items (mapv :text options)
|
||||
:itemsCallback callback}))
|
||||
(.show dialog)))
|
||||
|
||||
|
||||
;; Structure to be exported
|
||||
|
||||
(def platform-specific
|
||||
{:fonts fonts
|
||||
:list-selection-fn show-dialog
|
||||
:tabs {:tab-shadows? true}
|
||||
:chats {:action-button? true
|
||||
:new-chat-in-toolbar? false
|
||||
|
|
|
@ -17,14 +17,13 @@
|
|||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon-screen]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
[status-im.ui.components.sync-state.offline :as offline]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]))
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.animation :as animation]))
|
||||
|
||||
(defview chat-icon []
|
||||
(letsubs [{:keys [chat-id group-chat name color]} [:get-current-chat]]
|
||||
[chat-icon-screen/chat-icon-view-action chat-id group-chat name color true]))
|
||||
(letsubs [{:keys [chat-id group-chat name]} [:get-current-chat]]
|
||||
[chat-icon-screen/chat-icon-view-action chat-id group-chat name true]))
|
||||
|
||||
(defn- toolbar-action [show-actions?]
|
||||
[react/touchable-highlight
|
||||
|
@ -51,7 +50,7 @@
|
|||
creating? [:get :accounts/creating-account?]]
|
||||
[react/view
|
||||
[status-bar/status-bar]
|
||||
[toolbar/toolbar {:show-sync-bar? true}
|
||||
[toolbar/toolbar {}
|
||||
(when-not (or show-actions? creating?)
|
||||
(if (empty? accounts)
|
||||
[toolbar/nav-clear-text (i18n/label :t/recover)
|
||||
|
@ -76,15 +75,15 @@
|
|||
|
||||
(defview messages-view-animation [message-view]
|
||||
;; smooths out appearance of message-view
|
||||
(letsubs [opacity (anim/create-value 0)
|
||||
(letsubs [opacity (animation/create-value 0)
|
||||
duration (if platform/android? 100 200)
|
||||
timeout (if platform/android? 50 0)]
|
||||
{:component-did-mount (fn [component]
|
||||
(anim/start
|
||||
(anim/anim-sequence
|
||||
[(anim/anim-delay timeout)
|
||||
(anim/spring opacity {:toValue 1
|
||||
:duration duration})])))}
|
||||
(animation/start
|
||||
(animation/anim-sequence
|
||||
[(animation/anim-delay timeout)
|
||||
(animation/spring opacity {:toValue 1
|
||||
:duration duration})])))}
|
||||
[react/with-activity-indicator
|
||||
{:style style/message-view-preview
|
||||
:preview [react/view style/message-view-preview]}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
{:flex-direction :row
|
||||
:align-items :flex-end})
|
||||
|
||||
(defnstyle input-root [content-height anim-margin]
|
||||
(defn input-root [content-height anim-margin]
|
||||
{:align-items :flex-start
|
||||
:background-color color-input
|
||||
:flex-direction :row
|
||||
|
@ -45,8 +45,7 @@
|
|||
:margin-top anim-margin
|
||||
:padding-left 10
|
||||
:padding-right 10
|
||||
:android {:border-radius 4}
|
||||
:ios {:border-radius 8}})
|
||||
:border-radius 8})
|
||||
|
||||
(defnstyle input-touch-handler-view [container-width]
|
||||
{:position :absolute
|
||||
|
|
|
@ -95,12 +95,11 @@
|
|||
(merge style-message-text
|
||||
{:marginTop (if incoming-group 4 0)}))
|
||||
|
||||
(defnstyle message-view
|
||||
(defn message-view
|
||||
[{:keys [content-type outgoing group-chat selected]}]
|
||||
(merge {:padding 12
|
||||
:backgroundColor styles/color-white
|
||||
:android {:border-radius 4}
|
||||
:ios {:border-radius 8}}
|
||||
:border-radius 8}
|
||||
(when (= content-type constants/content-type-command)
|
||||
{:paddingTop 10
|
||||
:paddingBottom 14})))
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
(ns status-im.ios.platform
|
||||
(:require [status-im.i18n :refer [label]]
|
||||
[status-im.utils.core :as utils]
|
||||
[status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
(ns status-im.ios.platform)
|
||||
|
||||
(def fonts
|
||||
{:light {:font-family "SFUIText-Light"}
|
||||
|
@ -12,26 +9,10 @@
|
|||
:toolbar-title {:font-family "SFUIText-Semibold"}
|
||||
:roboto-mono {:font-family "RobotoMono-Medium"}})
|
||||
|
||||
;; Dialogs
|
||||
|
||||
(defn action-sheet-options [options]
|
||||
(let [destructive-opt-index (utils/first-index :destructive? options)
|
||||
cancel-option {:text (label :t/cancel)}
|
||||
options (conj options cancel-option)]
|
||||
(clj->js (merge {:options (mapv :text options)
|
||||
:cancelButtonIndex (dec (count options))}
|
||||
(when destructive-opt-index {:destructiveButtonIndex destructive-opt-index})))))
|
||||
|
||||
(defn show-action-sheet [{:keys [options callback]}]
|
||||
(.showActionSheetWithOptions (.-ActionSheetIOS rn-dependencies/react-native)
|
||||
(action-sheet-options options)
|
||||
callback))
|
||||
|
||||
;; Structure to be exported
|
||||
|
||||
(def platform-specific
|
||||
{:fonts fonts
|
||||
:list-selection-fn show-action-sheet
|
||||
:tabs {:tab-shadows? false}
|
||||
:chats {:action-button? false
|
||||
:new-chat-in-toolbar? true
|
||||
|
|
|
@ -263,6 +263,10 @@
|
|||
:unsigned-transaction-expired "Unsigned transaction expired"
|
||||
:status "Status"
|
||||
:recipient "Recipient"
|
||||
:specify-recipient "Specify recipient..."
|
||||
:recipient-code "Enter recipient address"
|
||||
:enter-contact-code "Enter Contact Code"
|
||||
:recent-recipients "Recent recipients"
|
||||
:to "To"
|
||||
:from "From"
|
||||
:data "Data"
|
||||
|
@ -312,9 +316,10 @@
|
|||
:send-request "Send request"
|
||||
:share "Share"
|
||||
:eth "ETH"
|
||||
:gwei "Gwei"
|
||||
:currency "Currency"
|
||||
:usd-currency "USD"
|
||||
:amount-placeholder "Specify amount"
|
||||
:amount-placeholder "Specify amount..."
|
||||
:transactions "Transactions"
|
||||
:transaction-details "Transaction details"
|
||||
:transaction-failed "Transaction failed"
|
||||
|
@ -342,6 +347,7 @@
|
|||
:not-applicable "Not applicable for unsigned transactions"
|
||||
:send-transaction "Send transaction"
|
||||
:receive-transaction "Receive transaction"
|
||||
:new-transaction "New Transaction"
|
||||
:transaction-history "Transaction History"
|
||||
|
||||
;; Wallet Send
|
||||
|
@ -357,6 +363,7 @@
|
|||
:wallet-transaction-total-fee "Total Fee"
|
||||
:validation-amount-invalid-number "Amount is not a valid number"
|
||||
:validation-amount-is-too-precise "Amount is too precise. The smallest unit you can send is 1 Wei (1x10^-18 ETH)"
|
||||
:scan-qr-code "Scan a QR code with a wallet address"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
(ns status-im.ui.components.action-button.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
||||
(:require [status-im.utils.platform :as p]
|
||||
[status-im.ui.components.styles :refer [color-white
|
||||
color-light-blue-transparent
|
||||
color-light-blue
|
||||
color-light-gray
|
||||
color-black
|
||||
color-gray4]]))
|
||||
(:require [status-im.ui.components.styles :as styles]))
|
||||
|
||||
(defstyle action-button
|
||||
{:padding-left 16
|
||||
|
@ -15,34 +9,34 @@
|
|||
:ios {:height 63}
|
||||
:android {:height 56}})
|
||||
|
||||
(defnstyle action-button-icon-container [cyrcle-color]
|
||||
(defnstyle action-button-icon-container [circle-color]
|
||||
{:border-radius 50
|
||||
:width 40
|
||||
:height 40
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:ios {:background-color (or cyrcle-color color-light-blue-transparent)}})
|
||||
:ios {:background-color (or circle-color styles/color-light-blue-transparent)}})
|
||||
|
||||
(def action-button-label-container
|
||||
{:padding-left 16})
|
||||
|
||||
(defstyle action-button-label
|
||||
{:ios {:color color-light-blue
|
||||
{:ios {:color styles/color-light-blue
|
||||
:letter-spacing -0.2
|
||||
:font-size 17
|
||||
:line-height 20}
|
||||
:android {:color color-black
|
||||
:android {:color styles/color-black
|
||||
:font-size 16}})
|
||||
|
||||
(defstyle actions-list
|
||||
{:background-color color-white
|
||||
{:background-color styles/color-white
|
||||
:android {:padding-top 8
|
||||
:padding-bottom 8}})
|
||||
|
||||
|
||||
(def action-button-label-disabled
|
||||
(merge action-button-label
|
||||
{:color color-gray4}))
|
||||
{:color styles/color-gray4}))
|
||||
|
||||
(defstyle action-button-icon-container-disabled
|
||||
{:border-radius 50
|
||||
|
@ -50,5 +44,5 @@
|
|||
:height 40
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:ios {:background-color color-light-gray}})
|
||||
:ios {:background-color styles/color-light-gray}})
|
||||
|
||||
|
|
|
@ -6,19 +6,19 @@
|
|||
(defn- callback [options]
|
||||
(fn [index]
|
||||
(when (< index (count options))
|
||||
(when-let [handler (:actione (nth options index))]
|
||||
(when-let [handler (:action (nth options index))]
|
||||
(handler)))))
|
||||
|
||||
(defn- options [options]
|
||||
(defn- prepare-options [title message options]
|
||||
(let [destructive-opt-index (utils/first-index :destructive? options)] ;; TODO Can only be a single destructive?
|
||||
(clj->js (merge {:options (conj (mapv :label options) (i18n/label :t/cancel))
|
||||
:cancelButtonIndex (count options)}
|
||||
(when destructive-opt-index
|
||||
{:destructiveButtonIndex destructive-opt-index})))))
|
||||
{:destructiveButtonIndex destructive-opt-index})
|
||||
(when title {:title title})
|
||||
(when message {:message message})))))
|
||||
|
||||
(defn show [{:keys [title message options callback]}]
|
||||
(defn show [{:keys [title message options]}]
|
||||
(.showActionSheetWithOptions (.-ActionSheetIOS rn-dependencies/react-native)
|
||||
(merge (options options)
|
||||
(when title {:title title})
|
||||
(when message {:message message}))
|
||||
callback))
|
||||
(prepare-options title message options)
|
||||
(callback options)))
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
(ns status-im.ui.components.bottom-buttons.styles
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def wrapper
|
||||
{:position :absolute
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(def border
|
||||
{:margin-horizontal 16
|
||||
:border-top-width 1
|
||||
:border-color colors/white-light-transparent})
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between})
|
||||
|
||||
(def container-single
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :center})
|
|
@ -0,0 +1,21 @@
|
|||
(ns status-im.ui.components.bottom-buttons.view
|
||||
(:require [status-im.ui.components.bottom-buttons.styles :as styles]
|
||||
[status-im.ui.components.react :as react]))
|
||||
|
||||
(defn bottom-button
|
||||
([button] (bottom-button nil button))
|
||||
([style button]
|
||||
[react/view styles/wrapper
|
||||
[react/view styles/border]
|
||||
[react/view (merge styles/container-single style)
|
||||
button]]))
|
||||
|
||||
(defn bottom-buttons
|
||||
([left right] (bottom-buttons nil left right))
|
||||
([style left right]
|
||||
[react/view styles/wrapper
|
||||
[react/view styles/border]
|
||||
[react/view (merge styles/container style)
|
||||
left
|
||||
[react/view {:flex 1}]
|
||||
right]]))
|
|
@ -10,13 +10,12 @@
|
|||
|
||||
(def button-container styles/flex)
|
||||
|
||||
(defnstyle button [disabled?]
|
||||
{:flex-direction :row
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:android {:background-color border-color}
|
||||
:ios (when-not disabled?
|
||||
{:background-color border-color})})
|
||||
(def button
|
||||
{:flex-direction :row
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:padding-horizontal 12})
|
||||
|
||||
|
||||
(defn- border [position]
|
||||
(let [radius (if platform/ios? 8 4)]
|
||||
|
@ -39,27 +38,27 @@
|
|||
(merge {:border-color border-color}
|
||||
(border position)))
|
||||
|
||||
(defnstyle button-text [disabled?]
|
||||
(defstyle button-text
|
||||
{:font-weight :normal
|
||||
:color styles/color-white
|
||||
:padding-horizontal 16
|
||||
:android (merge
|
||||
{:font-size 14
|
||||
:padding-vertical 10
|
||||
:letter-spacing 0.5}
|
||||
(when disabled? {:opacity 0.4}))
|
||||
:ios (merge
|
||||
{:font-size 15
|
||||
:padding-vertical 9
|
||||
:letter-spacing -0.2}
|
||||
(when disabled? {:opacity 0.6}))})
|
||||
:android {:font-size 14
|
||||
:padding-vertical 10
|
||||
:letter-spacing 0.5}
|
||||
:ios {:font-size 15
|
||||
:padding-vertical 9
|
||||
:letter-spacing -0.2}})
|
||||
|
||||
(defstyle button-text-disabled
|
||||
{:android {:opacity 0.4}
|
||||
:ios {:opacity 0.6}})
|
||||
|
||||
|
||||
(defstyle button-borders
|
||||
{:android {:border-radius 4}
|
||||
:ios {:border-radius 8
|
||||
;; Border radius is ignored with transparent background unless overflow "hidden" is used
|
||||
;; See https://github.com/facebook/react-native/issues/13760
|
||||
:overflow :hidden}})
|
||||
{:border-radius 8
|
||||
:ios {;; Border radius is ignored with transparent background unless overflow "hidden" is used
|
||||
;; See https://github.com/facebook/react-native/issues/13760
|
||||
:overflow :hidden}})
|
||||
|
||||
(def primary-button
|
||||
(merge
|
||||
|
@ -73,4 +72,4 @@
|
|||
button-borders
|
||||
{:background-color styles/color-blue4-transparent}))
|
||||
|
||||
(def secondary-button-text {:color styles/color-blue4})
|
||||
(def secondary-button-text {:color styles/color-blue4})
|
||||
|
|
|
@ -1,36 +1,33 @@
|
|||
(ns status-im.ui.components.button.view
|
||||
(:require [status-im.ui.components.button.styles :as button.styles]
|
||||
(:require [status-im.ui.components.button.styles :as styles]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn button-text [{:keys [disabled? text-style]} label]
|
||||
[react/text {:style (merge (button.styles/button-text disabled?)
|
||||
text-style)
|
||||
:font (if platform/android? :medium :default)
|
||||
:uppercase? (get-in platform/platform-specific [:uppercase?])}
|
||||
label])
|
||||
|
||||
(defn button [{:keys [on-press style disabled? fit-to-text?] :as props} label]
|
||||
[react/touchable-highlight (merge {:underlay-color button.styles/border-color-high}
|
||||
(defn button [{:keys [on-press style disabled? fit-to-text? text-style] :or {fit-to-text? true}} label icon]
|
||||
[react/touchable-highlight (merge {:underlay-color styles/border-color-high}
|
||||
(when-not fit-to-text?
|
||||
{:style button.styles/button-container})
|
||||
{:style styles/button-container})
|
||||
(when (and on-press (not disabled?))
|
||||
{:on-press on-press}))
|
||||
[react/view {:style (merge (button.styles/button disabled?)
|
||||
[react/view {:style (merge styles/button
|
||||
style)}
|
||||
[button-text props
|
||||
label]]])
|
||||
[react/text {:style (merge styles/button-text
|
||||
text-style
|
||||
(when disabled?
|
||||
{:opacity 0.4}))
|
||||
:font (if platform/android? :medium :default)
|
||||
:uppercase? (get-in platform/platform-specific [:uppercase?])}
|
||||
label]
|
||||
icon]])
|
||||
|
||||
(defn primary-button [{:keys [style text-style] :as m} label]
|
||||
[button (assoc m
|
||||
:fit-to-text? true
|
||||
:style (merge button.styles/primary-button style)
|
||||
:text-style (merge button.styles/primary-button-text text-style))
|
||||
:style (merge styles/primary-button style)
|
||||
:text-style (merge styles/primary-button-text text-style))
|
||||
label])
|
||||
|
||||
(defn secondary-button [{:keys [style text-style] :as m} label]
|
||||
[button (assoc m
|
||||
:fit-to-text? true
|
||||
:style (merge button.styles/secondary-button style)
|
||||
:text-style (merge button.styles/secondary-button-text text-style))
|
||||
:style (merge styles/secondary-button style)
|
||||
:text-style (merge styles/secondary-button-text text-style))
|
||||
label])
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
(:require [goog.object :as object]
|
||||
[reagent.core :as r]
|
||||
[clojure.walk :refer [keywordize-keys]]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.react-native.js-dependencies :as rn-dependecies]))
|
||||
|
||||
(def default-camera (.-default rn-dependecies/camera))
|
||||
|
@ -19,15 +18,13 @@
|
|||
(defn set-torch [state]
|
||||
(set! (.-torchMode default-camera) (get torch-modes state)))
|
||||
|
||||
(defn request-access [callback]
|
||||
(if platform/android?
|
||||
(callback true)
|
||||
(-> (.checkVideoAuthorizationStatus default-camera)
|
||||
(.then #(callback %))
|
||||
(.catch #(callback false)))))
|
||||
(defn request-access-ios [then else]
|
||||
(-> (.checkVideoAuthorizationStatus default-camera)
|
||||
(.then then)
|
||||
(.catch else)))
|
||||
|
||||
(defn camera [props]
|
||||
(r/create-element default-camera (clj->js (merge {:inverted true} props))))
|
||||
|
||||
(defn get-qr-code-data [code]
|
||||
(.-data code))
|
||||
(.-data code))
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
(ns status-im.ui.components.carousel.carousel
|
||||
(:require [reagent.impl.component :as rc]
|
||||
[status-im.ui.components.react :refer [view
|
||||
scroll-view
|
||||
touchable-without-feedback
|
||||
text]]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.carousel.styles :as st]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ui.components.react :as r]
|
||||
[status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
|
||||
|
||||
|
@ -160,15 +156,15 @@
|
|||
gap (get-gap data)
|
||||
count (get-count data)]
|
||||
(doall (map-indexed (fn [index child]
|
||||
(let [page-index index
|
||||
touchable-data {:key index
|
||||
:onPress #(go-to-page component page-index)}]
|
||||
[touchable-without-feedback touchable-data
|
||||
[view {:style [(st/page index count page-width gap)
|
||||
page-style]
|
||||
:onLayout #(log/debug "view onLayout" %)}
|
||||
(let [page-index index
|
||||
touchable-data {:key index
|
||||
:onPress #(go-to-page component page-index)}]
|
||||
[react/touchable-without-feedback touchable-data
|
||||
[react/view {:style [(st/page index count page-width gap)
|
||||
page-style]
|
||||
:onLayout #(log/debug "view onLayout" %)}
|
||||
|
||||
child]])) children))))
|
||||
child]])) children))))
|
||||
|
||||
(defn reagent-render [data children]
|
||||
(let [starting-position (atom 0)
|
||||
|
@ -176,18 +172,18 @@
|
|||
state (reagent.core/state component)
|
||||
gap (get-gap state)]
|
||||
(log/debug "reagent-render: " data state)
|
||||
[view {:style st/scroll-view-container}
|
||||
[scroll-view {:contentContainerStyle (st/content-container gap)
|
||||
:automaticallyAdjustContentInsets false
|
||||
:bounces false
|
||||
:decelerationRate 0.9
|
||||
:horizontal true
|
||||
:onLayout #(on-layout-change % component)
|
||||
:scrollEnabled (not (get state :scrolling?))
|
||||
:onScrollBeginDrag #(reset! starting-position (get-current-position %))
|
||||
:onScrollEndDrag #(on-scroll-end % component @starting-position)
|
||||
:showsHorizontalScrollIndicator false
|
||||
:ref #(set! (.-scrollView component) %)}
|
||||
[react/view {:style st/scroll-view-container}
|
||||
[react/scroll-view {:contentContainerStyle (st/content-container gap)
|
||||
:automaticallyAdjustContentInsets false
|
||||
:bounces false
|
||||
:decelerationRate 0.9
|
||||
:horizontal true
|
||||
:onLayout #(on-layout-change % component)
|
||||
:scrollEnabled (not (get state :scrolling?))
|
||||
:onScrollBeginDrag #(reset! starting-position (get-current-position %))
|
||||
:onScrollEndDrag #(on-scroll-end % component @starting-position)
|
||||
:showsHorizontalScrollIndicator false
|
||||
:ref #(set! (.-scrollView component) %)}
|
||||
(get-pages component state children)]]))
|
||||
|
||||
(defn carousel [_ _]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
(ns status-im.ui.components.chat-icon.screen
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.chat-icon.styles :as styles]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[clojure.string :as string]
|
||||
[status-im.i18n :as i18n]))
|
||||
[status-im.react-native.resources :as resources]))
|
||||
|
||||
(defn default-chat-icon [name styles]
|
||||
[react/view (:default-chat-icon styles)
|
||||
|
@ -64,7 +64,7 @@
|
|||
:default-chat-icon (styles/default-chat-icon-chat-list color)
|
||||
:default-chat-icon-text styles/default-chat-icon-text}])
|
||||
|
||||
(defn chat-icon-view-action [chat-id group-chat name _color online]
|
||||
(defn chat-icon-view-action [chat-id group-chat name online]
|
||||
^{:key chat-id}
|
||||
[chat-icon-view chat-id group-chat name online
|
||||
{:container styles/container-chat-list
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
(def white "#ffffff")
|
||||
(def white-light-transparent "rgba(255, 255, 255, 0.1)") ;; Used as icon background color for a dark foreground
|
||||
(def white-transparent "rgba(255, 255, 255, 0.2)") ;; Used as icon color on dark background
|
||||
(def blue "#4360df") ;; Used as main wallet color
|
||||
(def white-lighter-transparent "rgba(255, 255, 255, 0.6)") ;; Used for input placeholder color
|
||||
(def black "#000000") ;; Used as the default text color
|
||||
(def gray "#939ba1") ;; Used as a background for a light foreground and for text descriptions
|
||||
(def gray "#939ba1") ;; Used as a background for a light foreground and as section header and secondary text color
|
||||
(def gray-light "#d9dae1") ;; Used as divider color
|
||||
(def gray-lighter "#eef2f5") ;; Used as a background or shadow
|
||||
(def blue "#4360df") ;; Used as main wallet color
|
||||
(def red "#ff2d55") ;; Used to highlight errors or "dangerous" actions
|
||||
(def light-gray "#eef2f5") ;; Used as a background or shadow
|
||||
(def text-light-gray "#212121") ;; Used for labels (home items)
|
||||
(def text-light-gray "#212121") ;; Used for labels (home items)
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
(ns status-im.ui.components.context-menu
|
||||
(:require [goog.object :as object]
|
||||
(:require [status-im.react-native.js-dependencies :as rn-dependencies]
|
||||
[status-im.ui.components.action-sheet :as action-sheet]
|
||||
[status-im.ui.components.react :as react]
|
||||
[goog.object :as object]
|
||||
[reagent.core :as r]
|
||||
[status-im.ui.components.styles :as st]
|
||||
[status-im.utils.platform :refer [platform-specific ios?]]
|
||||
[status-im.ui.components.react :as rn]
|
||||
[status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn- get-property [name]
|
||||
(object/get rn-dependencies/popup-menu name))
|
||||
|
||||
(defn- get-class [name]
|
||||
(rn/adapt-class (get-property name)))
|
||||
(react/adapt-class (get-property name)))
|
||||
|
||||
(def menu (get-class "Menu"))
|
||||
(def menu-context (get-class "MenuContext"))
|
||||
|
@ -18,7 +19,7 @@
|
|||
(def menu-options (get-class "MenuOptions"))
|
||||
(def menu-option (get-class "MenuOption"))
|
||||
|
||||
(defn context-menu-options [custom-styles]
|
||||
(defn- context-menu-options [custom-styles]
|
||||
{:customStyles {:optionsContainer
|
||||
(merge {:elevation 2
|
||||
:margin-top 0
|
||||
|
@ -33,39 +34,22 @@
|
|||
:height 48}
|
||||
(:optionWrapper custom-styles))}})
|
||||
|
||||
(defn context-menu-text [destructive?]
|
||||
(defn- context-menu-text [destructive?]
|
||||
{:font-size 15
|
||||
:line-height 20
|
||||
:color (if destructive? st/color-light-red st/text1-color)})
|
||||
|
||||
(def list-selection-fn (:list-selection-fn platform-specific))
|
||||
|
||||
(defn open-ios-menu [title options]
|
||||
(list-selection-fn {:options options
|
||||
:title title
|
||||
:callback (fn [index]
|
||||
(when (< index (count options))
|
||||
(when-let [handler (:value (nth options index))]
|
||||
(handler))))})
|
||||
nil)
|
||||
|
||||
(defn context-menu [trigger options & custom-styles trigger-style]
|
||||
(if ios?
|
||||
[rn/touchable-highlight {:style trigger-style
|
||||
:on-press #(open-ios-menu nil options)}
|
||||
[rn/view
|
||||
(if platform/ios?
|
||||
[react/touchable-highlight {:style trigger-style
|
||||
:on-press #(action-sheet/show options)}
|
||||
[react/view
|
||||
trigger]]
|
||||
[menu {:onSelect #(when % (do (%) nil))}
|
||||
[menu-trigger {:style trigger-style} trigger]
|
||||
[menu-options (context-menu-options custom-styles)
|
||||
(for [{:keys [style value destructive?] :as option} options]
|
||||
(for [{:keys [style action destructive?] :as option} options]
|
||||
^{:key option}
|
||||
[menu-option {:value value}
|
||||
[rn/text {:style (merge (context-menu-text destructive?) style)}
|
||||
(:text option)]])]]))
|
||||
|
||||
(defn modal-menu [trigger style title options]
|
||||
[rn/touchable-highlight {:style style
|
||||
:on-press #(open-ios-menu title options)}
|
||||
[rn/view
|
||||
trigger]])
|
||||
[menu-option {:value action}
|
||||
[react/text {:style (merge (context-menu-text destructive?) style)}
|
||||
(:label option)]])]]))
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
(ns status-im.ui.components.dialog
|
||||
(:require [status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
|
||||
(defn- callback [options]
|
||||
(fn [index]
|
||||
(when (< index (count options))
|
||||
(when-let [handler (:action (nth options index))]
|
||||
(handler)))))
|
||||
|
||||
(defn- show [{:keys [title options]}]
|
||||
(let [dialog (new rn-dependencies/dialogs)]
|
||||
(.set dialog (clj->js {:title title
|
||||
:items (mapv :label options)
|
||||
:itemsCallback (callback options)}))
|
||||
(.show dialog)))
|
|
@ -1,7 +1,6 @@
|
|||
(ns status-im.ui.components.list.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]])
|
||||
(:require [status-im.ui.components.styles :as styles]
|
||||
[status-im.utils.platform :as platform]))
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def item
|
||||
{:flex-direction :row
|
||||
|
@ -19,25 +18,27 @@
|
|||
:justify-content :center})
|
||||
|
||||
(def primary-text-base
|
||||
{:font-size 17
|
||||
:color styles/color-black})
|
||||
{:font-size 16
|
||||
:color colors/black})
|
||||
|
||||
(def primary-text
|
||||
(merge primary-text-base
|
||||
{:padding-top (if platform/ios? 13 14)}))
|
||||
{:padding-top 12}))
|
||||
|
||||
(def primary-text-only
|
||||
(merge primary-text-base
|
||||
{:padding-vertical 16}))
|
||||
|
||||
(def secondary-text
|
||||
{:font-size 16
|
||||
:color styles/color-gray4
|
||||
{:font-size 14
|
||||
:color colors/gray
|
||||
:padding-top 4})
|
||||
|
||||
(def image-size 40)
|
||||
|
||||
(def item-image
|
||||
{:width 40
|
||||
:height 40})
|
||||
{:width image-size
|
||||
:height image-size})
|
||||
|
||||
(def icon-size 24)
|
||||
(def icon-wrapper-size (+ icon-size (* 2 8)))
|
||||
|
@ -61,9 +62,9 @@
|
|||
:margin-vertical vertical-margin})
|
||||
|
||||
(def content-item-wrapper
|
||||
{:flex 1
|
||||
:justify-content :center
|
||||
:margin-left horizontal-margin})
|
||||
{:flex 1
|
||||
:justify-content :center
|
||||
:margin-horizontal horizontal-margin})
|
||||
|
||||
(def right-item-wrapper
|
||||
{:justify-content :center
|
||||
|
@ -71,16 +72,15 @@
|
|||
|
||||
(def base-separator
|
||||
{:height 1
|
||||
:background-color styles/color-gray5
|
||||
:opacity 0.5})
|
||||
:background-color colors/gray-light})
|
||||
|
||||
(def separator
|
||||
(merge
|
||||
base-separator
|
||||
{:margin-left 70}))
|
||||
{:margin-left 70}))
|
||||
|
||||
(defstyle list-header-footer-spacing
|
||||
{:android {:background-color styles/color-white
|
||||
{:android {:background-color colors/white
|
||||
:height 8}})
|
||||
|
||||
(defstyle section-separator
|
||||
|
@ -90,7 +90,7 @@
|
|||
|
||||
(defstyle section-header
|
||||
{:font-size 14
|
||||
:color styles/color-gray4
|
||||
:color colors/gray
|
||||
:margin-left 16
|
||||
:android {:margin-top 11
|
||||
:margin-bottom 3}
|
||||
|
|
|
@ -31,20 +31,21 @@
|
|||
|
||||
(defn item
|
||||
([content] (item nil content))
|
||||
([left-action content] (item left-action content nil))
|
||||
([left-action content right-action]
|
||||
([left content] (item left content nil))
|
||||
([left content right]
|
||||
[react/view {:style styles/item}
|
||||
[react/view {:style styles/left-item-wrapper}
|
||||
left-action]
|
||||
left]
|
||||
[react/view {:style styles/content-item-wrapper}
|
||||
content]
|
||||
(when right-action
|
||||
(when right
|
||||
[react/view {:style styles/right-item-wrapper}
|
||||
right-action])]))
|
||||
right])]))
|
||||
|
||||
(defn touchable-item [handler item]
|
||||
[react/touchable-highlight {:on-press handler}
|
||||
item])
|
||||
[react/view
|
||||
item]])
|
||||
|
||||
(defn item-icon
|
||||
[{:keys [icon style icon-opts]}]
|
||||
|
@ -84,7 +85,7 @@
|
|||
(def item-icon-forward
|
||||
[item-icon {:style styles/item-icon
|
||||
:icon :icons/forward
|
||||
:icon-opts {:color colors/white-transparent}}])
|
||||
:icon-opts {:color colors/white-light-transparent}}])
|
||||
|
||||
(defn- wrap-render-fn [f]
|
||||
(fn [data]
|
||||
|
|
|
@ -1,41 +1,36 @@
|
|||
(ns status-im.ui.components.list-selection
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :refer [copy-to-clipboard
|
||||
sharing
|
||||
linking]]
|
||||
[status-im.utils.platform :refer [platform-specific ios?]]
|
||||
[status-im.i18n :refer [label]]))
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.action-sheet :as action-sheet]
|
||||
[status-im.ui.components.dialog :as dialog]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn open-share [content]
|
||||
(defn- open-share [content]
|
||||
(when (or (:message content)
|
||||
(:url content))
|
||||
(.share sharing (clj->js content))))
|
||||
(.share react/sharing (clj->js content))))
|
||||
|
||||
(defn share-options [text]
|
||||
[{:text (label :t/sharing-copy-to-clipboard)
|
||||
:value #(copy-to-clipboard text)}
|
||||
{:text (label :t/sharing-share)
|
||||
:value #(open-share {:message text})}])
|
||||
[{:label (i18n/label :t/sharing-copy-to-clipboard)
|
||||
:action #(react/copy-to-clipboard text)}
|
||||
{:label (i18n/label :t/sharing-share)
|
||||
:action #(open-share {:message text})}])
|
||||
|
||||
(defn show [options]
|
||||
(if platform/ios?
|
||||
(action-sheet/show options)
|
||||
(dialog/show options)))
|
||||
|
||||
(defn share [text dialog-title]
|
||||
(let [list-selection-fn (:list-selection-fn platform-specific)]
|
||||
(list-selection-fn {:title dialog-title
|
||||
:options (share-options text)
|
||||
:callback (fn [index]
|
||||
(case index
|
||||
0 (copy-to-clipboard text)
|
||||
1 (open-share {:message text})
|
||||
:default))
|
||||
:cancel-text (label :t/sharing-cancel)})))
|
||||
(show {:title dialog-title
|
||||
:options (share-options text)
|
||||
:cancel-text (i18n/label :t/sharing-cancel)}))
|
||||
|
||||
(defn browse [link]
|
||||
(let [list-selection-fn (:list-selection-fn platform-specific)]
|
||||
(list-selection-fn {:title (label :t/browsing-title)
|
||||
:options [{:text (label :t/browsing-open-in-browser)}
|
||||
{:text (label :t/browsing-open-in-web-browser)}]
|
||||
:callback (fn [index]
|
||||
(case index
|
||||
0 (re-frame/dispatch [:open-browser {:url link}])
|
||||
1 (.openURL linking link)
|
||||
:default))
|
||||
:cancel-text (label :t/browsing-cancel)})))
|
||||
(show {:title (i18n/label :t/browsing-title)
|
||||
:options [{:text (i18n/label :t/browsing-open-in-browser)
|
||||
:action (re-frame/dispatch [:open-browser {:url link}])}
|
||||
{:text (i18n/label :t/browsing-open-in-web-browser)
|
||||
:action (.openURL react/linking link)}]
|
||||
:cancel-text (i18n/label :t/browsing-cancel)}))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.ui.components.permissions
|
||||
(:require [status-im.utils.platform :as platform]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ui.components.camera :as camera]
|
||||
[status-im.react-native.js-dependencies :as rn-dependencies]))
|
||||
|
||||
(def permissions-class (.-PermissionsAndroid rn-dependencies/react-native))
|
||||
|
@ -27,4 +28,6 @@
|
|||
(else-fn)))
|
||||
(.catch else-fn))))
|
||||
|
||||
(then)))
|
||||
(if ((set permissions) :camera)
|
||||
(camera/request-access-ios then else)
|
||||
(then))))
|
||||
|
|
|
@ -66,13 +66,13 @@
|
|||
:justify-content :center})
|
||||
|
||||
(def qr-code
|
||||
{:background-color colors/light-gray
|
||||
{:background-color colors/gray-lighter
|
||||
:flex-grow 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def footer
|
||||
{:background-color colors/light-gray
|
||||
{:background-color colors/gray-lighter
|
||||
:flex-direction :row
|
||||
:justify-content :center
|
||||
:padding-bottom 50})
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
(ns status-im.ui.components.status-bar.styles
|
||||
(:require [status-im.ui.components.styles :as styles]
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.utils.platform :as platform])
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle]]))
|
||||
|
||||
(def elevation 2)
|
||||
|
||||
(defn- create-status-bar-style [{:keys [background-color bar-style translucent?]
|
||||
:or {bar-style "light-content"}}]
|
||||
{:background-color (if translucent? "transparent" background-color)
|
||||
|
@ -17,13 +20,13 @@
|
|||
|
||||
;; :main
|
||||
(defstyle status-bar-main
|
||||
{:ios (create-status-bar-style {:background-color styles/color-white
|
||||
{:ios (create-status-bar-style {:background-color colors/white
|
||||
:bar-style "default"})
|
||||
:android (create-status-bar-style {:translucent? true
|
||||
:bar-style "dark-content"})})
|
||||
|
||||
(def view-main
|
||||
(create-view-style {:background-color styles/color-white}))
|
||||
(create-view-style {:background-color colors/white}))
|
||||
|
||||
;; :transparent
|
||||
(defstyle status-bar-transparent
|
||||
|
@ -45,25 +48,25 @@
|
|||
|
||||
;; :modal-white
|
||||
(defstyle status-bar-modal-white
|
||||
{:ios (create-status-bar-style {:background-color styles/color-white
|
||||
{:ios (create-status-bar-style {:background-color colors/white
|
||||
:bar-style "default"})
|
||||
:android (create-status-bar-style {:background-color styles/color-black
|
||||
:bar-style "light-content"})})
|
||||
|
||||
(defstyle view-modal-white
|
||||
{:ios (create-view-style {:background-color styles/color-white})
|
||||
{:ios (create-view-style {:background-color colors/white})
|
||||
:android (create-view-style {:background-color styles/color-black
|
||||
:height 0})})
|
||||
|
||||
;; :modal-wallet
|
||||
(defstyle status-bar-modal-wallet
|
||||
{:ios (create-status-bar-style {:background-color styles/color-blue4})
|
||||
:android (create-status-bar-style {:background-color styles/color-black})})
|
||||
(def status-bar-modal-wallet
|
||||
(create-status-bar-style {:background-color colors/blue}))
|
||||
|
||||
(defstyle view-model-wallet
|
||||
{:ios (create-view-style {:background-color styles/color-blue4})
|
||||
:android (create-view-style {:background-color styles/color-black
|
||||
:height 0})})
|
||||
(defstyle view-modal-wallet
|
||||
{:ios (create-view-style {:background-color colors/blue})
|
||||
:android (create-view-style {:background-color colors/blue
|
||||
:height 0
|
||||
:elevation elevation})})
|
||||
|
||||
;; :transaction
|
||||
(defstyle status-bar-transaction
|
||||
|
@ -75,21 +78,32 @@
|
|||
:android (create-view-style {:background-color styles/color-dark-blue-2
|
||||
:height 0})})
|
||||
|
||||
;; :wallet
|
||||
(defstyle status-bar-wallet
|
||||
{:ios (create-status-bar-style {:background-color styles/color-blue4})
|
||||
;; TODO(jeluard) Fix status-bar mess by removing useless view and introducing 2dn level tab-bar
|
||||
|
||||
;; :wallet HOME
|
||||
(defstyle status-bar-wallet-tab
|
||||
{:ios (create-status-bar-style {:background-color colors/blue})
|
||||
:android (create-status-bar-style {:translucent? true})})
|
||||
|
||||
(def view-wallet
|
||||
(def view-wallet-tab
|
||||
(create-view-style {:background-color styles/color-blue4}))
|
||||
|
||||
;; :wallet
|
||||
(defstyle status-bar-wallet
|
||||
{:ios (create-status-bar-style {:background-color colors/blue})
|
||||
:android (create-status-bar-style {:translucent? true})})
|
||||
|
||||
(def view-wallet
|
||||
(create-view-style {:background-color styles/color-blue4
|
||||
:elevation elevation}))
|
||||
|
||||
;; :default
|
||||
(defstyle status-bar-default
|
||||
{:ios (create-status-bar-style {:background-color styles/color-white
|
||||
{:ios (create-status-bar-style {:background-color colors/white
|
||||
:bar-style "default"})
|
||||
:android (create-status-bar-style {:translucent? true
|
||||
:bar-style "dark-content"})})
|
||||
|
||||
(defstyle view-default
|
||||
(create-view-style {:background-color styles/color-white
|
||||
:elevation 2}))
|
||||
(create-view-style {:background-color colors/white
|
||||
:elevation elevation}))
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
:transparent [styles/status-bar-transparent styles/view-transparent]
|
||||
:modal [styles/status-bar-modal styles/view-modal]
|
||||
:modal-white [styles/status-bar-modal-white styles/view-modal-white]
|
||||
:modal-wallet [styles/status-bar-modal-wallet styles/view-model-wallet]
|
||||
:modal-wallet [styles/status-bar-modal-wallet styles/view-modal-wallet]
|
||||
:transaction [styles/status-bar-transaction styles/view-transaction]
|
||||
:wallet [styles/status-bar-wallet styles/view-wallet]
|
||||
:wallet-tab [styles/status-bar-wallet-tab styles/view-wallet-tab]
|
||||
[styles/status-bar-default styles/view-default])]
|
||||
[react/view
|
||||
[react/status-bar status-bar-style]
|
||||
|
|
|
@ -160,6 +160,8 @@
|
|||
{:background-color color-white
|
||||
:flex 1})
|
||||
|
||||
(def border-radius 8)
|
||||
|
||||
;; TODO(goranjovic): replace all platform conditional uppercase styling with a reference to this var
|
||||
(def uppercase?
|
||||
(condp = platform/platform
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
(ns status-im.ui.components.sync-state.gradient
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.ui.components.react :refer [view
|
||||
text
|
||||
animated-view
|
||||
linear-gradient
|
||||
get-dimensions]]
|
||||
[status-im.ui.components.sync-state.styles :as st]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def gradient-animation-duration 700)
|
||||
(def synced-disappear-delay 2500)
|
||||
(def gradient-width 250)
|
||||
(def in-progress-animation-delay 1500)
|
||||
|
||||
(def window-width (:width (get-dimensions "window")))
|
||||
|
||||
(declare start-gradient-reverse-animation)
|
||||
|
||||
(defn- start-gradient-animation [{:keys [gradient-position sync-state] :as context}]
|
||||
(when (= @sync-state :in-progress)
|
||||
(anim/start
|
||||
(anim/timing gradient-position
|
||||
{:toValue (- window-width (/ gradient-width 3))
|
||||
:duration gradient-animation-duration})
|
||||
(fn [_]
|
||||
(start-gradient-reverse-animation context)))))
|
||||
|
||||
(defn- start-gradient-reverse-animation [{:keys [gradient-position sync-state] :as context}]
|
||||
(when (= @sync-state :in-progress)
|
||||
(anim/start
|
||||
(anim/timing gradient-position
|
||||
{:toValue (- 0 (* 2 (/ gradient-width 3)))
|
||||
:duration gradient-animation-duration})
|
||||
(fn [_]
|
||||
(start-gradient-animation context)))))
|
||||
|
||||
(defn- start-synced-animation [{:keys [sync-state-opacity in-progress-opacity synced-opacity]}]
|
||||
(anim/start
|
||||
(anim/timing in-progress-opacity {:toValue 0.0
|
||||
:duration 250}))
|
||||
(anim/start
|
||||
(anim/timing synced-opacity {:toValue 1.0
|
||||
:duration 250})
|
||||
(fn [_]
|
||||
(anim/start
|
||||
(anim/timing sync-state-opacity {:toValue 0.0
|
||||
:duration 250
|
||||
:delay synced-disappear-delay})
|
||||
(fn [_]
|
||||
(dispatch [:set :sync-state :done]))))))
|
||||
|
||||
(defn start-in-progress-animation [component]
|
||||
(r/set-state component
|
||||
{:pending? true
|
||||
:animation (js/setTimeout
|
||||
(fn []
|
||||
(dispatch [:set :sync-state :in-progress])
|
||||
(r/set-state component {:pending? false}))
|
||||
in-progress-animation-delay)}))
|
||||
|
||||
(defn start-offline-animation [{:keys [sync-state-opacity]}]
|
||||
(anim/start
|
||||
(anim/timing sync-state-opacity {:toValue 0.0
|
||||
:duration 250})))
|
||||
|
||||
(defn clear-pending-animation [component]
|
||||
(let [{:keys [pending? animation]} (r/state component)]
|
||||
(when pending?
|
||||
(r/set-state component {:pending? false})
|
||||
(js/clearTimeout animation))))
|
||||
|
||||
|
||||
(defn sync-state-gradient-view []
|
||||
(let [sync-state (subscribe [:sync-state])
|
||||
gradient-position (anim/create-value 0)
|
||||
sync-state-opacity (anim/create-value 0.0)
|
||||
in-progress-opacity (anim/create-value 0.0)
|
||||
synced-opacity (anim/create-value 0.0)
|
||||
|
||||
context {:sync-state sync-state
|
||||
:gradient-position gradient-position
|
||||
|
||||
:sync-state-opacity sync-state-opacity
|
||||
:in-progress-opacity in-progress-opacity
|
||||
:synced-opacity synced-opacity}
|
||||
on-update (fn [component _]
|
||||
(case @sync-state
|
||||
:pending (start-in-progress-animation component)
|
||||
:in-progress (do
|
||||
(anim/set-value gradient-position 0)
|
||||
(anim/set-value sync-state-opacity 1)
|
||||
(anim/set-value in-progress-opacity 1)
|
||||
(anim/set-value synced-opacity 0)
|
||||
(start-gradient-animation context))
|
||||
:synced (start-synced-animation context)
|
||||
:done (clear-pending-animation component)
|
||||
:offline (do (clear-pending-animation component)
|
||||
(start-offline-animation context))
|
||||
(log/debug "Sync state:" @sync-state)))]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:display-name "sync-state-gradient-view"
|
||||
:reagent-render
|
||||
(fn []
|
||||
[view st/sync-style-gradient
|
||||
[animated-view {:style (st/loading-wrapper sync-state-opacity)}
|
||||
[animated-view {:style (st/gradient-wrapper in-progress-opacity gradient-position)}
|
||||
[linear-gradient {:colors ["#89b1fe" "#8b5fe4" "#8b5fe4" "#89b1fe"]
|
||||
:start {:x 0 :y 1}
|
||||
:end {:x 1 :y 1}
|
||||
:locations [0 0.3 0.7 1]
|
||||
:style (st/gradient gradient-width)}]]
|
||||
(when (not= @sync-state :in-progress)
|
||||
[animated-view {:style (st/synced-wrapper synced-opacity window-width)}])]])})))
|
|
@ -1,31 +1,5 @@
|
|||
(ns status-im.ui.components.sync-state.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]))
|
||||
|
||||
(def sync-style-gradient
|
||||
{:position :relative
|
||||
:height 0
|
||||
:top -2})
|
||||
|
||||
(defn loading-wrapper [opacity]
|
||||
{:background-color "#89b1fe"
|
||||
:opacity opacity
|
||||
:height 2})
|
||||
|
||||
(defn gradient-wrapper [in-progress-opacity position]
|
||||
{:position :absolute
|
||||
:left position
|
||||
:opacity in-progress-opacity})
|
||||
|
||||
(defn gradient [width]
|
||||
{:width width
|
||||
:height 2})
|
||||
|
||||
(defn synced-wrapper [opacity window-width]
|
||||
{:opacity opacity
|
||||
:position :absolute
|
||||
:width window-width
|
||||
:background-color "#5fc48d"
|
||||
:height 2})
|
||||
(:require-macros [status-im.utils.styles :refer [defnstyle]]))
|
||||
|
||||
(defnstyle offline-wrapper [top opacity window-width pending?]
|
||||
{:ios {:z-index 0}
|
||||
|
|
|
@ -1,49 +1,51 @@
|
|||
(ns status-im.ui.components.toolbar.view
|
||||
(:require [reagent.core :as r]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.ui.components.react :as rn]
|
||||
[status-im.ui.components.sync-state.gradient :as sync-state-gradient-view]
|
||||
[status-im.ui.components.styles :as st]
|
||||
[status-im.ui.components.context-menu :as context-menu]
|
||||
[status-im.ui.components.toolbar.actions :as act]
|
||||
[status-im.ui.components.toolbar.styles :as tst]
|
||||
[status-im.ui.components.icons.vector-icons :as vi]
|
||||
[status-im.utils.platform :as platform]))
|
||||
(:require [reagent.core :as reagent]
|
||||
[re-frame.core :as re-frame]
|
||||
[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.react :as react]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.styles :as styles]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.utils.utils :as utils]))
|
||||
|
||||
;; Navigation item
|
||||
|
||||
(defn nav-item
|
||||
[{:keys [handler accessibility-label style] :or {handler #(rf/dispatch [:navigate-back])}} item]
|
||||
[rn/touchable-highlight
|
||||
[{:keys [handler accessibility-label style] :or {handler #(re-frame/dispatch [:navigate-back])}} item]
|
||||
[react/touchable-highlight
|
||||
(merge {:on-press handler}
|
||||
(when accessibility-label
|
||||
{:accessibility-label accessibility-label}))
|
||||
[rn/view {:style style}
|
||||
[react/view {:style style}
|
||||
item]])
|
||||
|
||||
(defn nav-button
|
||||
[{:keys [icon icon-opts] :as props}]
|
||||
[nav-item (merge {:style tst/nav-item-button} props)
|
||||
[vi/icon icon icon-opts]])
|
||||
[nav-item (merge {:style styles/nav-item-button} props)
|
||||
[vector-icons/icon icon icon-opts]])
|
||||
|
||||
(defn nav-text
|
||||
([text] (nav-text text nil))
|
||||
([text handler] (nav-text nil text handler))
|
||||
([props text] (nav-text props text nil))
|
||||
([props text handler]
|
||||
[rn/text (merge {:style (merge tst/item tst/item-text) :on-press (or handler #(rf/dispatch [:navigate-back]))})
|
||||
[react/text (utils/deep-merge {:style (merge styles/item styles/item-text) :on-press (or handler #(re-frame/dispatch [:navigate-back]))}
|
||||
props)
|
||||
text]))
|
||||
|
||||
(defn nav-clear-text
|
||||
([text] (nav-clear-text text nil))
|
||||
([text handler]
|
||||
(nav-text tst/item-text-white-background text handler)))
|
||||
(nav-text styles/item-text-white-background text handler)))
|
||||
|
||||
(def default-nav-back [nav-button act/default-back])
|
||||
(def default-nav-back [nav-button actions/default-back])
|
||||
|
||||
;; Content
|
||||
|
||||
(defn content-wrapper [content]
|
||||
[rn/view {:style tst/toolbar-container}
|
||||
[react/view {:style styles/toolbar-container}
|
||||
content])
|
||||
|
||||
(defn content-title
|
||||
|
@ -51,39 +53,37 @@
|
|||
([title-style title]
|
||||
(content-title title-style title nil nil))
|
||||
([title-style title subtitle-style subtitle]
|
||||
[rn/view {:style tst/toolbar-title-container}
|
||||
[rn/text {:style (merge tst/toolbar-title-text title-style)
|
||||
:font :toolbar-title}
|
||||
[react/view {:style styles/toolbar-title-container}
|
||||
[react/text {:style (merge styles/toolbar-title-text title-style)
|
||||
:font :toolbar-title}
|
||||
title]
|
||||
(when subtitle [rn/text {:style subtitle-style} subtitle])]))
|
||||
(when subtitle
|
||||
[react/text {:style subtitle-style}
|
||||
subtitle])]))
|
||||
|
||||
;; Actions
|
||||
|
||||
(defn text-action [{:keys [style handler disabled?]} title]
|
||||
[rn/text {:style (merge tst/item tst/item-text style
|
||||
(when disabled? tst/toolbar-text-action-disabled))
|
||||
:on-press (when-not disabled? handler)}
|
||||
[react/text {:style (merge styles/item styles/item-text style
|
||||
(when disabled? styles/toolbar-text-action-disabled))
|
||||
:on-press (when-not disabled? handler)}
|
||||
title])
|
||||
|
||||
(def blank-action [rn/view {:style (merge tst/item tst/toolbar-action)}])
|
||||
|
||||
(defn- option-actions [icon icon-opts options]
|
||||
[context-menu/context-menu
|
||||
[rn/view {:style tst/toolbar-action}
|
||||
[vi/icon icon icon-opts]]
|
||||
options
|
||||
nil
|
||||
tst/item])
|
||||
(def blank-action [react/view {:style (merge styles/item styles/toolbar-action)}])
|
||||
|
||||
(defn- icon-action [icon {:keys [overlay-style] :as icon-opts} handler]
|
||||
[rn/touchable-highlight {:on-press handler}
|
||||
[rn/view {:style (merge tst/item tst/toolbar-action)}
|
||||
[react/touchable-highlight {:on-press handler}
|
||||
[react/view {:style (merge styles/item styles/toolbar-action)}
|
||||
(when overlay-style
|
||||
[rn/view overlay-style])
|
||||
[vi/icon icon icon-opts]]])
|
||||
[react/view overlay-style])
|
||||
[vector-icons/icon icon icon-opts]]])
|
||||
|
||||
(defn- option-actions [icon icon-opts options]
|
||||
[icon-action icon icon-opts
|
||||
#(list-selection/show {:options options})])
|
||||
|
||||
(defn actions [v]
|
||||
[rn/view {:style tst/toolbar-actions}
|
||||
[react/view {:style styles/toolbar-actions}
|
||||
(for [{:keys [image icon icon-opts options handler]} v]
|
||||
(with-meta
|
||||
(cond (= image :blank)
|
||||
|
@ -98,72 +98,72 @@
|
|||
|
||||
(defn toolbar
|
||||
([props nav-item content-item] (toolbar props nav-item content-item [actions [{:image :blank}]]))
|
||||
([{:keys [background-color style flat? show-sync-bar?]}
|
||||
([{:keys [background-color style flat?]}
|
||||
nav-item
|
||||
content-item
|
||||
action-items]
|
||||
;; TODO remove extra view wen we remove sync-state-gradient
|
||||
[rn/view
|
||||
[rn/view {:style (merge (tst/toolbar background-color flat?) style)}
|
||||
;; On iOS title must be centered. Current solution is a workaround and eventually this will be sorted out using flex
|
||||
(when platform/ios?
|
||||
[rn/view tst/ios-content-item
|
||||
content-item])
|
||||
(when nav-item
|
||||
[rn/view {:style (tst/toolbar-nav-actions-container 0)}
|
||||
nav-item])
|
||||
(if platform/ios?
|
||||
[rn/view st/flex]
|
||||
content-item)
|
||||
action-items]
|
||||
(when show-sync-bar? [sync-state-gradient-view/sync-state-gradient-view])]))
|
||||
[react/view {:style (merge (styles/toolbar background-color flat?) style)}
|
||||
;; On iOS title must be centered. Current solution is a workaround and eventually this will be sorted out using flex
|
||||
(when platform/ios?
|
||||
[react/view styles/ios-content-item
|
||||
content-item])
|
||||
(when nav-item
|
||||
[react/view {:style (styles/toolbar-nav-actions-container 0)}
|
||||
nav-item])
|
||||
(if platform/ios?
|
||||
[react/view components.styles/flex]
|
||||
content-item)
|
||||
action-items]))
|
||||
|
||||
(defn simple-toolbar
|
||||
"A simple toolbar whose content is a single line text"
|
||||
"A simple toolbar composed of a nav-back item and a single line title."
|
||||
([] (simple-toolbar nil))
|
||||
([title] (toolbar nil default-nav-back [content-title title])))
|
||||
([title] (simple-toolbar nil title))
|
||||
([m title] (simple-toolbar m default-nav-back title))
|
||||
([m nav-back title]
|
||||
(toolbar m nav-back [content-title title])))
|
||||
|
||||
(def search-text-input (r/atom nil))
|
||||
(def search-text-input (reagent/atom nil))
|
||||
|
||||
(defn- toolbar-search-submit [on-search-submit]
|
||||
(let [text @(rf/subscribe [:get-in [:toolbar-search :text]])]
|
||||
(let [text @(re-frame/subscribe [:get-in [:toolbar-search :text]])]
|
||||
(on-search-submit text)
|
||||
(rf/dispatch [:set-in [:toolbar-search :text] nil])))
|
||||
(re-frame/dispatch [:set-in [:toolbar-search :text] nil])))
|
||||
|
||||
(defn- toolbar-with-search-content [{:keys [show-search?
|
||||
search-placeholder
|
||||
title
|
||||
custom-title
|
||||
on-search-submit]}]
|
||||
[rn/view tst/toolbar-with-search-content
|
||||
[react/view styles/toolbar-with-search-content
|
||||
(if show-search?
|
||||
[rn/text-input
|
||||
{:style tst/toolbar-search-input
|
||||
[react/text-input
|
||||
{:style styles/toolbar-search-input
|
||||
:ref #(reset! search-text-input %)
|
||||
:auto-focus true
|
||||
:placeholder search-placeholder
|
||||
:placeholder-text-color st/color-gray4
|
||||
:on-change-text #(rf/dispatch [:set-in [:toolbar-search :text] %])
|
||||
:placeholder-text-color colors/gray
|
||||
:on-change-text #(re-frame/dispatch [:set-in [:toolbar-search :text] %])
|
||||
:on-submit-editing (when on-search-submit
|
||||
#(toolbar-search-submit on-search-submit))}]
|
||||
(or custom-title
|
||||
[rn/view
|
||||
[rn/text {:style tst/toolbar-title-text
|
||||
:font :toolbar-title}
|
||||
[react/view
|
||||
[react/text {:style styles/toolbar-title-text
|
||||
:font :toolbar-title}
|
||||
title]]))])
|
||||
|
||||
(defn- toggle-search-fn [text]
|
||||
(rf/dispatch [:set-in [:toolbar-search :show] text])
|
||||
(rf/dispatch [:set-in [:toolbar-search :text] ""]))
|
||||
(re-frame/dispatch [:set-in [:toolbar-search :show] text])
|
||||
(re-frame/dispatch [:set-in [:toolbar-search :text] ""]))
|
||||
|
||||
(defn- search-actions [show-search? search-text search-key actions]
|
||||
(if show-search?
|
||||
(if (pos? (count search-text))
|
||||
[(act/close #(do
|
||||
(.clear @search-text-input)
|
||||
(rf/dispatch [:set-in [:toolbar-search :text] ""])))]
|
||||
[act/search-icon])
|
||||
(into [(act/search #(toggle-search-fn search-key))] actions)))
|
||||
[(actions/close #(do
|
||||
(.clear @search-text-input)
|
||||
(re-frame/dispatch [:set-in [:toolbar-search :text] ""])))]
|
||||
[actions/search-icon])
|
||||
(into [(actions/search #(toggle-search-fn search-key))] actions)))
|
||||
|
||||
|
||||
(defn toolbar-with-search [{:keys [show-search?
|
||||
|
@ -178,7 +178,7 @@
|
|||
:style style}
|
||||
[nav-button
|
||||
(if show-search?
|
||||
(act/back #(toggle-search-fn nil))
|
||||
(or nav-action (if modal? act/default-close act/default-back)))]
|
||||
(actions/back #(toggle-search-fn nil))
|
||||
(or nav-action (if modal? actions/default-close actions/default-back)))]
|
||||
[toolbar-with-search-content opts]
|
||||
[actions (search-actions show-search? search-text search-key (:actions opts))]])
|
||||
[actions (search-actions show-search? search-text search-key (:actions opts))]])
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
(defstyle login-badge-container
|
||||
{:background-color :white
|
||||
:ios {:border-radius 8
|
||||
:padding-top 16
|
||||
:ios {:padding-top 16
|
||||
:height 150}
|
||||
:android {:border-radius 4
|
||||
:padding-top 12
|
||||
|
@ -29,13 +28,12 @@
|
|||
(merge sign-it-text
|
||||
{:color st/color-gray2}))
|
||||
|
||||
(defstyle sign-in-button
|
||||
(def sign-in-button
|
||||
{:background-color st/color-blue3
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:height 52
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(def processing-view
|
||||
{:position :absolute
|
||||
|
|
|
@ -14,9 +14,7 @@
|
|||
[status-im.ui.components.react :as components]))
|
||||
|
||||
(defn login-toolbar []
|
||||
[toolbar/toolbar
|
||||
{:background-color :transparent
|
||||
:hide-border? true}
|
||||
[toolbar/toolbar {:background-color :transparent}
|
||||
[toolbar/nav-button (act/back-white #(dispatch [:navigate-back]))]
|
||||
[toolbar/content-title {:color :white} (i18n/label :t/sign-in-to-status)]])
|
||||
|
||||
|
|
|
@ -49,8 +49,7 @@
|
|||
{:background-color :white
|
||||
:justify-content :center
|
||||
:height 64
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(def account-badge
|
||||
{:flex-direction :row
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns status-im.ui.screens.contacts.subs
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[status-im.utils.identicon :refer [identicon]]
|
||||
[clojure.string :as str]))
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :refer [reg-sub subscribe]]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.utils.identicon :as identicon]))
|
||||
|
||||
(reg-sub :current-contact
|
||||
(fn [db [_ k]]
|
||||
|
@ -94,9 +95,9 @@
|
|||
|
||||
(defn search-filter [text item]
|
||||
(let [name (-> (or (:name item) "")
|
||||
(str/lower-case))
|
||||
text (str/lower-case text)]
|
||||
(not= (str/index-of name text) nil)))
|
||||
(string/lower-case))
|
||||
text (string/lower-case text)]
|
||||
(not= (string/index-of name text) nil)))
|
||||
|
||||
(defn search-filter-reaction [contacts text]
|
||||
(if text
|
||||
|
@ -177,7 +178,7 @@
|
|||
contacts))
|
||||
|
||||
(reg-sub :contacts-by-chat
|
||||
(fn [[_ fn chat-id] _]
|
||||
(fn [[_ _ chat-id] _]
|
||||
[(subscribe [:get-chat chat-id])
|
||||
(subscribe [:get-contacts])])
|
||||
chat-contacts)
|
||||
|
@ -196,7 +197,21 @@
|
|||
(:photo-path (first contacts))
|
||||
|
||||
:else
|
||||
(identicon chat-id)))))
|
||||
(identicon/identicon chat-id)))))
|
||||
|
||||
(defn- address= [{:keys [address] :as contact} s]
|
||||
(when (and address (= (ethereum/normalized-address s)
|
||||
(ethereum/normalized-address address)))
|
||||
contact))
|
||||
|
||||
(defn- contact-by-address [[_ contact] s]
|
||||
(when (address= contact s)
|
||||
contact))
|
||||
|
||||
(reg-sub :contact/by-address
|
||||
:<- [:get-contacts]
|
||||
(fn [contacts [_ address]]
|
||||
(some #(contact-by-address % address) contacts)))
|
||||
|
||||
(reg-sub :contacts/by-address
|
||||
:<- [:get-contacts]
|
||||
|
|
|
@ -41,19 +41,19 @@
|
|||
[toolbar/content-title (label :t/edit-contacts)]])
|
||||
|
||||
(defn contact-options [{:keys [unremovable?] :as contact} group]
|
||||
(let [delete-contact-opt {:value #(u/show-confirmation
|
||||
(let [delete-contact-opt {:action #(u/show-confirmation
|
||||
(str (label :t/delete-contact) "?") (label :t/delete-contact-confirmation)
|
||||
(label :t/delete)
|
||||
(fn [] (dispatch [:hide-contact contact])))
|
||||
:text (label :t/delete-contact)
|
||||
:label (label :t/delete-contact)
|
||||
:destructive? true}
|
||||
options (if unremovable? [] [delete-contact-opt])]
|
||||
(if group
|
||||
(conj options
|
||||
{:value #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity contact)
|
||||
(:group-id group)])
|
||||
:text (label :t/remove-from-group)})
|
||||
{:action #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity contact)
|
||||
(:group-id group)])
|
||||
:label (label :t/remove-from-group)})
|
||||
options)))
|
||||
|
||||
(defn contact-group-form [{:keys [contacts contacts-count group edit? click-handler]}]
|
||||
|
@ -63,8 +63,8 @@
|
|||
[common/form-title subtitle
|
||||
{:count-value contacts-count
|
||||
:extended? edit?
|
||||
:options [{:value #(dispatch [:navigate-to :edit-contact-group group :contact-group])
|
||||
:text (label :t/edit-group)}]}])
|
||||
:options [{:action #(dispatch [:navigate-to :edit-contact-group group :contact-group])
|
||||
:label (label :t/edit-group)}]}])
|
||||
[view st/contacts-list
|
||||
[common/list-footer]
|
||||
(doall
|
||||
|
|
|
@ -143,12 +143,11 @@
|
|||
:margin-bottom 4
|
||||
:margin-right 2}})
|
||||
|
||||
(defstyle chat-button-container
|
||||
(def chat-button-container
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
:background-color styles/color-blue4-transparent
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(defstyle chat-button-inner
|
||||
{:flex-direction :row
|
||||
|
@ -257,7 +256,7 @@
|
|||
:justify-content :center
|
||||
:align-items :center
|
||||
:flex-direction :column
|
||||
:ios {:border-radius 8
|
||||
:ios {
|
||||
:border-color styles/color-light-blue6}
|
||||
:android {:border-radius 4}})
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
[view
|
||||
[contact-view
|
||||
{:contact row
|
||||
:extend-options [{:value #(dispatch [:remove-group-chat-participants #{(:whisper-identity row)}])
|
||||
:text (label :t/remove)}]
|
||||
:extend-options [{:action #(dispatch [:remove-group-chat-participants #{(:whisper-identity row)}])
|
||||
:label (label :t/remove)}]
|
||||
:extended? admin?}]
|
||||
(when-not (= row (last limited-contacts))
|
||||
[common/list-separator])])
|
||||
|
|
|
@ -33,16 +33,16 @@
|
|||
:header list/default-header}]])
|
||||
|
||||
(defn chat-extended-options [item]
|
||||
[{:value #(re-frame/dispatch [:remove-group-chat-participants #{(:whisper-identity item)}])
|
||||
:text (i18n/label :t/remove)}])
|
||||
[{:action #(re-frame/dispatch [:remove-group-chat-participants #{(:whisper-identity item)}])
|
||||
:label (i18n/label :t/remove)}])
|
||||
|
||||
(defn contact-extended-options [group-id]
|
||||
(fn [item]
|
||||
[{:value #(re-frame/dispatch [:remove-contact-from-group
|
||||
(:whisper-identity item)
|
||||
group-id])
|
||||
[{:action #(re-frame/dispatch [:remove-contact-from-group
|
||||
(:whisper-identity item)
|
||||
group-id])
|
||||
:accessibility-label :remove-button
|
||||
:text (i18n/label :t/remove-from-group)}]))
|
||||
:label (i18n/label :t/remove-from-group)}]))
|
||||
|
||||
(defview edit-chat-group-contact-list []
|
||||
(letsubs [chat-name [:chat :name]
|
||||
|
|
|
@ -106,10 +106,10 @@
|
|||
[view
|
||||
[contact-view
|
||||
{:contact row
|
||||
:extend-options [{:value #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity row)
|
||||
(:group-id group)])
|
||||
:text (label :t/remove-from-group)}]
|
||||
:extend-options [{:action #(dispatch [:remove-contact-from-group
|
||||
(:whisper-identity row)
|
||||
(:group-id group)])
|
||||
:label (label :t/remove-from-group)}]
|
||||
:extended? true}]
|
||||
(when-not (= row (last contacts))
|
||||
[common/list-separator])])
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn toolbar-view []
|
||||
[toolbar/toolbar {:show-sync-bar? true}
|
||||
[toolbar/toolbar {}
|
||||
nil
|
||||
[toolbar/content-title (i18n/label :t/status)]
|
||||
[toolbar/actions
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
(views/defview main-tabs []
|
||||
(views/letsubs [view-id [:get :view-id]]
|
||||
[react/view common.styles/flex
|
||||
[status-bar.view/status-bar {:type (if (= view-id :wallet) :wallet :main)}]
|
||||
[status-bar.view/status-bar {:type (if (= view-id :wallet) :wallet-tab :main)}]
|
||||
[react/view common.styles/main-container
|
||||
|
||||
[react/with-activity-indicator
|
||||
|
|
|
@ -33,9 +33,8 @@
|
|||
:align-items :center
|
||||
:justify-content :center
|
||||
:background-color common/color-light-blue
|
||||
:ios {:border-radius 8
|
||||
:opacity 0.9}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8
|
||||
:ios {:opacity 0.9}})
|
||||
|
||||
(defstyle connect-button-label
|
||||
{:color common/color-white
|
||||
|
@ -84,10 +83,10 @@
|
|||
:align-items :center
|
||||
:justify-content :center
|
||||
:background-color common/color-light-blue-transparent
|
||||
:ios {:width 343
|
||||
:border-radius 8}
|
||||
:android {:width 328
|
||||
:border-radius 4}})
|
||||
:border-radius 8
|
||||
:ios {:width 343}
|
||||
|
||||
:android {:width 328}})
|
||||
|
||||
(defstyle edit-button-label
|
||||
{:color common/color-light-blue
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
[react/view styles/wnode-item-inner
|
||||
[react/text {:style styles/wnode-item-name-text}
|
||||
name]
|
||||
#_(when connected?
|
||||
#_
|
||||
(when connected?
|
||||
[react/text {:style styles/wnode-item-connected-text}
|
||||
(i18n/label :t/connected)])]]]])))
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
(def profile-status-container
|
||||
{:background-color colors/gray
|
||||
:margin-top 16
|
||||
:border-radius 4
|
||||
:border-radius 8
|
||||
:padding 16
|
||||
:max-height 114})
|
||||
|
||||
|
@ -201,7 +201,7 @@
|
|||
|
||||
(defstyle edit-profile-status
|
||||
{:background-color styles/color-light-gray
|
||||
:border-radius 4
|
||||
:border-radius 8
|
||||
:height 90
|
||||
:padding-horizontal 16
|
||||
:padding-bottom 16
|
||||
|
|
|
@ -42,8 +42,8 @@
|
|||
[toolbar/toolbar {}
|
||||
nil
|
||||
[toolbar/content-title ""]
|
||||
[common/icon-or-label {:on-press #(re-frame/dispatch [:my-profile/save-profile])}
|
||||
:t/done {} :icons/ok {:color colors/blue}]])
|
||||
[common/icon-or-label {:on-press #(re-frame/dispatch [:my-profile/save-profile])}
|
||||
:t/done {} :icons/ok {:color colors/blue}]])
|
||||
|
||||
(defn profile-toolbar [contact]
|
||||
[toolbar/toolbar {}
|
||||
|
@ -52,8 +52,8 @@
|
|||
[toolbar/actions
|
||||
(when (and (not (:pending? contact))
|
||||
(not (:unremovable? contact)))
|
||||
[(actions/opts [{:value #(re-frame/dispatch [:hide-contact contact])
|
||||
:text (i18n/label :t/remove-from-contacts)}])])]])
|
||||
[(actions/opts [{:action #(re-frame/dispatch [:hide-contact contact])
|
||||
:label (i18n/label :t/remove-from-contacts)}])])]])
|
||||
|
||||
(defn online-text [last-online]
|
||||
(let [last-online-date (time/to-date last-online)
|
||||
|
@ -88,27 +88,24 @@
|
|||
:on-change-text #(re-frame/dispatch [:my-profile/update-name %])}]])
|
||||
|
||||
(def profile-icon-options
|
||||
[{:text (i18n/label :t/image-source-gallery)
|
||||
:value #(re-frame/dispatch [:my-profile/update-picture])}
|
||||
{:text (i18n/label :t/image-source-make-photo)
|
||||
:value (fn []
|
||||
(re-frame/dispatch [:request-permissions
|
||||
[:camera :write-external-storage]
|
||||
(fn []
|
||||
(camera/request-access
|
||||
#(if %
|
||||
(re-frame/dispatch [:navigate-to :profile-photo-capture])
|
||||
(utils/show-popup (i18n/label :t/error)
|
||||
(i18n/label :t/camera-access-error)))))]))}])
|
||||
[{:label (i18n/label :t/image-source-gallery)
|
||||
:action #(re-frame/dispatch [:my-profile/update-picture])}
|
||||
{:label (i18n/label :t/image-source-make-photo)
|
||||
:action (fn []
|
||||
(re-frame/dispatch [:request-permissions
|
||||
[:camera :write-external-storage]
|
||||
#(re-frame/dispatch [:navigate-to :profile-photo-capture])
|
||||
#(utils/show-popup (i18n/label :t/error)
|
||||
(i18n/label :t/camera-access-error))]))}])
|
||||
|
||||
|
||||
(defn profile-badge-edit [{:keys [name last-online] :as account}]
|
||||
[react/view styles/profile-badge-edit
|
||||
[context-menu/modal-menu
|
||||
[chat-icon.screen/my-profile-icon {:account account
|
||||
:edit? true}]
|
||||
styles/modal-menu
|
||||
(i18n/label :t/image-source-title)
|
||||
profile-icon-options]
|
||||
[react/touchable-highlight {:on-press #(list-selection/show {:title (i18n/label :t/image-source-title)
|
||||
:options profile-icon-options})}
|
||||
[react/view styles/modal-menu
|
||||
[chat-icon.screen/my-profile-icon {:account account
|
||||
:edit? true}]]]
|
||||
[react/view styles/profile-badge-name-container
|
||||
[profile-name-input name]
|
||||
(when-not (nil? last-online)
|
||||
|
@ -164,15 +161,15 @@
|
|||
|
||||
(defn profile-options [contact k text]
|
||||
(into []
|
||||
(concat [{:value (show-qr contact k text)
|
||||
:text (i18n/label :t/show-qr)}]
|
||||
(concat [{:action (show-qr contact k text)
|
||||
:label (i18n/label :t/show-qr)}]
|
||||
(when text
|
||||
(list-selection/share-options text)))))
|
||||
|
||||
(defn profile-info-address-item [{:keys [address] :as contact}]
|
||||
[profile-info-item
|
||||
{:label (i18n/label :t/address)
|
||||
:value address
|
||||
:action address
|
||||
:options (profile-options contact :address address)
|
||||
:text-mode :middle
|
||||
:accessibility-label :profile-address}])
|
||||
|
@ -180,7 +177,7 @@
|
|||
(defn profile-info-public-key-item [public-key contact]
|
||||
[profile-info-item
|
||||
{:label (i18n/label :t/public-key)
|
||||
:value public-key
|
||||
:action public-key
|
||||
:options (profile-options contact :public-key public-key)
|
||||
:text-mode :middle
|
||||
:accessibility-label :profile-public-key}])
|
||||
|
@ -207,7 +204,7 @@
|
|||
(i18n/label :t/not-specified)
|
||||
phone)]
|
||||
[profile-info-item {:label (i18n/label :t/phone-number)
|
||||
:value phone-text
|
||||
:action phone-text
|
||||
:options options
|
||||
:empty-value? phone-empty?
|
||||
:accessibility-label :profile-phone-number}]))
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
[_ [_ identifier]]
|
||||
(re-frame/dispatch [:request-permissions
|
||||
[:camera]
|
||||
(fn []
|
||||
(camera/request-access
|
||||
#(if % (re-frame/dispatch [:navigate-to :qr-scanner identifier])
|
||||
(utils/show-popup (i18n/label :t/error)
|
||||
(i18n/label :t/camera-access-error)))))]))
|
||||
#(re-frame/dispatch [:navigate-to :qr-scanner identifier])
|
||||
#(utils/show-popup (i18n/label :t/error)
|
||||
(i18n/label :t/camera-access-error))]))
|
||||
|
||||
(register-handler :scan-qr-code
|
||||
(re-frame/after navigate-to-scanner)
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
[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.send.transaction-sent.views :refer [transaction-sent transaction-sent-modal]]
|
||||
[status-im.ui.screens.wallet.components.views :refer [contact-code recent-recipients recipient-qr-code]]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.screens.discover.search-results.views :as discover-search]
|
||||
[status-im.ui.screens.discover.recent-statuses.views :as discover-recent]
|
||||
|
@ -96,6 +97,7 @@
|
|||
|
||||
{:view :wallet-send-transaction
|
||||
:parent :wallet
|
||||
:hide? (not android?)
|
||||
:component send-transaction}
|
||||
|
||||
{:view :wallet-request-transaction
|
||||
|
@ -108,6 +110,7 @@
|
|||
|
||||
{:view :choose-recipient
|
||||
:parent :wallet-send-transaction
|
||||
:hide? true
|
||||
:component choose-recipient}
|
||||
|
||||
{:view :wallet-transaction-sent
|
||||
|
@ -134,7 +137,6 @@
|
|||
:browser browser
|
||||
:wallet-send-transaction send-transaction
|
||||
:wallet-transaction-sent transaction-sent
|
||||
:choose-recipient choose-recipient
|
||||
:wallet-request-transaction request-transaction
|
||||
(:transactions-history :unsigned-transactions) wallet-transactions/transactions
|
||||
:wallet-transaction-details wallet-transactions/transaction-details
|
||||
|
@ -169,11 +171,15 @@
|
|||
:paste-json-text paste-json-text
|
||||
:add-rpc-url add-rpc-url
|
||||
:network-details network-details
|
||||
:recent-recipients recent-recipients
|
||||
:recipient-qr-code recipient-qr-code
|
||||
:contact-code contact-code
|
||||
:qr-viewer qr-code-viewer/qr-viewer
|
||||
(throw (str "Unknown view: " current-view)))]
|
||||
[(if android? menu-context view) common-styles/flex
|
||||
[view common-styles/flex
|
||||
(if (and signed-up?
|
||||
(if (and android?
|
||||
signed-up?
|
||||
(#{:home :wallet :my-profile :chat :wallet-send-transaction
|
||||
:choose-recipient :wallet-transaction-sent :transactions-history
|
||||
:unsigned-transactions :wallet-request-transaction :edit-my-profile
|
||||
|
@ -184,7 +190,7 @@
|
|||
(when modal-view
|
||||
[view common-styles/modal
|
||||
[modal {:animation-type :slide
|
||||
:transparent false
|
||||
:transparent true
|
||||
:on-request-close #(dispatch [:navigate-back])}
|
||||
(let [component (case modal-view
|
||||
:qr-scanner qr-scanner
|
||||
|
|
|
@ -13,16 +13,15 @@
|
|||
toggled-state (if (= :on flashlight-state) :off :on)]
|
||||
(assoc-in db [:wallet :send-transaction :camera-flashlight] toggled-state))))
|
||||
|
||||
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice] :as m}]
|
||||
(defn- fill-request-details [db {:keys [address name value symbol gas gasPrice]}]
|
||||
{:pre [(not (nil? address))]}
|
||||
(update-in
|
||||
db [:wallet :send-transaction]
|
||||
#(cond-> (assoc % :to address)
|
||||
value (assoc :amount value)
|
||||
name (assoc :to-name name)
|
||||
symbol (assoc :symbol symbol)
|
||||
gas (assoc :gas (money/bignumber gas))
|
||||
gasPrice (assoc :gas-price (money/bignumber gasPrice))
|
||||
#(cond-> (assoc % :to address :to-name name)
|
||||
value (assoc :amount value)
|
||||
symbol (assoc :symbol symbol)
|
||||
gas (assoc :gas (money/bignumber gas))
|
||||
gasPrice (assoc :gas-price (money/bignumber gasPrice))
|
||||
(and symbol (not gasPrice))
|
||||
(assoc :gas-price (ethereum/estimate-gas symbol)))))
|
||||
|
||||
|
@ -37,12 +36,13 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:wallet/fill-request-from-url
|
||||
(fn [{{:keys [web3 network] :as db} :db} [_ data name]]
|
||||
(fn [{{:keys [network] :as db} :db} [_ data]]
|
||||
(let [{:keys [view-id]} db
|
||||
current-chain-id (get-in constants/default-networks [network :raw-config :NetworkId])
|
||||
{:keys [address chain-id] :as details} (extract-details data current-chain-id)
|
||||
valid-network? (boolean (= current-chain-id chain-id))]
|
||||
(cond-> {:db db}
|
||||
(cond-> {:db db
|
||||
:dispatch [:navigate-back]}
|
||||
(and address (= :choose-recipient view-id)) (assoc :dispatch [:navigate-back])
|
||||
(and address valid-network?) (update :db #(fill-request-details % details))
|
||||
(not address) (assoc :show-error (i18n/label :t/wallet-invalid-address {:data data}))
|
||||
|
@ -52,5 +52,4 @@
|
|||
:wallet/fill-request-from-contact
|
||||
(fn [{db :db} [_ {:keys [address name]}]]
|
||||
{:db (fill-request-details db {:address address :name name})
|
||||
:dispatch-n [[:navigate-back]
|
||||
[:navigate-back]]}))
|
||||
:dispatch [:navigate-back]}))
|
||||
|
|
|
@ -1,38 +1,12 @@
|
|||
(ns status-im.ui.screens.wallet.choose-recipient.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defnstyle defstyle]])
|
||||
(:require [status-im.ui.components.styles :as styles]))
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def toolbar
|
||||
{:background-color :transparent})
|
||||
|
||||
(def wallet-container
|
||||
{:flex 1
|
||||
:background-color styles/color-blue4})
|
||||
|
||||
(def toolbar-buttons-container
|
||||
{:flex-direction :row
|
||||
:flex-shrink 1
|
||||
:justify-content :space-between
|
||||
:width 68
|
||||
:margin-right 12})
|
||||
|
||||
(def choose-recipient-container
|
||||
{:flex-direction :row
|
||||
:padding-top 20
|
||||
:padding-bottom 20
|
||||
:justify-content :center})
|
||||
|
||||
(def choose-recipient-label
|
||||
{:color :white})
|
||||
|
||||
(defstyle recipient-buttons
|
||||
{:flex-direction :column
|
||||
:margin-horizontal 28
|
||||
:margin-vertical 20
|
||||
:border-radius 8
|
||||
:ios {:background-color styles/color-blue6}})
|
||||
|
||||
(def recipient-icon {:margin-right 20})
|
||||
|
||||
(def recipient-icon-disabled {:margin-right 20
|
||||
:opacity 0.3})
|
||||
:background-color colors/blue})
|
||||
|
||||
(def recipient-button
|
||||
{:flex-direction :row
|
||||
|
@ -45,24 +19,12 @@
|
|||
:align-self :center
|
||||
:font-size 14})
|
||||
|
||||
(def recipient-button-text-disabled
|
||||
(merge recipient-button-text {:color "rgba(255, 255, 255, 0.3)"}))
|
||||
|
||||
(defnstyle recipient-touchable [divider?]
|
||||
(cond-> {:border-color styles/color-gray-transparent-light}
|
||||
divider? (assoc :ios {:border-bottom-width 1})))
|
||||
|
||||
(def recipient-touchable-disabled
|
||||
{:background-color styles/color-blue4
|
||||
:border-bottom-left-radius 8
|
||||
:border-bottom-right-radius 8
|
||||
:border-left-width 1
|
||||
:border-bottom-width 1
|
||||
:border-right-width 1
|
||||
:border-color "rgba(255, 255, 255, 0.3)"})
|
||||
|
||||
(def qr-container
|
||||
{:flex 1})
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0})
|
||||
|
||||
(def preview
|
||||
{:flex 1
|
||||
|
@ -74,25 +36,21 @@
|
|||
:width 40
|
||||
:height 40})
|
||||
|
||||
(defn corner-left-bottom [dimension]
|
||||
(let [viewport-offset 0.1666]
|
||||
(merge corner-dimensions {:bottom (* viewport-offset dimension)
|
||||
:left (* viewport-offset dimension)})))
|
||||
(defn corner-left-bottom [height width size]
|
||||
(merge corner-dimensions {:bottom (int (/ (- height size) 2))
|
||||
:left (int (/ (- width size) 2))}))
|
||||
|
||||
(defn corner-right-bottom [dimension]
|
||||
(let [viewport-offset 0.1666]
|
||||
(merge corner-dimensions {:right (* viewport-offset dimension)
|
||||
:bottom (* viewport-offset dimension)})))
|
||||
(defn corner-right-bottom [height width size]
|
||||
(merge corner-dimensions {:right (int (/ (- width size) 2))
|
||||
:bottom (int (/ (- height size) 2))}))
|
||||
|
||||
(defn corner-left-top [dimension]
|
||||
(let [viewport-offset 0.1666]
|
||||
(merge corner-dimensions {:top (* viewport-offset dimension)
|
||||
:left (* viewport-offset dimension)})))
|
||||
(defn corner-left-top [height width size]
|
||||
(merge corner-dimensions {:top (int (/ (- height size) 2))
|
||||
:left (int (/ (- width size) 2))}))
|
||||
|
||||
(defn corner-right-top [dimension]
|
||||
(let [viewport-offset 0.1666]
|
||||
(merge corner-dimensions {:top (* viewport-offset dimension)
|
||||
:right (* viewport-offset dimension)})))
|
||||
(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
|
||||
|
@ -101,24 +59,37 @@
|
|||
:right 0
|
||||
:flex 1})
|
||||
|
||||
(defn viewfinder-translucent [height width side]
|
||||
(let [viewport-offset 0.1666
|
||||
min-dimension (min height width)
|
||||
min-offset (* viewport-offset min-dimension)]
|
||||
(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 min-offset
|
||||
:width width)
|
||||
(= :right side) (assoc :height (- height min-offset)
|
||||
:width min-offset
|
||||
:bottom 0
|
||||
:right 0)
|
||||
(= :bottom side) (assoc :height min-offset
|
||||
:width (- width min-offset)
|
||||
(= :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 (- height (* 2 min-offset))
|
||||
:width min-offset
|
||||
:top min-offset
|
||||
:left 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-lighter-transparent
|
||||
:align-items :center})
|
||||
|
||||
(defn qr-code-text [dimensions]
|
||||
{:zIndex 1
|
||||
:padding-top 20
|
||||
:color :white
|
||||
:text-align :center
|
||||
:width (int (/ (:width dimensions) 2))})
|
||||
|
|
|
@ -1,100 +1,65 @@
|
|||
(ns status-im.ui.screens.wallet.choose-recipient.views
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.bottom-buttons.view :as bottom-buttons]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.components.camera :as camera]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.toolbar.actions :as act]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.wallet.choose-recipient.styles :as styles]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ui.screens.wallet.styles :as wallet.styles]))
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn choose-from-contacts []
|
||||
(re-frame/dispatch [:navigate-to-modal
|
||||
:contact-list-modal
|
||||
{:handler #(re-frame/dispatch [:wallet/fill-request-from-contact %])
|
||||
:action :send
|
||||
:params {:hide-actions? true}}]))
|
||||
|
||||
(defn toolbar-view [camera-flashlight]
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||
[toolbar/nav-button (act/back-white act/default-handler)]
|
||||
[toolbar/content-title {:color :white} (i18n/label :t/wallet-choose-recipient)]
|
||||
[toolbar/actions [{:icon (if (= :on camera-flashlight) :icons/flash-active
|
||||
:icons/flash-inactive)
|
||||
(defn- toolbar-view [camera-flashlight]
|
||||
[toolbar/toolbar styles/toolbar
|
||||
[toolbar/nav-button (actions/back-white actions/default-handler)]
|
||||
[toolbar/content-title {:color :white}
|
||||
(i18n/label :t/wallet-choose-recipient)]
|
||||
[toolbar/actions [{:icon (if (= :on camera-flashlight)
|
||||
:icons/flash-active
|
||||
:icons/flash-inactive)
|
||||
:icon-opts {:color :white}
|
||||
:handler #(re-frame/dispatch [:wallet/toggle-flashlight])}]]])
|
||||
:handler #(re-frame/dispatch [:wallet/toggle-flashlight])}]]])
|
||||
|
||||
(defn recipient-buttons []
|
||||
[react/view {:style styles/recipient-buttons}
|
||||
[react/touchable-highlight {:style (styles/recipient-touchable true)
|
||||
:on-press choose-from-contacts}
|
||||
[react/view {:style styles/recipient-button}
|
||||
[react/text {:style styles/recipient-button-text}
|
||||
(i18n/label :t/wallet-choose-from-contacts)]
|
||||
[vector-icons/icon :icons/qr {:color :white
|
||||
:container-style styles/recipient-icon}]]]
|
||||
[react/touchable-highlight {:style (styles/recipient-touchable true)
|
||||
:on-press #(react/get-from-clipboard
|
||||
(fn [clipboard]
|
||||
(re-frame/dispatch [:wallet/fill-request-from-url (string/trim-newline clipboard) nil])))}
|
||||
[react/view {:style styles/recipient-button}
|
||||
[react/text {:style styles/recipient-button-text}
|
||||
(i18n/label :t/wallet-address-from-clipboard)]
|
||||
[vector-icons/icon :icons/copy-from {:color :white
|
||||
:container-style styles/recipient-icon}]]]
|
||||
[react/touchable-highlight {:style styles/recipient-touchable-disabled}
|
||||
[react/view {:style styles/recipient-button}
|
||||
[react/text {:style styles/recipient-button-text-disabled}
|
||||
(i18n/label :t/wallet-browse-photos)]
|
||||
[vector-icons/icon :icons/browse {:color :white
|
||||
:container-style styles/recipient-icon-disabled}]]]])
|
||||
(defn- viewfinder [{:keys [height width]} size]
|
||||
[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 viewfinder [{:keys [height width]}]
|
||||
(let [min-dimension (min height width)]
|
||||
[react/view {:style styles/viewfinder-port}
|
||||
[react/view {:style (styles/viewfinder-translucent height width :top)}]
|
||||
[react/view {:style (styles/viewfinder-translucent height width :right)}]
|
||||
[react/view {:style (styles/viewfinder-translucent height width :bottom)}]
|
||||
[react/view {:style (styles/viewfinder-translucent height width :left)}]
|
||||
[react/image {:source {:uri :corner_left_top}
|
||||
:style (styles/corner-left-top min-dimension)}]
|
||||
[react/image {:source {:uri :corner_right_top}
|
||||
:style (styles/corner-right-top min-dimension)}]
|
||||
[react/image {:source {:uri :corner_left_bottom}
|
||||
:style (styles/corner-left-bottom min-dimension)}]
|
||||
[react/image {:source {:uri :corner_right_bottom}
|
||||
:style (styles/corner-right-bottom min-dimension)}]]))
|
||||
(defn- size [{:keys [height width]}]
|
||||
(int (* 2 (/ (min height width) 3))))
|
||||
|
||||
(defview choose-recipient []
|
||||
(letsubs [camera-dimensions [:wallet.send/camera-dimensions]
|
||||
(letsubs [dimensions (react/get-dimensions "window")
|
||||
camera-flashlight [:wallet.send/camera-flashlight]
|
||||
camera-permitted? [:wallet.send/camera-permitted?]
|
||||
view [:get :view-id]]
|
||||
[react/view {:style styles/wallet-container}
|
||||
[status-bar/status-bar {:type :wallet}]
|
||||
[react/view {:style styles/qr-code}
|
||||
[status-bar/status-bar {:type :transparent}]
|
||||
[toolbar-view camera-flashlight]
|
||||
[react/view {:style styles/qr-container
|
||||
:pointerEvents :none
|
||||
:on-layout #(let [layout (.. % -nativeEvent -layout)]
|
||||
(re-frame/dispatch [:wallet.send/set-camera-dimensions
|
||||
{:width (.-width layout)
|
||||
:height (.-height layout)}]))}
|
||||
|
||||
(when (and
|
||||
(= view :choose-recipient)
|
||||
(or platform/android?
|
||||
camera-permitted?))
|
||||
[react/with-activity-indicator
|
||||
{}
|
||||
[camera/camera {:style styles/preview
|
||||
:aspect :fill
|
||||
:captureAudio false
|
||||
:torchMode (camera/set-torch camera-flashlight)
|
||||
:onBarCodeRead #(re-frame/dispatch [:wallet/fill-request-from-url (camera/get-qr-code-data %) nil])}]])
|
||||
[viewfinder camera-dimensions]]
|
||||
[recipient-buttons]]))
|
||||
[react/text {:style (styles/qr-code-text dimensions)}
|
||||
(i18n/label :t/scan-qr-code)]
|
||||
[react/view {:style styles/qr-container
|
||||
:pointer-events :none}
|
||||
[react/with-activity-indicator
|
||||
{}
|
||||
[camera/camera {:style styles/preview
|
||||
:aspect :fill
|
||||
:captureAudio false
|
||||
:torchMode (camera/set-torch camera-flashlight)
|
||||
:onBarCodeRead #(re-frame/dispatch [:wallet/fill-request-from-url (camera/get-qr-code-data %) nil])}]]
|
||||
[viewfinder dimensions (size dimensions)]]
|
||||
[bottom-buttons/bottom-button
|
||||
[button/button {:disabled? false :on-press #(re-frame/dispatch [:navigate-back])}
|
||||
(i18n/label :t/cancel)]]]))
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
(ns status-im.ui.screens.wallet.components
|
||||
"
|
||||
Higher-level components used in the wallet screens.
|
||||
"
|
||||
(:require [status-im.utils.utils :as utils]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.screens.wallet.styles :as styles]))
|
||||
|
||||
;; 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/deep-merge {:placeholder-text-color colors/white-lighter-transparent
|
||||
:selection-color colors/white
|
||||
:style {:color colors/white
|
||||
:font-size 15
|
||||
:height 52
|
||||
:letter-spacing -0.2}}
|
||||
props)
|
||||
text])
|
||||
|
||||
(defn- toolbar [action title]
|
||||
[toolbar/toolbar {:style styles/toolbar}
|
||||
[toolbar/nav-button action]
|
||||
[toolbar/content-title {:color :white}
|
||||
title]])
|
||||
|
||||
(defn simple-screen [title content]
|
||||
[react/view {:flex 1 :background-color colors/blue}
|
||||
[status-bar/status-bar {:type :wallet}]
|
||||
[toolbar (actions/back-white actions/default-handler)
|
||||
title]
|
||||
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] :or {icon :icons/forward} :as m} header content]
|
||||
[react/view {:style styles/cartouche-container}
|
||||
[react/text {:style styles/cartouche-header}
|
||||
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 {:color :white}]]
|
||||
content)]]])])
|
||||
|
||||
(defn- cartouche-primary-text [s]
|
||||
[react/text {:style styles/cartouche-primary-text}
|
||||
s])
|
||||
|
||||
(defn- cartouche-secondary-text [s]
|
||||
[react/text {:style styles/cartouche-secondary-text}
|
||||
s])
|
||||
|
||||
(defn cartouche-text-content [primary secondary]
|
||||
[react/view {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 15
|
||||
:padding-vertical 15}
|
||||
[cartouche-primary-text primary]
|
||||
[cartouche-secondary-text secondary]])
|
|
@ -7,6 +7,6 @@
|
|||
(animation/parallel
|
||||
[(animation/timing opacity-value {:toValue 1
|
||||
:duration 500})
|
||||
(animation/timing bottom-value {:toValue 8.5
|
||||
(animation/timing bottom-value {:toValue -40
|
||||
:easing (.bezier (animation/easing) 0.685, 0.000, 0.025, 1.185)
|
||||
:duration 500})]))))
|
||||
:duration 500})]))))
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
(ns status-im.ui.screens.wallet.components.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defnstyle defstyle]])
|
||||
(:require [status-im.ui.components.styles :as styles]))
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.styles :as styles]))
|
||||
|
||||
(def text-content
|
||||
{:color :white})
|
||||
{:color colors/white})
|
||||
|
||||
(def text-secondary-content
|
||||
{:color styles/color-white-transparent})
|
||||
{:color colors/white-lighter-transparent})
|
||||
|
||||
(def text
|
||||
{:margin-right 10})
|
||||
|
||||
(def text-list-primary-content
|
||||
(merge text {:color styles/color-black}))
|
||||
(merge text {:color colors/black}))
|
||||
|
||||
(def text-input
|
||||
(merge text-content
|
||||
{:padding-left 14
|
||||
:padding-right 14
|
||||
:font-size 15
|
||||
{:font-size 15
|
||||
:padding-bottom 0
|
||||
:padding-top 0
|
||||
:height 52
|
||||
|
@ -36,15 +35,14 @@
|
|||
|
||||
(def label-transparent
|
||||
(merge label
|
||||
{:color styles/color-white-transparent}))
|
||||
{:color colors/white-lighter-transparent}))
|
||||
|
||||
(defnstyle amount-container [active?]
|
||||
(defn amount-container [active?]
|
||||
{:height 52
|
||||
:background-color (if active?
|
||||
styles/color-white-transparent-4
|
||||
colors/white-light-transparent
|
||||
styles/color-white-transparent-3)
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(def network
|
||||
{:color :white
|
||||
|
@ -56,11 +54,11 @@
|
|||
:height 27
|
||||
:border-radius 100
|
||||
:border-width 1
|
||||
:border-color styles/color-white-transparent-4
|
||||
:border-color colors/white-light-transparent
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(defstyle asset-container
|
||||
(def asset-container
|
||||
{:margin-top 8
|
||||
:height 52
|
||||
:background-color styles/color-white-transparent-3
|
||||
|
@ -68,12 +66,23 @@
|
|||
:padding-left 14
|
||||
:padding-vertical 14
|
||||
:padding-right 8
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(def asset-container-read-only
|
||||
{:margin-top 8
|
||||
:height 52
|
||||
:border-color styles/color-white-transparent-3
|
||||
: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})
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:margin-vertical 11})
|
||||
|
||||
(def asset-icon
|
||||
{:background-color styles/color-gray9
|
||||
|
@ -97,37 +106,19 @@
|
|||
|
||||
(defstyle container-disabled
|
||||
{:border-width 1
|
||||
:border-color styles/color-white-transparent-4
|
||||
:border-color colors/white-light-transparent
|
||||
:background-color nil
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
|
||||
(defstyle recipient-container
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:margin-top 8
|
||||
:height 52
|
||||
:align-items :center
|
||||
:background-color styles/color-white-transparent-3
|
||||
:padding-vertical 14
|
||||
:padding-left 14
|
||||
:padding-right 8
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
|
||||
(defstyle wallet-container
|
||||
(def wallet-container
|
||||
{:flex-direction :row
|
||||
:margin-top 8
|
||||
:height 52
|
||||
;;TODO disabled
|
||||
:border-width 1
|
||||
:border-color styles/color-white-transparent-4
|
||||
;:background-color styles/color-white-transparent-3
|
||||
:border-color colors/white-light-transparent
|
||||
:align-items :center
|
||||
:padding 14
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(def wallet-name
|
||||
{:color :white
|
||||
|
@ -135,11 +126,34 @@
|
|||
:letter-spacing -0.2})
|
||||
|
||||
(defn participant [address?]
|
||||
{:color (if address? :white styles/color-white-transparent)
|
||||
{:color (if address? :white colors/white-lighter-transparent)
|
||||
:flex-shrink 1
|
||||
:font-size 15
|
||||
:letter-spacing -0.2})
|
||||
|
||||
(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
|
||||
:color colors/white})
|
||||
|
||||
(def recipient-no-address
|
||||
{:color colors/white-lighter-transparent})
|
||||
|
||||
(def recent-recipients
|
||||
{:flex 1
|
||||
:background-color colors/white})
|
||||
|
||||
(def wallet-value-container
|
||||
{:flex 1
|
||||
:flex-direction :row})
|
||||
|
@ -191,31 +205,3 @@
|
|||
(def tooltip-triangle
|
||||
{:width 16
|
||||
:height 8})
|
||||
|
||||
(def recipient-name-container
|
||||
{:padding-right 6})
|
||||
|
||||
(def today-variation-container
|
||||
{:border-radius 100
|
||||
:margin-left 8
|
||||
:padding-horizontal 8
|
||||
:padding-vertical 4})
|
||||
|
||||
(def today-variation-container-positive
|
||||
(merge today-variation-container
|
||||
{:background-color styles/color-green-1}))
|
||||
|
||||
(def today-variation-container-negative
|
||||
(merge today-variation-container
|
||||
{:background-color styles/color-red-3}))
|
||||
|
||||
(def today-variation
|
||||
{:font-size 12})
|
||||
|
||||
(def today-variation-positive
|
||||
(merge today-variation
|
||||
{:color styles/color-green-2}))
|
||||
|
||||
(def today-variation-negative
|
||||
(merge today-variation
|
||||
{:color styles/color-red-4}))
|
|
@ -1,64 +1,44 @@
|
|||
(ns status-im.ui.screens.wallet.components.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [reagent.core :as reagent]
|
||||
(:require [clojure.string :as string]
|
||||
[reagent.core :as reagent]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.screens.wallet.components.styles :as styles]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.animation :as animation]
|
||||
[status-im.ui.components.bottom-buttons.view :as bottom-buttons]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.list.styles :as list.styles]
|
||||
[status-im.ui.components.list-selection :as list-selection]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.screens.wallet.components :as components]
|
||||
[status-im.ui.screens.wallet.components.animations :as animations]
|
||||
[status-im.ui.screens.wallet.components.styles :as styles]
|
||||
[status-im.ui.screens.wallet.choose-recipient.views :as choose-recipient]
|
||||
[status-im.ui.screens.wallet.main.views :as main]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.utils.ethereum.tokens :as tokens]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ui.screens.wallet.components.animations :as animations]
|
||||
[status-im.ui.screens.wallet.main.views :as main]
|
||||
[status-im.ui.screens.wallet.utils :as wallet.utils]))
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(views/defview tooltip [label & [style]]
|
||||
(views/letsubs [bottom-value (animation/create-value 16)
|
||||
(views/defview tooltip [label]
|
||||
(views/letsubs [bottom-value (animation/create-value -30)
|
||||
opacity-value (animation/create-value 0)]
|
||||
{:component-did-mount (animations/animate-tooltip bottom-value opacity-value)}
|
||||
[react/view styles/tooltip-container
|
||||
[react/animated-view {:style (merge (styles/tooltip-animated bottom-value opacity-value) style)}
|
||||
[react/animated-view {:style (styles/tooltip-animated bottom-value opacity-value)}
|
||||
[react/view styles/tooltip-text-container
|
||||
[react/text {:style styles/tooltip-text} label]]
|
||||
[vector-icons/icon :icons/tooltip-triangle {:color :white :style styles/tooltip-triangle}]]]))
|
||||
|
||||
(defn amount-input []
|
||||
(let [active? (reagent/atom false)]
|
||||
(fn [& [{:keys [input-options style error disabled?]}]]
|
||||
(let [{:keys [on-focus on-blur]} input-options]
|
||||
[react/view components.styles/flex
|
||||
[react/text {:style styles/label} (i18n/label :t/amount)]
|
||||
[react/view styles/amount-text-input-container
|
||||
[react/view (merge (styles/amount-container @active?) (if disabled? styles/container-disabled style))
|
||||
[react/text-input
|
||||
(merge
|
||||
{:style styles/text-input}
|
||||
(if disabled?
|
||||
{:editable false}
|
||||
{:keyboard-type :numeric
|
||||
:placeholder (i18n/label :t/amount-placeholder)
|
||||
:placeholder-text-color components.styles/color-white-transparent
|
||||
:selection-color components.styles/color-white
|
||||
:style styles/text-input
|
||||
:on-focus #(do (reset! active? true)
|
||||
(when on-focus (on-focus)))
|
||||
:on-blur #(do (reset! active? false)
|
||||
(when on-blur (on-blur)))})
|
||||
(dissoc input-options :on-focus :on-blur))]]
|
||||
(when-not (nil? error)
|
||||
[tooltip error])]]))))
|
||||
|
||||
(views/defview view-asset [symbol]
|
||||
(defn view-asset [symbol]
|
||||
[react/view
|
||||
[react/text {:style styles/label}
|
||||
(i18n/label :t/wallet-asset)]
|
||||
[react/view styles/asset-container
|
||||
[react/view styles/asset-container-read-only
|
||||
[react/text {:style styles/asset-text}
|
||||
(name symbol)]]])
|
||||
|
||||
|
@ -76,11 +56,9 @@
|
|||
[list/item-image icon]
|
||||
[list/item-content
|
||||
[react/view {:flex-direction :row}
|
||||
[react/text {:style (merge styles/text-list-primary-content)
|
||||
:number-of-lines 1}
|
||||
[react/text {:style styles/text-list-primary-content}
|
||||
name]
|
||||
[react/text {:uppercase? true
|
||||
:number-of-lines 1}
|
||||
[react/text {:uppercase? true}
|
||||
(clojure.core/name symbol)]]
|
||||
[list/item-secondary (wallet.utils/format-amount (symbol balance) decimals)]]]]])
|
||||
|
||||
|
@ -88,14 +66,11 @@
|
|||
(views/letsubs [network [:network]
|
||||
visible-tokens [:wallet.settings/visible-tokens]
|
||||
balance [:balance]]
|
||||
[react/view components.styles/flex
|
||||
[status-bar/status-bar {}]
|
||||
[toolbar/toolbar {}
|
||||
[toolbar/nav-clear-text (i18n/label :t/done)]
|
||||
[toolbar/content-title (i18n/label :t/wallet-assets)]]
|
||||
[react/view {:style components.styles/flex}
|
||||
[list/flat-list {:data (concat [tokens/ethereum] (main/current-tokens visible-tokens network))
|
||||
:render-fn #(render-token % balance type)}]]]))
|
||||
[components/simple-screen (i18n/label :t/wallet-assets)
|
||||
[react/view {:style (assoc components.styles/flex :background-color :white)}
|
||||
[list/flat-list {:default-separator? true
|
||||
:data (concat [tokens/ethereum] (main/current-tokens visible-tokens network))
|
||||
:render-fn #(render-token % balance type)}]]]))
|
||||
|
||||
(defn send-assets []
|
||||
[assets :send])
|
||||
|
@ -109,54 +84,115 @@
|
|||
:request :wallet-request-assets
|
||||
(throw (str "Unknown type: " k))))
|
||||
|
||||
(views/defview choose-asset [{:keys [type symbol]}]
|
||||
(views/defview asset-selector [{:keys [disabled? type symbol]}]
|
||||
(views/letsubs [balance [:balance]
|
||||
network [:network]]
|
||||
(let [{:keys [name icon decimals]} (tokens/asset-for (ethereum/network->chain-keyword network) symbol)]
|
||||
[react/view
|
||||
[react/text {:style styles/label}
|
||||
(i18n/label :t/wallet-asset)]
|
||||
[react/touchable-highlight {:style styles/asset-container
|
||||
:on-press #(re-frame/dispatch [:navigate-to (type->view type)])}
|
||||
[react/view styles/asset-content-container
|
||||
[list/item-image (assoc icon :style styles/asset-icon :image-style {:width 32 :height 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}
|
||||
(clojure.core/name symbol)]]
|
||||
[react/text {:style (merge styles/text-secondary-content styles/asset-label)}
|
||||
(str (wallet.utils/format-amount (symbol balance) decimals))]]
|
||||
[vector-icons/icon :icons/forward {:color :white}]]]])))
|
||||
[components/cartouche {:disabled? disabled? :on-press #(re-frame/dispatch [:navigate-to (type->view type)])}
|
||||
(i18n/label :t/wallet-asset)
|
||||
[react/view styles/asset-content-container
|
||||
[list/item-image (assoc icon :style styles/asset-icon :image-style {:width 32 :height 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}
|
||||
(clojure.core/name symbol)]]
|
||||
[react/text {:style (merge styles/text-secondary-content styles/asset-label)}
|
||||
(str (wallet.utils/format-amount (symbol balance) decimals))]]]])))
|
||||
|
||||
(defn choose-recipient-content [{:keys [address name on-press style]}]
|
||||
(let [address? (and (not (nil? address)) (not= address ""))]
|
||||
[react/view
|
||||
[react/text {:style styles/label} (i18n/label :t/recipient)]
|
||||
[react/view (merge styles/recipient-container
|
||||
(when-not on-press styles/container-disabled)
|
||||
style)
|
||||
(when name
|
||||
[react/view styles/recipient-name-container
|
||||
[react/text {:style (styles/participant true)
|
||||
:number-of-lines 1}
|
||||
name]])
|
||||
(defn- recipient-address [address]
|
||||
[react/text {:style (merge styles/recipient-address (when-not address styles/recipient-no-address))}
|
||||
(or (ethereum/normalized-address address) (i18n/label :t/specify-recipient))])
|
||||
|
||||
(views/defview recipient-contact [address name]
|
||||
(views/letsubs [contact [:contact/by-address address]]
|
||||
(let [address? (and (not (nil? address)) (not= address ""))]
|
||||
[react/view styles/recipient-container
|
||||
[react/view styles/recipient-icon
|
||||
[chat-icon/chat-icon (:photo-path contact) {:size list.styles/image-size}]]
|
||||
[react/view styles/recipient-name
|
||||
[react/text {:style (styles/participant true)
|
||||
:number-of-lines 1}
|
||||
name]
|
||||
[react/text {:style (styles/participant (and (not name) address?))}
|
||||
(ethereum/normalized-address address)]]])))
|
||||
|
||||
(defn render-contact [contact]
|
||||
[list/touchable-item #(re-frame/dispatch [:wallet/fill-request-from-contact contact])
|
||||
[list/item
|
||||
[chat-icon/chat-icon (:photo-path contact) {:size list.styles/image-size}]
|
||||
[list/item-content
|
||||
[list/item-primary (:name contact)]
|
||||
[react/text {:style list.styles/secondary-text}
|
||||
(ethereum/normalized-address (:address contact))]]]])
|
||||
|
||||
(views/defview recent-recipients []
|
||||
(views/letsubs [contacts [:contacts-filtered :all-added-people-contacts]]
|
||||
[components/simple-screen
|
||||
(i18n/label :t/recipient)
|
||||
[react/view styles/recent-recipients
|
||||
[list/flat-list {:data contacts
|
||||
:render-fn render-contact}]]]))
|
||||
|
||||
(defn contact-code []
|
||||
(let [content (reagent/atom nil)]
|
||||
(fn []
|
||||
[react/view components.styles/flex
|
||||
[react/text {:style (styles/participant (and (not name) address?))
|
||||
:number-of-lines 1
|
||||
:ellipsizeMode :middle}
|
||||
(if address? address "Choose recipient...")]]
|
||||
(when on-press
|
||||
[vector-icons/icon :icons/forward {:color :white}])]]))
|
||||
[components/simple-screen
|
||||
(i18n/label :t/recipient)
|
||||
[react/view components.styles/flex
|
||||
[components/cartouche {}
|
||||
(i18n/label :t/recipient)
|
||||
[components/text-input {:multiline true
|
||||
:placeholder (i18n/label :t/recipient-code)
|
||||
:on-change-text #(reset! content %)}]]
|
||||
[bottom-buttons/bottom-button
|
||||
[button/button {:disabled? (string/blank? @content)
|
||||
:on-press #(re-frame/dispatch [:wallet/fill-request-from-url @content])}
|
||||
(i18n/label :t/done)]]]]])))
|
||||
|
||||
(defn choose-recipient [{:keys [on-press] :as m}]
|
||||
(if on-press
|
||||
[react/touchable-highlight {:on-press on-press}
|
||||
[react/view ;; TODO(jeluard) remove extra view when migrating to latest RN
|
||||
[choose-recipient-content m]]]
|
||||
[react/view
|
||||
[choose-recipient-content m]]))
|
||||
(defn recipient-qr-code []
|
||||
[choose-recipient/choose-recipient])
|
||||
|
||||
(defn- request-camera-permissions []
|
||||
(re-frame/dispatch [:request-permissions [:camera]
|
||||
#(re-frame/dispatch [:navigate-to :recipient-qr-code])]))
|
||||
|
||||
(defn- on-choose-recipient []
|
||||
(list-selection/show {:title (i18n/label :t/wallet-choose-recipient)
|
||||
:options [{:label (i18n/label :t/recent-recipients)
|
||||
:action #(re-frame/dispatch [:navigate-to :recent-recipients])}
|
||||
{:label (i18n/label :t/scan-qr)
|
||||
:action request-camera-permissions}
|
||||
{:label (i18n/label :t/enter-contact-code)
|
||||
:action #(re-frame/dispatch [:navigate-to :contact-code])}]}))
|
||||
|
||||
(defn recipient-selector [{:keys [name address disabled?]}]
|
||||
[components/cartouche {:on-press on-choose-recipient :disabled? disabled? :icon :icons/dots-horizontal}
|
||||
(i18n/label :t/wallet-choose-recipient)
|
||||
(if name
|
||||
[recipient-contact address name]
|
||||
[recipient-address address])])
|
||||
|
||||
(defn- amount-input [{:keys [input-options disabled?]}]
|
||||
[react/view components.styles/flex
|
||||
[components/text-input
|
||||
(merge
|
||||
(if disabled?
|
||||
{:editable false}
|
||||
{:keyboard-type :numeric
|
||||
:placeholder (i18n/label :t/amount-placeholder)
|
||||
:style components.styles/flex})
|
||||
input-options)]])
|
||||
|
||||
(defn amount-selector [{:keys [error disabled?] :as m}]
|
||||
[react/view
|
||||
[components/cartouche {:disabled? disabled?}
|
||||
(i18n/label :t/amount)
|
||||
[amount-input m]]
|
||||
(when error
|
||||
[tooltip error])])
|
||||
|
||||
(defn separator []
|
||||
[react/view styles/separator])
|
||||
|
@ -165,15 +201,3 @@
|
|||
[react/text {:style styles/button-text
|
||||
:font (if platform/android? :medium :default)
|
||||
:uppercase? (get-in platform/platform-specific [:uppercase?])} label])
|
||||
|
||||
(defn change-display [change]
|
||||
(let [pos-change? (or (pos? change) (zero? change))]
|
||||
[react/view {:style (if pos-change?
|
||||
styles/today-variation-container-positive
|
||||
styles/today-variation-container-negative)}
|
||||
[react/text {:style (if pos-change?
|
||||
styles/today-variation-positive
|
||||
styles/today-variation-negative)}
|
||||
(if change
|
||||
(str (when pos-change? "+") change "%")
|
||||
"-%")]]))
|
||||
|
|
|
@ -38,4 +38,4 @@
|
|||
{:error (i18n/label :t/validation-amount-is-too-precise) :value value}
|
||||
|
||||
:else
|
||||
{:value value}))))
|
||||
{:value value}))))
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
{:background-color colors/blue})
|
||||
|
||||
(def action
|
||||
{:background-color colors/white-light-transparent
|
||||
{:background-color colors/white-transparent
|
||||
:border-radius 50})
|
||||
|
||||
(def action-label
|
||||
|
@ -74,7 +74,7 @@
|
|||
|
||||
(def action-separator
|
||||
{:height 1
|
||||
:background-color colors/white-transparent
|
||||
:background-color colors/white-light-transparent
|
||||
:margin-left 70})
|
||||
|
||||
;; Assets section
|
||||
|
@ -116,6 +116,3 @@
|
|||
{:font-size 16
|
||||
:color styles/color-gray4
|
||||
:margin-left 6})
|
||||
|
||||
(defn asset-border [color]
|
||||
{:border-color color :border-width 1 :border-radius 32})
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
(: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.colors :as colors]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
|
@ -18,12 +17,12 @@
|
|||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(defn toolbar-view []
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar :flat? true}
|
||||
nil
|
||||
[toolbar/content-wrapper]
|
||||
[toolbar/actions
|
||||
[(assoc (act/opts [{:text (i18n/label :t/wallet-manage-assets)
|
||||
:value #(re-frame/dispatch [:navigate-to-modal :wallet-settings-assets])}])
|
||||
[(assoc (act/opts [{:label (i18n/label :t/wallet-manage-assets)
|
||||
:action #(re-frame/dispatch [:navigate-to-modal :wallet-settings-assets])}])
|
||||
:icon-opts {:color :white})]]])
|
||||
|
||||
(defn- total-section [usd-value syncing? error-message]
|
||||
|
@ -38,23 +37,23 @@
|
|||
[react/text {:style styles/total-balance-currency} (i18n/label :t/usd-currency)]]
|
||||
[react/text {:style styles/total-value} (i18n/label :t/wallet-total-value)]]])
|
||||
|
||||
(defn- render-action [{:keys [name icon action]}]
|
||||
(defn- render-action [{:keys [label icon action]}]
|
||||
[react/touchable-highlight {:on-press action}
|
||||
[react/view
|
||||
[list/item
|
||||
[list/item-icon {:icon icon :style styles/action :icon-opts {:color :white}}]
|
||||
[list/item-primary-only {:style styles/action-label}
|
||||
name]
|
||||
label]
|
||||
list/item-icon-forward]]])
|
||||
|
||||
(def actions
|
||||
[{:name (i18n/label :t/send-transaction)
|
||||
[{:label (i18n/label :t/send-transaction)
|
||||
:icon :icons/arrow-right
|
||||
:action #(re-frame/dispatch [:navigate-to :wallet-send-transaction])}
|
||||
{:name (i18n/label :t/receive-transaction)
|
||||
{:label (i18n/label :t/receive-transaction)
|
||||
:icon :icons/arrow-left
|
||||
:action #(re-frame/dispatch [:navigate-to :wallet-request-transaction])}
|
||||
{:name (i18n/label :t/transaction-history)
|
||||
{:label (i18n/label :t/transaction-history)
|
||||
:icon :icons/transaction-history
|
||||
:action #(re-frame/dispatch [:navigate-to :transactions-history])}])
|
||||
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
{:flex 1
|
||||
:align-items :center})
|
||||
|
||||
(defstyle qr-container
|
||||
(def qr-container
|
||||
{:margin-top 8
|
||||
:padding 16
|
||||
:background-color styles/color-white
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
:border-radius 8})
|
||||
|
||||
(def share-icon-container
|
||||
{:margin-right 8})
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
(ns status-im.ui.screens.wallet.request.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.common.common :as common]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.qr-code-viewer.views :as components.qr-code-viewer]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.qr-code-viewer.views :as qr-code-viewer]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||
[status-im.ui.components.common.common :as common]
|
||||
[status-im.ui.components.icons.vector-icons :as vi]
|
||||
[status-im.ui.screens.wallet.components.views :as components]
|
||||
[status-im.ui.screens.wallet.request.styles :as styles]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.utils.ethereum.eip681 :as eip681]
|
||||
[status-im.utils.ethereum.tokens :as tokens]))
|
||||
|
||||
(defn toolbar-view []
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar :hide-border? true}
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||
[toolbar/nav-button (actions/back-white actions/default-handler)]
|
||||
[toolbar/content-title {:color :white} (i18n/label :t/request-transaction)]])
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
|||
(views/defview qr-code [amount symbol]
|
||||
(views/letsubs [account [:get-current-account]
|
||||
chain-id [:get-network-id]]
|
||||
[components.qr-code-viewer/qr-code
|
||||
[qr-code-viewer/qr-code
|
||||
(let [address (ethereum/normalized-address (:address account))
|
||||
params {:chain-id chain-id :value amount :symbol (or symbol :ETH)}]
|
||||
{:value (generate-value address params)
|
||||
|
@ -61,22 +61,20 @@
|
|||
[react/with-activity-indicator
|
||||
{:style wallet.styles/qr-code-preview}
|
||||
[qr-code amount symbol]]]]
|
||||
[react/view wallet.styles/amount-container
|
||||
[components/amount-input
|
||||
{:error amount-error
|
||||
:input-options {:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100)))
|
||||
:on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount %])}}]]
|
||||
[react/view wallet.styles/choose-asset-container
|
||||
[components/choose-asset {:type :request
|
||||
:symbol symbol}]]]]
|
||||
[components/amount-selector
|
||||
{:error amount-error
|
||||
:input-options {:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100)))
|
||||
:on-change-text #(re-frame/dispatch [:wallet.request/set-and-validate-amount %])}}]
|
||||
[components/asset-selector {:type :request
|
||||
:symbol symbol}]]]
|
||||
[components/separator]
|
||||
[react/view wallet.styles/buttons-container
|
||||
[react/touchable-highlight {:style wallet.styles/button :disabled true}
|
||||
[react/view (wallet.styles/button-container false)
|
||||
[vi/icon :icons/share {:color :white :container-style styles/share-icon-container}]
|
||||
[vector-icons/icon :icons/share {:color :white :container-style styles/share-icon-container}]
|
||||
[components/button-text (i18n/label :t/share)]]]
|
||||
[react/view components.styles/flex]
|
||||
[react/touchable-highlight {:style wallet.styles/button :disabled (not request-enabled?) :on-press send-request}
|
||||
[react/view (wallet.styles/button-container request-enabled?)
|
||||
[components/button-text (i18n/label :t/send-request)]
|
||||
[vi/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]]))
|
||||
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]]))
|
||||
|
|
|
@ -15,9 +15,7 @@
|
|||
(spec/def ::later? (spec/nilable boolean?))
|
||||
(spec/def ::height double?)
|
||||
(spec/def ::width double?)
|
||||
(spec/def ::camera-dimensions (spec/keys :req-un [::height ::width]))
|
||||
(spec/def ::camera-flashlight #{:on :off})
|
||||
(spec/def ::camera-permitted? boolean?)
|
||||
(spec/def ::in-progress? boolean?)
|
||||
(spec/def ::from-chat? (spec/nilable boolean?))
|
||||
(spec/def ::symbol (spec/nilable keyword?))
|
||||
|
@ -28,6 +26,6 @@
|
|||
(spec/def :wallet/send-transaction (allowed-keys
|
||||
:opt-un [::amount ::to ::to-name ::amount-error ::password
|
||||
::waiting-signal? ::signing? ::id ::later?
|
||||
::camera-dimensions ::camera-flashlight ::in-progress?
|
||||
::wrong-password? ::camera-permitted? ::from-chat? ::symbol ::advanced?
|
||||
::camera-flashlight ::in-progress?
|
||||
::wrong-password? ::from-chat? ::symbol ::advanced?
|
||||
::gas ::gas-price]))
|
||||
|
|
|
@ -255,11 +255,6 @@
|
|||
:signing? false
|
||||
:wrong-password? false)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.send/set-camera-dimensions
|
||||
(fn [{:keys [db]} [_ camera-dimensions]]
|
||||
{:db (assoc-in db [:wallet :send-transaction :camera-dimensions] camera-dimensions)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:wallet.send/set-password
|
||||
(fn [{:keys [db]} [_ password]]
|
||||
|
|
|
@ -1,29 +1,11 @@
|
|||
(ns status-im.ui.screens.wallet.send.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defnstyle defstyle]])
|
||||
(:require [status-im.ui.components.styles :as styles]
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.screens.wallet.components.styles :as wallet.components.styles]))
|
||||
|
||||
(def toolbar
|
||||
{:background-color styles/color-blue5
|
||||
:elevation 0
|
||||
:padding-bottom 10})
|
||||
|
||||
(def toolbar-title-container
|
||||
(def send-transaction-form
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:margin-left 6})
|
||||
|
||||
(def toolbar-title-text
|
||||
{:color styles/color-white
|
||||
:font-size 17
|
||||
:margin-right 4})
|
||||
|
||||
(def toolbar-icon
|
||||
{:width 24
|
||||
:height 24})
|
||||
|
||||
(def toolbar-title-icon
|
||||
(merge toolbar-icon {:opacity 0.4}))
|
||||
:padding-bottom 60})
|
||||
|
||||
(defn animated-sign-panel [bottom-value]
|
||||
{:position :absolute
|
||||
|
@ -34,7 +16,7 @@
|
|||
(defn sign-panel [opacity-value]
|
||||
{:opacity opacity-value
|
||||
:border-radius 8
|
||||
:background-color :white
|
||||
:background-color colors/white
|
||||
:padding-top 12
|
||||
:padding-horizontal 12})
|
||||
|
||||
|
@ -43,12 +25,12 @@
|
|||
:height 36
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:background-color styles/color-light-gray})
|
||||
:background-color colors/gray-lighter})
|
||||
|
||||
(def signing-phrase
|
||||
{:font-size 15
|
||||
:letter-spacing -0.2
|
||||
:color :black})
|
||||
:color colors/black})
|
||||
|
||||
(def signing-phrase-description
|
||||
{:padding-top 8})
|
||||
|
@ -71,13 +53,16 @@
|
|||
:left 0
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:background-color (str styles/color-black "1A")})
|
||||
:background-color (str colors/black "1A")})
|
||||
|
||||
(def empty-text
|
||||
{:text-align :center
|
||||
:margin-top 22
|
||||
:margin-horizontal 92})
|
||||
|
||||
(def advanced-cartouche
|
||||
{:padding-bottom 50})
|
||||
|
||||
(def advanced-button
|
||||
{:flex-direction :row
|
||||
:background-color styles/color-blue6
|
||||
|
@ -89,63 +74,43 @@
|
|||
{:align-items :center})
|
||||
|
||||
(def advanced-wrapper
|
||||
{:margin-horizontal 15})
|
||||
{:margin-top 24
|
||||
:margin-bottom 16})
|
||||
|
||||
(def advanced-options-wrapper
|
||||
{:height 52
|
||||
:background-color styles/color-white-transparent-3
|
||||
:border-radius 4
|
||||
:margin-top 16
|
||||
:margin-bottom 16
|
||||
:align-items :center
|
||||
:flex-direction :row
|
||||
:padding-vertical 14
|
||||
:padding-right 8
|
||||
:ios {:border-radius 8}
|
||||
:android {:border-radius 4}})
|
||||
{:align-items :center
|
||||
:flex-direction :row})
|
||||
|
||||
(def advanced-options-text-wrapper
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 15})
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-vertical 15})
|
||||
|
||||
(def advanced-label
|
||||
{:text-align-vertical :center
|
||||
:margin-left 4})
|
||||
|
||||
(def advanced-fees-text
|
||||
{:color styles/color-white})
|
||||
{:color colors/white})
|
||||
|
||||
(def advanced-fees-details-text
|
||||
{:color styles/color-white-transparent})
|
||||
{:color colors/white-lighter-transparent})
|
||||
|
||||
(def transaction-fee-block-wrapper
|
||||
{:flex-direction :row
|
||||
:margin-top 15})
|
||||
|
||||
(def transaction-fee-column-wrapper
|
||||
{:flex 0.5
|
||||
:margin-horizontal 15})
|
||||
|
||||
(def transaction-fee-bubble
|
||||
(merge advanced-options-wrapper
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 15}))
|
||||
|
||||
(def transaction-fee-bubble-read-only
|
||||
(merge transaction-fee-bubble
|
||||
{:background-color styles/color-blue6}))
|
||||
{:flex-direction :row})
|
||||
|
||||
(def transaction-fee-info
|
||||
{:margin 15})
|
||||
|
||||
(def transaction-fee-input
|
||||
{:flex 1
|
||||
:keyboard-type :numeric
|
||||
{:keyboard-type :numeric
|
||||
:auto-capitalize "none"
|
||||
:placeholder "0.000"
|
||||
:placeholder-text-color styles/color-white-transparent
|
||||
:selection-color :white
|
||||
:style wallet.components.styles/text-input})
|
||||
:placeholder-text-color colors/white-lighter-transparent
|
||||
:selection-color colors/white
|
||||
:style wallet.components.styles/text-input})
|
||||
|
||||
(def sign-buttons
|
||||
{:background-color colors/blue
|
||||
:padding-vertical 8})
|
||||
|
|
|
@ -31,21 +31,11 @@
|
|||
(fn [send-transaction]
|
||||
(:advanced? send-transaction)))
|
||||
|
||||
(re-frame/reg-sub :wallet.send/camera-dimensions
|
||||
:<- [::send-transaction]
|
||||
(fn [send-transaction]
|
||||
(:camera-dimensions send-transaction)))
|
||||
|
||||
(re-frame/reg-sub :wallet.send/camera-flashlight
|
||||
:<- [::send-transaction]
|
||||
(fn [send-transaction]
|
||||
(:camera-flashlight send-transaction)))
|
||||
|
||||
(re-frame/reg-sub :wallet.send/camera-permitted?
|
||||
:<- [::send-transaction]
|
||||
(fn [send-transaction]
|
||||
(:camera-permitted? send-transaction)))
|
||||
|
||||
(re-frame/reg-sub :wallet.send/wrong-password?
|
||||
:<- [::send-transaction]
|
||||
(fn [send-transaction]
|
||||
|
@ -79,7 +69,7 @@
|
|||
(re-frame/reg-sub :wallet.send/transaction
|
||||
:<- [::send-transaction]
|
||||
:<- [:balance]
|
||||
(fn [[{:keys [amount to symbol] :as transaction} balance]]
|
||||
(fn [[{:keys [amount symbol] :as transaction} balance]]
|
||||
(assoc transaction :sufficient-funds? (or (nil? amount)
|
||||
(money/sufficient-funds? amount (get balance symbol))))))
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.animation :as animation]
|
||||
[status-im.ui.components.camera :as camera]
|
||||
[status-im.ui.components.bottom-buttons.view :as bottom-buttons]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.components.common.common :as common]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
|
@ -13,11 +13,11 @@
|
|||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.ui.screens.wallet.components.styles :as wallet.components.styles]
|
||||
[status-im.ui.screens.wallet.components.views :as components]
|
||||
[status-im.ui.screens.wallet.components :as wallet.components]
|
||||
[status-im.ui.screens.wallet.send.animations :as send.animations]
|
||||
[status-im.ui.screens.wallet.send.styles :as send.styles]
|
||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.utils.utils :as utils])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
|
@ -56,16 +56,15 @@
|
|||
;; "Cancel" and "Sign Transaction >" buttons, signing with password
|
||||
(defview signing-buttons [cancel-handler sign-handler in-progress?]
|
||||
(letsubs [sign-enabled? [:wallet.send/sign-password-enabled?]]
|
||||
[react/view wallet.styles/buttons-container
|
||||
[react/touchable-highlight {:style wallet.styles/button :on-press cancel-handler}
|
||||
[react/view (wallet.styles/button-container true)
|
||||
[components/button-text (i18n/label :t/cancel)]]]
|
||||
[react/view components.styles/flex]
|
||||
[react/touchable-highlight {:style wallet.styles/button :on-press sign-handler}
|
||||
[react/view (wallet.styles/button-container sign-enabled?)
|
||||
(when in-progress? [react/activity-indicator {:animating? true}])
|
||||
[components/button-text (i18n/label :t/transactions-sign-transaction)]
|
||||
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
|
||||
[bottom-buttons/bottom-buttons
|
||||
send.styles/sign-buttons
|
||||
[button/button {:style components.styles/flex
|
||||
:on-press cancel-handler}
|
||||
(i18n/label :t/cancel)]
|
||||
[button/button {:style (wallet.styles/button-container sign-enabled?)
|
||||
:on-press sign-handler}
|
||||
(i18n/label :t/transactions-sign-transaction)
|
||||
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]))
|
||||
|
||||
(defn- sign-enabled? [amount-error to amount]
|
||||
(and
|
||||
|
@ -75,46 +74,30 @@
|
|||
|
||||
;; "Sign Later" and "Sign Transaction >" buttons
|
||||
(defn- sign-buttons [amount-error to amount sufficient-funds? sign-later-handler]
|
||||
(let [sign-enabled? (sign-enabled? amount-error to amount)
|
||||
(let [sign-enabled? (sign-enabled? amount-error to amount)
|
||||
immediate-sign-enabled? (and sign-enabled? sufficient-funds?)]
|
||||
[react/view wallet.styles/buttons-container
|
||||
[bottom-buttons/bottom-buttons
|
||||
send.styles/sign-buttons
|
||||
(when sign-enabled?
|
||||
[react/touchable-highlight {:style wallet.styles/button :on-press sign-later-handler}
|
||||
[react/view (wallet.styles/button-container sign-enabled?)
|
||||
[components/button-text (i18n/label :t/transactions-sign-later)]]])
|
||||
[react/view components.styles/flex]
|
||||
[react/touchable-highlight {:style wallet.styles/button
|
||||
:on-press (when immediate-sign-enabled? #(re-frame/dispatch [:wallet.send/set-signing? true]))}
|
||||
[react/view (wallet.styles/button-container immediate-sign-enabled?)
|
||||
[components/button-text (i18n/label :t/transactions-sign-transaction)]
|
||||
[vector-icons/icon :icons/forward {:color :white :container-style wallet.styles/forward-icon-container}]]]]))
|
||||
[button/button {:style components.styles/flex
|
||||
:on-press sign-later-handler}
|
||||
(i18n/label :t/transactions-sign-later)])
|
||||
[button/button {:style components.styles/flex
|
||||
:disabled? (not immediate-sign-enabled?)
|
||||
:on-press #(re-frame/dispatch [:wallet.send/set-signing? true])
|
||||
:text-style {:color :white}}
|
||||
(i18n/label :t/transactions-sign-transaction)
|
||||
[vector-icons/icon :icons/forward {:color (if immediate-sign-enabled? :white :gray) :container-style wallet.styles/forward-icon-container}]]]))
|
||||
|
||||
(defn- request-camera-permissions []
|
||||
(when platform/android?
|
||||
(re-frame/dispatch [:request-permissions [:camera]]))
|
||||
(camera/request-access
|
||||
(fn [permitted?]
|
||||
(re-frame/dispatch [:set-in [:wallet :send-transaction :camera-permitted?] permitted?])
|
||||
(re-frame/dispatch [:navigate-to :choose-recipient]))))
|
||||
(defn handler [discard?]
|
||||
(if discard?
|
||||
#(re-frame/dispatch [:wallet/discard-transaction-navigate-back])
|
||||
act/default-handler))
|
||||
|
||||
(defn- toolbar-modal [from-chat?]
|
||||
(defn- toolbar [discard? action title]
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||
[toolbar/nav-button (act/close-white (if from-chat?
|
||||
#(re-frame/dispatch [:wallet/discard-transaction-navigate-back])
|
||||
act/default-handler))]
|
||||
[toolbar/content-title {:color :white} (i18n/label :t/send-transaction)]])
|
||||
|
||||
(defn- toolbar-view [signing?]
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||
[toolbar/nav-button (act/back-white (if signing?
|
||||
#(re-frame/dispatch [:wallet/discard-transaction-navigate-back])
|
||||
act/default-handler))]
|
||||
[toolbar/content-title {:color :white} (i18n/label :t/send-transaction)]])
|
||||
|
||||
(defn- transaction-fee-toolbar []
|
||||
[toolbar/toolbar {:style wallet.styles/toolbar}
|
||||
[toolbar/nav-button (act/close-white #(re-frame/dispatch [:wallet/discard-transaction-navigate-back]))]
|
||||
[toolbar/content-title {:color :white} (i18n/label :t/wallet-transaction-fee)]])
|
||||
[toolbar/nav-button (action (handler discard?))]
|
||||
[toolbar/content-title {:color :white} title]])
|
||||
|
||||
(defn- max-fee [gas gas-price]
|
||||
(when (and gas gas-price)
|
||||
|
@ -125,109 +108,83 @@
|
|||
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
||||
[react/view components.styles/flex
|
||||
[status-bar/status-bar {:type :modal-wallet}]
|
||||
[transaction-fee-toolbar]
|
||||
[react/view send.styles/transaction-fee-block-wrapper
|
||||
[react/view send.styles/transaction-fee-column-wrapper
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(i18n/label :t/gas-limit)]
|
||||
[toolbar true act/close-white
|
||||
(i18n/label :t/wallet-transaction-fee)]
|
||||
[react/view {:flex-direction :row}
|
||||
[wallet.components/cartouche {}
|
||||
(i18n/label :t/gas-limit)
|
||||
[react/text-input (merge send.styles/transaction-fee-input
|
||||
{:on-change-text #(re-frame/dispatch [:wallet.send/set-gas %])
|
||||
:default-value (str (money/to-fixed gas))})]]
|
||||
[wallet.components/cartouche {}
|
||||
(i18n/label :t/gas-price)
|
||||
[react/view send.styles/advanced-options-wrapper
|
||||
[react/text-input (merge send.styles/transaction-fee-input
|
||||
{:on-change-text #(re-frame/dispatch [:wallet.send/set-gas %])
|
||||
:default-value (str (money/to-fixed gas))})]]]
|
||||
|
||||
[react/view send.styles/transaction-fee-column-wrapper
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(i18n/label :t/gas-price)]
|
||||
[react/view send.styles/transaction-fee-bubble
|
||||
[react/text-input (merge send.styles/transaction-fee-input
|
||||
{:on-change-text #(re-frame/dispatch [:wallet.send/set-gas-price (money/->wei :gwei %)])
|
||||
:default-value (str (money/to-fixed (money/wei-> :gwei gas-price)))})]
|
||||
[react/text {:style send.styles/advanced-fees-details-text}
|
||||
"Gwei"]]]]
|
||||
[wallet.components/cartouche-secondary-text
|
||||
(i18n/label :t/gwei)]]]]
|
||||
[react/view send.styles/transaction-fee-info
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(i18n/label :t/wallet-transaction-fee-details)]]
|
||||
[components/separator]
|
||||
[react/view send.styles/transaction-fee-block-wrapper
|
||||
[react/view send.styles/transaction-fee-column-wrapper
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(i18n/label :t/amount)]
|
||||
[react/view send.styles/transaction-fee-bubble-read-only
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(str (money/to-fixed (money/wei->ether amount)))]
|
||||
[react/text {:style send.styles/advanced-fees-details-text}
|
||||
(name symbol)]]]
|
||||
[react/view send.styles/transaction-fee-column-wrapper
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(i18n/label :t/wallet-transaction-total-fee)]
|
||||
[react/view send.styles/transaction-fee-bubble-read-only
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(str (money/to-fixed (max-fee gas gas-price)))]
|
||||
[react/text {:style send.styles/advanced-fees-details-text}
|
||||
"ETH"]]]]]]))
|
||||
[wallet.components/cartouche {:disabled? true}
|
||||
(i18n/label :t/amount)
|
||||
[wallet.components/cartouche-text-content
|
||||
(str (money/to-fixed (money/wei->ether amount)))
|
||||
(name symbol)]]
|
||||
[wallet.components/cartouche {:disabled? true}
|
||||
(i18n/label :t/wallet-transaction-total-fee)
|
||||
[wallet.components/cartouche-text-content
|
||||
(str (money/to-fixed (max-fee gas gas-price)))
|
||||
(i18n/label :t/eth)]]]]]))
|
||||
|
||||
(defn- advanced-options-wrapper [on-press content]
|
||||
(if on-press
|
||||
[react/touchable-highlight {:on-press on-press}
|
||||
[react/view
|
||||
content]]
|
||||
[react/view
|
||||
content]))
|
||||
(defn- advanced-cartouche [{:keys [gas gas-price]} modal?]
|
||||
[react/view send.styles/advanced-cartouche
|
||||
[wallet.components/cartouche {:disabled? modal? :on-press #(re-frame/dispatch [:navigate-to-modal :wallet-transaction-fee])}
|
||||
(i18n/label :t/wallet-transaction-fee)
|
||||
[react/view send.styles/advanced-options-text-wrapper
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(str (money/to-fixed (max-fee gas gas-price)) " " (i18n/label :t/eth))]
|
||||
[react/text {:style send.styles/advanced-fees-details-text}
|
||||
(str (money/to-fixed gas) " * " (money/to-fixed (money/wei-> :gwei gas-price)) (i18n/label :t/gwei))]]]])
|
||||
|
||||
(defn- advanced-options [{:keys [gas gas-price]} on-press]
|
||||
[react/touchable-highlight {:on-press on-press}
|
||||
[react/view
|
||||
[react/text {:style wallet.components.styles/label}
|
||||
(i18n/label :t/wallet-transaction-fee)]
|
||||
[advanced-options-wrapper on-press
|
||||
[react/view send.styles/advanced-options-wrapper
|
||||
[react/view send.styles/advanced-options-text-wrapper
|
||||
[react/text {:style send.styles/advanced-fees-text}
|
||||
(str (money/to-fixed (max-fee gas gas-price)) " ETH")]
|
||||
[react/text {:style send.styles/advanced-fees-details-text}
|
||||
(str (money/to-fixed gas) " * " (money/to-fixed (money/wei-> :gwei gas-price)) "GWEI")]]
|
||||
(when on-press
|
||||
[vector-icons/icon :icons/forward {:color :white}])]]]])
|
||||
(defn- advanced-options [advanced? transaction modal?]
|
||||
[react/view {:style send.styles/advanced-wrapper}
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)])}
|
||||
[react/view {:style send.styles/advanced-button-wrapper}
|
||||
[react/view {:style send.styles/advanced-button}
|
||||
[react/text {:style (merge wallet.components.styles/label send.styles/advanced-label)}
|
||||
(i18n/label :t/wallet-advanced)]
|
||||
[vector-icons/icon (if advanced? :icons/up :icons/down) {:color :white}]]]]
|
||||
(when advanced?
|
||||
[advanced-cartouche transaction modal?])])
|
||||
|
||||
(defn- send-transaction-panel [{:keys [modal? transaction scroll advanced? symbol]}]
|
||||
(let [{:keys [amount amount-error signing? to to-name sufficient-funds? in-progress? from-chat?]} transaction]
|
||||
[react/keyboard-avoiding-view wallet.styles/wallet-modal-container
|
||||
[react/view components.styles/flex
|
||||
[status-bar/status-bar {:type (if modal? :modal-wallet :wallet)}]
|
||||
(if modal? [toolbar-modal from-chat?] [toolbar-view signing?])
|
||||
[toolbar from-chat? (if modal? act/close-white act/back-white)
|
||||
(i18n/label :t/send-transaction)]
|
||||
[common/network-info {:text-color :white}]
|
||||
[react/scroll-view (merge {:keyboardShouldPersistTaps :always} (when-not modal? {:ref #(reset! scroll %)}))
|
||||
[react/view components.styles/flex
|
||||
[react/view wallet.styles/choose-participant-container
|
||||
[components/choose-recipient (merge {:address to
|
||||
:name to-name}
|
||||
(when-not modal?
|
||||
{:on-press request-camera-permissions}))]]
|
||||
[react/view wallet.styles/choose-asset-container
|
||||
(if modal?
|
||||
[components/view-asset symbol]
|
||||
[components/choose-asset {:type :send
|
||||
:symbol symbol}])]
|
||||
[react/view wallet.styles/amount-container
|
||||
[components/amount-input
|
||||
(merge
|
||||
{:error (or amount-error
|
||||
(when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds)))
|
||||
:input-options {:default-value (str (money/wei->ether amount))
|
||||
:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100)))
|
||||
:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount %])}}
|
||||
(when modal?
|
||||
{:disabled? true}))]]
|
||||
[react/view {:style send.styles/advanced-wrapper}
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.send/toggle-advanced (not advanced?)])}
|
||||
[react/view {:style send.styles/advanced-button-wrapper}
|
||||
[react/view {:style send.styles/advanced-button}
|
||||
[react/text {:style (merge wallet.components.styles/label send.styles/advanced-label)}
|
||||
(i18n/label :t/wallet-advanced)]
|
||||
[vector-icons/icon (if advanced? :icons/up :icons/down) {:color :white}]]]]
|
||||
(when advanced?
|
||||
[advanced-options transaction (when-not modal? #(re-frame/dispatch [:navigate-to-modal :wallet-transaction-fee]))])]]]
|
||||
[components/separator]
|
||||
[react/view send.styles/send-transaction-form
|
||||
[components/recipient-selector {:disabled? modal?
|
||||
:address to
|
||||
:name to-name}]
|
||||
[components/asset-selector {:disabled? modal?
|
||||
:type :send
|
||||
:symbol symbol}]
|
||||
[components/amount-selector {:disabled? modal?
|
||||
:error (or amount-error
|
||||
(when-not sufficient-funds? (i18n/label :t/wallet-insufficient-funds)))
|
||||
:input-options {:default-value (str (money/to-fixed (money/wei->ether amount)))
|
||||
:max-length 21
|
||||
:on-focus (fn [] (when @scroll (js/setTimeout #(.scrollToEnd @scroll) 100)))
|
||||
:on-change-text #(re-frame/dispatch [:wallet.send/set-and-validate-amount %])}}]
|
||||
[advanced-options advanced? transaction modal?]]]
|
||||
(if signing?
|
||||
[signing-buttons
|
||||
#(re-frame/dispatch (if modal? [:wallet/cancel-signing-modal] [:wallet/discard-transaction]))
|
||||
|
@ -257,5 +214,6 @@
|
|||
[react/view wallet.styles/wallet-modal-container
|
||||
[react/view components.styles/flex
|
||||
[status-bar/status-bar {:type :modal-wallet}]
|
||||
[toolbar-modal false]
|
||||
[toolbar false act/close-white
|
||||
(i18n/label :t/send-transaction)]
|
||||
[react/text {:style send.styles/empty-text} (i18n/label :t/unsigned-transaction-expired)]]])))
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
(ns status-im.ui.screens.wallet.settings.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.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.wallet.styles :as wallet.styles]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.utils.ethereum.tokens :as tokens]
|
||||
[status-im.ui.components.styles :as components.styles]))
|
||||
[status-im.utils.ethereum.tokens :as tokens]))
|
||||
|
||||
|
||||
(defn- render-token [{:keys [symbol name icon]} visible-tokens]
|
||||
[list/item
|
||||
|
@ -21,10 +23,12 @@
|
|||
(defview manage-assets []
|
||||
(letsubs [network [:network]
|
||||
visible-tokens [:wallet.settings/visible-tokens]]
|
||||
[react/view components.styles/flex
|
||||
[toolbar/toolbar {}
|
||||
[toolbar/nav-clear-text (i18n/label :t/done)]
|
||||
[toolbar/content-title (i18n/label :t/wallet-assets)]]
|
||||
[react/view (merge components.styles/flex {:background-color :white})
|
||||
[toolbar/toolbar #_{} {:style wallet.styles/toolbar}
|
||||
[toolbar/nav-text {:style {:color :white}}
|
||||
(i18n/label :t/done)]
|
||||
[toolbar/content-title {:color :white}
|
||||
(i18n/label :t/wallet-assets)]]
|
||||
[react/view {:style components.styles/flex}
|
||||
[list/flat-list {:data (tokens/tokens-for (ethereum/network->chain-keyword network))
|
||||
:render-fn #(render-token % visible-tokens)}]]]))
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
:justify-content :center
|
||||
:ios {:border-radius 20
|
||||
:margin-top 6}
|
||||
:android {:border-radius 4
|
||||
:android {
|
||||
:margin-top 18}
|
||||
:background-color colors/blue})
|
||||
|
||||
|
@ -44,9 +44,12 @@
|
|||
(def wallet-container
|
||||
{:flex 1})
|
||||
|
||||
(defstyle toolbar
|
||||
(def toolbar
|
||||
{:background-color colors/blue})
|
||||
|
||||
(defstyle toolbar-modal
|
||||
{:background-color colors/blue
|
||||
:android {:elevation 0}})
|
||||
:android {:elevation 2}})
|
||||
|
||||
(def buttons-container
|
||||
{:flex-direction :row
|
||||
|
@ -69,19 +72,43 @@
|
|||
{:flex 1
|
||||
:background-color colors/blue})
|
||||
|
||||
(def choose-participant-container
|
||||
{:margin-top 16
|
||||
:margin-horizontal 15})
|
||||
|
||||
(def amount-container
|
||||
{:margin-top 16
|
||||
:margin-bottom 16
|
||||
:margin-horizontal 15
|
||||
:flex-direction :row})
|
||||
|
||||
(def choose-asset-container
|
||||
{:margin-top 16
|
||||
:margin-horizontal 15})
|
||||
(def cartouche-container
|
||||
{:flex 1
|
||||
:margin-top 16
|
||||
:margin-horizontal 16})
|
||||
|
||||
(def cartouche-header
|
||||
{:color colors/white})
|
||||
|
||||
(defn cartouche-content-wrapper [disabled?]
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:margin-top 8
|
||||
:border-radius styles/border-radius
|
||||
:padding-left 14
|
||||
:padding-right 8}
|
||||
(if disabled?
|
||||
{:border-color colors/white-light-transparent
|
||||
:border-width 1}
|
||||
{:background-color colors/white-transparent})))
|
||||
|
||||
(def cartouche-icon-wrapper
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center})
|
||||
|
||||
(def cartouche-primary-text
|
||||
{:color styles/color-white})
|
||||
|
||||
(def cartouche-secondary-text
|
||||
{:color styles/color-white-transparent})
|
||||
|
||||
(def qr-code-preview
|
||||
{:width 256
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
(ns status-im.ui.screens.wallet.transactions.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defnstyle defstyle]])
|
||||
(:require [status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.screens.main-tabs.styles :as tabs.styles]
|
||||
[status-im.utils.platform :as platform]))
|
||||
(:require [status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.screens.main-tabs.styles :as tabs.styles]))
|
||||
|
||||
(def error-container
|
||||
{:align-self :center
|
||||
:justify-content :center
|
||||
:border-radius 4
|
||||
:border-radius 8
|
||||
:padding-vertical 4
|
||||
:flex-direction :row
|
||||
:background-color styles/color-gray9})
|
||||
|
@ -234,4 +234,8 @@
|
|||
:width 4
|
||||
:height 4
|
||||
:border-radius 2
|
||||
:background-color styles/color-cyan})
|
||||
:background-color styles/color-cyan})
|
||||
|
||||
(def filter-container
|
||||
{:flex 1})
|
||||
;:background-color colors/white})
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
(ns status-im.ui.screens.wallet.transactions.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.button.view :as button]
|
||||
[status-im.ui.components.checkbox.view :as checkbox]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.styles :as styles]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.toolbar.view :as toolbar]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.wallet.transactions.styles :as transactions.styles]
|
||||
[status-im.ui.screens.wallet.transactions.styles :as styles]
|
||||
[status-im.ui.screens.wallet.views :as wallet.views]
|
||||
[status-im.utils.money :as money]
|
||||
[status-im.ui.components.styles :as common.styles])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
[status-im.utils.money :as money]))
|
||||
|
||||
(defn on-delete-transaction
|
||||
[{:keys [id]}]
|
||||
|
@ -23,7 +21,7 @@
|
|||
(merge
|
||||
{:icon :icons/filter
|
||||
:handler #(re-frame/dispatch [:navigate-to-modal :wallet-transactions-filter])}
|
||||
(when filter? {:icon-opts {:overlay-style transactions.styles/corner-dot}})))
|
||||
(when filter? {:icon-opts {:overlay-style styles/corner-dot}})))
|
||||
|
||||
(defn- all-checked? [filter-data]
|
||||
(and (every? :checked? (:type filter-data))
|
||||
|
@ -40,7 +38,7 @@
|
|||
|
||||
|
||||
(defn action-buttons [{:keys [id] :as transaction}]
|
||||
[react/view {:style transactions.styles/action-buttons}
|
||||
[react/view {:style styles/action-buttons}
|
||||
[button/primary-button {:style {:margin-right 12}
|
||||
:on-press #(re-frame/dispatch [:wallet/show-sign-transaction id])}
|
||||
(i18n/label :t/transactions-sign)]
|
||||
|
@ -53,17 +51,17 @@
|
|||
(defn- transaction-icon [k background-color color]
|
||||
{:icon k
|
||||
:icon-opts {:color color}
|
||||
:style (transactions.styles/transaction-icon-background background-color)})
|
||||
:style (styles/transaction-icon-background background-color)})
|
||||
|
||||
(defn- transaction-type->icon [k]
|
||||
(case k
|
||||
:unsigned (transaction-icon :icons/dots-horizontal styles/color-gray4-transparent styles/color-gray7)
|
||||
:inbound (transaction-icon :icons/arrow-left styles/color-green-3-light styles/color-green-3)
|
||||
:outbound (transaction-icon :icons/arrow-right styles/color-blue4-transparent styles/color-blue4)
|
||||
(:postponed :pending) (transaction-icon :icons/arrow-right styles/color-gray4-transparent styles/color-gray7)
|
||||
:unsigned (transaction-icon :icons/dots-horizontal components.styles/color-gray4-transparent components.styles/color-gray7)
|
||||
:inbound (transaction-icon :icons/arrow-left components.styles/color-green-3-light components.styles/color-green-3)
|
||||
:outbound (transaction-icon :icons/arrow-right components.styles/color-blue4-transparent components.styles/color-blue4)
|
||||
(:postponed :pending) (transaction-icon :icons/arrow-right components.styles/color-gray4-transparent components.styles/color-gray7)
|
||||
(throw (str "Unknown transaction type: " k))))
|
||||
|
||||
(defn render-transaction [{:keys [hash from-contact to-contact to from type value symbol time-formatted] :as transaction}]
|
||||
(defn render-transaction [{:keys [hash from-contact to-contact to from type value time-formatted] :as transaction}]
|
||||
(let [[label contact address] (if (inbound? type)
|
||||
[(i18n/label :t/from) from-contact from]
|
||||
[(i18n/label :t/to) to-contact to])]
|
||||
|
@ -72,20 +70,20 @@
|
|||
[list/item
|
||||
[list/item-icon (transaction-type->icon (keyword type))]
|
||||
[list/item-content
|
||||
[react/view {:style transactions.styles/amount-time}
|
||||
[react/text {:style transactions.styles/tx-amount
|
||||
[react/view {:style styles/amount-time}
|
||||
[react/text {:style styles/tx-amount
|
||||
:ellipsize-mode "tail"
|
||||
:number-of-lines 1}
|
||||
(money/wei->str :eth value)]
|
||||
[react/text {:style transactions.styles/tx-time}
|
||||
[react/text {:style styles/tx-time}
|
||||
time-formatted]]
|
||||
[react/view {:style transactions.styles/address-row}
|
||||
[react/text {:style transactions.styles/address-label}
|
||||
[react/view {:style styles/address-row}
|
||||
[react/text {:style styles/address-label}
|
||||
label]
|
||||
(when contact
|
||||
[react/text {:style transactions.styles/address-contact}
|
||||
[react/text {:style styles/address-contact}
|
||||
contact])
|
||||
[react/text {:style transactions.styles/address-hash
|
||||
[react/text {:style styles/address-hash
|
||||
:ellipsize-mode "middle"
|
||||
:number-of-lines 1}
|
||||
address]]
|
||||
|
@ -93,10 +91,7 @@
|
|||
[action-buttons transaction])]
|
||||
[list/item-icon {:icon :icons/forward
|
||||
:style {:margin-top 10}
|
||||
:icon-opts transactions.styles/forward}]]]]))
|
||||
|
||||
;; TODO(yenda) hook with re-frame
|
||||
(defn- empty-text [s] [react/text {:style transactions.styles/empty-text} s])
|
||||
:icon-opts styles/forward}]]]]))
|
||||
|
||||
(defn filtered-transaction? [transaction filter-data]
|
||||
(:checked? (some #(when (= (:type transaction) (:id %)) %) (:type filter-data))))
|
||||
|
@ -109,21 +104,23 @@
|
|||
transactions-loading? [:wallet.transactions/transactions-loading?]
|
||||
error-message [:wallet.transactions/error-message?]
|
||||
filter-data [:wallet.transactions/filters]]
|
||||
[react/view styles/flex
|
||||
[react/view components.styles/flex
|
||||
(when error-message
|
||||
[wallet.views/error-message-view transactions.styles/error-container transactions.styles/error-message])
|
||||
[wallet.views/error-message-view styles/error-container styles/error-message])
|
||||
[list/section-list {:sections (map #(update-transactions % filter-data) transactions-history-list)
|
||||
:render-fn render-transaction
|
||||
:empty-component (empty-text (i18n/label :t/transactions-history-empty))
|
||||
:empty-component [react/text {:style styles/empty-text}
|
||||
(i18n/label :t/transactions-history-empty)]
|
||||
:on-refresh #(re-frame/dispatch [:update-transactions])
|
||||
:refreshing (boolean transactions-loading?)}]]))
|
||||
|
||||
(defview unsigned-list []
|
||||
(letsubs [transactions [:wallet.transactions/unsigned-transactions-list]]
|
||||
[react/view {:style styles/flex}
|
||||
[react/view {:style components.styles/flex}
|
||||
[list/flat-list {:data transactions
|
||||
:render-fn render-transaction
|
||||
:empty-component (empty-text (i18n/label :t/transactions-unsigned-empty))}]]))
|
||||
:empty-component [react/text {:style styles/empty-text}
|
||||
(i18n/label :t/transactions-unsigned-empty)]}]]))
|
||||
|
||||
;; Filter history
|
||||
|
||||
|
@ -146,29 +143,29 @@
|
|||
|
||||
(defview filter-history []
|
||||
(letsubs [filter-data [:wallet.transactions/filters]]
|
||||
[react/view styles/flex
|
||||
[react/view styles/filter-container
|
||||
[toolbar/toolbar {}
|
||||
[toolbar/nav-clear-text (i18n/label :t/done)]
|
||||
[toolbar/content-title (i18n/label :t/transactions-filter-title)]
|
||||
[toolbar/text-action {:handler #(re-frame/dispatch [:wallet.transactions/filter-all])
|
||||
:disabled? (all-checked? filter-data)}
|
||||
(i18n/label :t/transactions-filter-select-all)]]
|
||||
[react/view {:style styles/flex}
|
||||
[react/view {:style (merge {:background-color :white} components.styles/flex)}
|
||||
[list/section-list {:sections (wrap-filter-data filter-data)}]]]))
|
||||
|
||||
(defn history-tab [active?]
|
||||
[react/text {:uppercase? true
|
||||
:style (transactions.styles/tab-title active?)}
|
||||
:style (styles/tab-title active?)}
|
||||
(i18n/label :t/transactions-history)])
|
||||
|
||||
(defview unsigned-tab [active?]
|
||||
(letsubs [unsigned-transactions-count [:wallet.transactions/unsigned-transactions-count]]
|
||||
[react/view {:flex-direction :row}
|
||||
[react/text {:style (transactions.styles/tab-title active?)
|
||||
[react/text {:style (styles/tab-title active?)
|
||||
:uppercase? true}
|
||||
(i18n/label :t/transactions-unsigned)]
|
||||
(when (pos? unsigned-transactions-count)
|
||||
[react/text {:style transactions.styles/tab-unsigned-transactions-count}
|
||||
[react/text {:style styles/tab-unsigned-transactions-count}
|
||||
(str " " unsigned-transactions-count)])]))
|
||||
|
||||
(def tabs-list
|
||||
|
@ -178,21 +175,21 @@
|
|||
:content unsigned-tab}])
|
||||
|
||||
(defn tab [view-id content active?]
|
||||
[react/touchable-highlight {:style common.styles/flex
|
||||
[react/touchable-highlight {:style components.styles/flex
|
||||
:disabled active?
|
||||
:on-press #(re-frame/dispatch [:navigation-replace view-id])}
|
||||
[react/view {:style (transactions.styles/tab active?)}
|
||||
[react/view {:style (styles/tab active?)}
|
||||
[content active?]]])
|
||||
|
||||
(defn tabs [current-view-id]
|
||||
[react/view {:style transactions.styles/tabs-container}
|
||||
[react/view {:style styles/tabs-container}
|
||||
(for [{:keys [content view-id]} tabs-list]
|
||||
^{:key view-id} [tab view-id content (= view-id current-view-id)])])
|
||||
|
||||
(defview transactions []
|
||||
(letsubs [current-tab [:get :view-id]
|
||||
filter-data [:wallet.transactions/filters]]
|
||||
[react/view {:style styles/flex}
|
||||
[react/view {:style components.styles/flex}
|
||||
[status-bar/status-bar]
|
||||
[toolbar-view current-tab filter-data]
|
||||
[tabs current-tab]
|
||||
|
@ -209,41 +206,41 @@
|
|||
|
||||
|
||||
(defn details-header [{:keys [value date type symbol]}]
|
||||
[react/view {:style transactions.styles/details-header}
|
||||
[react/view {:style transactions.styles/details-header-icon}
|
||||
[react/view {:style styles/details-header}
|
||||
[react/view {:style styles/details-header-icon}
|
||||
[list/item-icon (transaction-type->icon type)]]
|
||||
[react/view {:style transactions.styles/details-header-infos}
|
||||
[react/text {:style transactions.styles/details-header-value} (pretty-print-asset symbol value)]
|
||||
[react/text {:style transactions.styles/details-header-date} date]]])
|
||||
[react/view {:style styles/details-header-infos}
|
||||
[react/text {:style styles/details-header-value} (pretty-print-asset symbol value)]
|
||||
[react/text {:style styles/details-header-date} date]]])
|
||||
|
||||
(defn progress-bar [progress]
|
||||
[react/view {:style transactions.styles/progress-bar}
|
||||
[react/view {:style (transactions.styles/progress-bar-done progress)}]
|
||||
[react/view {:style (transactions.styles/progress-bar-todo (- 100 progress))}]])
|
||||
[react/view {:style styles/progress-bar}
|
||||
[react/view {:style (styles/progress-bar-done progress)}]
|
||||
[react/view {:style (styles/progress-bar-todo (- 100 progress))}]])
|
||||
|
||||
(defn details-confirmations [confirmations confirmations-progress]
|
||||
[react/view {:style transactions.styles/details-block}
|
||||
[react/view {:style styles/details-block}
|
||||
[progress-bar confirmations-progress]
|
||||
[react/text {:style transactions.styles/details-confirmations-count}
|
||||
[react/text {:style styles/details-confirmations-count}
|
||||
(str confirmations " " (i18n/label :t/confirmations))]
|
||||
[react/text {:style transactions.styles/details-confirmations-helper-text}
|
||||
[react/text {:style styles/details-confirmations-helper-text}
|
||||
(i18n/label :t/confirmations-helper-text)]])
|
||||
|
||||
(defn details-list-row
|
||||
([label value]
|
||||
(details-list-row label value nil))
|
||||
([label value extra-value]
|
||||
[react/view {:style transactions.styles/details-row}
|
||||
[react/text {:style transactions.styles/details-item-label} (i18n/label label)]
|
||||
[react/view {:style transactions.styles/details-item-value-wrapper}
|
||||
[react/text {:style transactions.styles/details-item-value} (str value)]
|
||||
[react/text {:style transactions.styles/details-item-extra-value} (str extra-value)]]]))
|
||||
[react/view {:style styles/details-row}
|
||||
[react/text {:style styles/details-item-label} (i18n/label label)]
|
||||
[react/view {:style styles/details-item-value-wrapper}
|
||||
[react/text {:style styles/details-item-value} (str value)]
|
||||
[react/text {:style styles/details-item-extra-value} (str extra-value)]]]))
|
||||
|
||||
(defn details-list [{:keys [block hash
|
||||
from from-wallet from-contact
|
||||
to to-wallet to-contact
|
||||
gas-limit gas-price-gwei gas-price-eth gas-used cost nonce data]}]
|
||||
[react/view {:style transactions.styles/details-block}
|
||||
[react/view {:style styles/details-block}
|
||||
[details-list-row :t/block block]
|
||||
[details-list-row :t/hash hash]
|
||||
[details-list-row :t/from
|
||||
|
@ -260,23 +257,24 @@
|
|||
[details-list-row :t/data data]])
|
||||
|
||||
(defn details-action [hash url]
|
||||
[(actions/opts [{:text (i18n/label :t/copy-transaction-hash) :value #(react/copy-to-clipboard hash)}
|
||||
{:text (i18n/label :t/open-on-etherscan) :value #(.openURL react/linking url)}])])
|
||||
[(actions/opts [{:label (i18n/label :t/copy-transaction-hash) :action #(react/copy-to-clipboard hash)}
|
||||
{:label (i18n/label :t/open-on-etherscan) :action #(.openURL react/linking url)}])])
|
||||
|
||||
(defview transaction-details []
|
||||
(letsubs [{:keys [hash url type] :as transaction} [:wallet.transactions/transaction-details]
|
||||
confirmations [:wallet.transactions.details/confirmations]
|
||||
confirmations-progress [:wallet.transactions.details/confirmations-progress]]
|
||||
[react/view {:style styles/flex}
|
||||
[react/view {:style components.styles/flex}
|
||||
[status-bar/status-bar]
|
||||
[toolbar/toolbar {}
|
||||
toolbar/default-nav-back
|
||||
[toolbar/content-title (i18n/label :t/transaction-details)]
|
||||
(when transaction [toolbar/actions (details-action hash url)])]
|
||||
(if transaction
|
||||
[react/scroll-view {:style styles/main-container}
|
||||
[react/scroll-view {:style components.styles/main-container}
|
||||
[details-header transaction]
|
||||
[details-confirmations confirmations confirmations-progress]
|
||||
[react/view {:style transactions.styles/details-separator}]
|
||||
[react/view {:style styles/details-separator}]
|
||||
[details-list transaction]]
|
||||
[empty-text (i18n/label :t/unsigned-transaction-expired)])]))
|
||||
[react/text {:style styles/empty-text}
|
||||
(i18n/label :t/unsigned-transaction-expired)])]))
|
||||
|
|
|
@ -6,6 +6,5 @@
|
|||
(defn identicon
|
||||
([hash] (identicon hash default-size))
|
||||
([hash options]
|
||||
(str "data:image/png;base64,"
|
||||
(str (new dependencies/identicon-js hash options)))))
|
||||
|
||||
(str "data:image/png;base64,"
|
||||
(str (new dependencies/identicon-js hash options)))))
|
||||
|
|
|
@ -80,3 +80,10 @@
|
|||
(.catch (or on-error
|
||||
(fn [error]
|
||||
(show-popup "Error" (str error))))))))
|
||||
|
||||
(defn deep-merge
|
||||
"Recursively merge maps"
|
||||
[& maps]
|
||||
(if (every? map? maps)
|
||||
(apply merge-with deep-merge maps)
|
||||
(last maps)))
|
||||
|
|
Loading…
Reference in New Issue