New design for /send and /receive commands

Move markup generation from js side to cljs
Add tx-hash to /send command to display a confirmation
and send user to transaction details screen on icon press

Signed-off-by: Goran Jovic <goranjovic@gmail.com>
This commit is contained in:
Dmitry Novotochinov 2018-06-07 17:00:04 +03:00 committed by Goran Jovic
parent e449e12a2a
commit 221e6fd2b7
No known key found for this signature in database
GPG Key ID: D429D1A9B2EB8A8E
18 changed files with 383 additions and 231 deletions

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#4360DF" fill-rule="evenodd" d="M6.343 10.192l5.66-5.66a.995.995 0 0 1 1.41.004.997.997 0 0 1 .004 1.41l-6.37 6.37a.999.999 0 0 1-1.405.003L2.801 9.48a.993.993 0 0 1 .006-1.408 1 1 0 0 1 1.408-.006l2.128 2.127z"/>
</svg>

After

Width:  |  Height:  |  Size: 321 B

7
resources/icons/dots.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="#4360DF" fill-rule="evenodd">
<circle cx="2.5" cy="8" r="1.5"/>
<circle cx="8" cy="8" r="1.5"/>
<circle cx="13.5" cy="8" r="1.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 268 B

View File

@ -101,105 +101,6 @@ function handleSend(params, context) {
} }
function previewSend(showRecipient, params, context) {
var amountStyle = {
fontSize: 36,
color: "#000000",
height: 40
};
var amount = status.components.view(
{
flexDirection: "column",
alignItems: "flex-end",
maxWidth: 250
},
[status.components.text(
{
style: amountStyle,
numberOfLines: 1,
ellipsizeMode: "tail",
font: "light"
},
status.localizeNumber(params.amount, context.delimiter, context.separator)
)]);
var currency = status.components.view(
{
style: {
flexDirection: "column",
justifyContent: "flex-end",
paddingBottom: 0
}
},
[status.components.text(
{
style: {
color: "#9199a0",
fontSize: 16,
lineHeight: 18,
marginLeft: 7.5
}
},
I18n.t('eth')
)]
);
var amountRow = status.components.view(
{
style: {
flexDirection: "row",
justifyContent: "space-between",
marginTop: 8,
marginBottom: 8
}
},
[amount, currency]
);
var markup = [amountRow];
if (showRecipient
&& params["bot-db"]
&& params["bot-db"]["public"]
&& params["bot-db"]["public"]["recipient"]
&& context["chat"]["group-chat"] === true) {
var recipientRow = status.components.text(
{
style: {
color: "#9199a0",
fontSize: 14,
lineHeight: 18
}
},
I18n.t('send_sending_to') + " " + params["bot-db"]["public"]["recipient"]["name"]
);
markup.push(recipientRow);
}
return {
markup: status.components.view(
{
style: {
flexDirection: "column"
}
},
markup
)
};
}
function shortPreviewSend(params, context) {
return {
markup: status.components.chatPreviewText(
{},
I18n.t('send_title') + ": "
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
+ " ETH"
)
};
}
var personalSend = { var personalSend = {
name: "send", name: "send",
scope: ["global", "personal-chats", "registered", "humans"], scope: ["global", "personal-chats", "registered", "humans"],
@ -210,9 +111,7 @@ var personalSend = {
params: paramsPersonalSend, params: paramsPersonalSend,
validator: validateSend.bind(this, false), validator: validateSend.bind(this, false),
handler: handleSend.bind(this), handler: handleSend.bind(this),
asyncHandler: false, asyncHandler: false
preview: previewSend.bind(this, false),
shortPreview: shortPreviewSend
}; };
var groupSend = { var groupSend = {
@ -225,9 +124,7 @@ var groupSend = {
params: paramsGroupSend, params: paramsGroupSend,
validator: validateSend.bind(this, true), validator: validateSend.bind(this, true),
handler: handleSend.bind(this), handler: handleSend.bind(this),
asyncHandler: false, asyncHandler: false
preview: previewSend.bind(this, true),
shortPreview: shortPreviewSend
}; };
status.command(personalSend); status.command(personalSend);
@ -297,58 +194,6 @@ function handleGroupRequest(params, context) {
}; };
} }
function previewRequest(showRecipient, params, context) {
var amountRow = status.components.text(
{},
I18n.t('request_requesting') + " "
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
+ " ETH"
);
var markup = [amountRow];
if (showRecipient
&& params["bot-db"]
&& params["bot-db"]["public"]
&& params["bot-db"]["public"]["recipient"]
&& context["chat"]["group-chat"] === true) {
var recipientRow = status.components.text(
{
style: {
color: "#9199a0",
fontSize: 14,
lineHeight: 18
}
},
I18n.t('request_requesting_from') + " " + params["bot-db"]["public"]["recipient"]["name"]
);
markup.push(recipientRow);
}
return {
markup: status.components.view(
{
style: {
flexDirection: "column"
}
},
markup
)
};
}
function shortPreviewRequest(params, context) {
return {
markup: status.components.chatPreviewText(
{},
I18n.t('request_requesting') + " "
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
+ " ETH"
)
};
}
function validateRequest(validateRecipient, params) { function validateRequest(validateRecipient, params) {
if (!params["bot-db"]) { if (!params["bot-db"]) {
params["bot-db"] = {}; params["bot-db"] = {};
@ -418,8 +263,6 @@ status.command({
description: I18n.t('request_description'), description: I18n.t('request_description'),
params: paramsPersonalRequest, params: paramsPersonalRequest,
handler: handlePersonalRequest, handler: handlePersonalRequest,
preview: previewRequest.bind(null, false),
shortPreview: shortPreviewRequest,
validator: validateRequest.bind(null, false) validator: validateRequest.bind(null, false)
}); });
@ -432,7 +275,5 @@ status.command({
description: I18n.t('request_description'), description: I18n.t('request_description'),
params: paramsGroupRequest, params: paramsGroupRequest,
handler: handleGroupRequest, handler: handleGroupRequest,
preview: previewRequest.bind(null, true),
shortPreview: shortPreviewRequest,
validator: validateRequest.bind(null, true) validator: validateRequest.bind(null, true)
}); });

View File

@ -9,6 +9,7 @@
[status-im.chat.models.message :as message-model] [status-im.chat.models.message :as message-model]
[status-im.chat.events.commands :as commands-events] [status-im.chat.events.commands :as commands-events]
[status-im.bots.events :as bots-events] [status-im.bots.events :as bots-events]
[status-im.utils.ethereum.tokens :as tokens]
[status-im.ui.components.react :as react-comp] [status-im.ui.components.react :as react-comp]
[status-im.utils.handlers :as handlers])) [status-im.utils.handlers :as handlers]))

View File

@ -22,13 +22,7 @@
(fn [messages] (fn [messages]
(re-frame/dispatch [:chat-received-message/add messages]))) (re-frame/dispatch [:chat-received-message/add messages])))
(defn add-message [{:keys [content] :as message} {:keys [db] :as cofx}] (defn- request-command-message-data [message {:keys [db]}]
(when (message-model/add-to-chat? cofx message)
(if (:command content)
;; we are dealing with received command message, we can't add it right away,
;; we first need to fetch short-preview + preview and add it only after we already have those.
;; note that `request-command-message-data` implicitly wait till jail is ready and
;; calls are made only after that
(commands-events/request-command-message-data (commands-events/request-command-message-data
db message db message
{:data-type :short-preview {:data-type :short-preview
@ -40,7 +34,20 @@
[::received-message [::received-message
(update message :content merge (update message :content merge
{:short-preview short-preview {:short-preview short-preview
:preview preview})])}])}) :preview preview})])}])}))
(defn add-message [{:keys [content] :as message} {:keys [db] :as cofx}]
(when (message-model/add-to-chat? cofx message)
(if (:command content)
;; we are dealing with received command message, we can't add it right away,
;; we first need to fetch short-preview + preview and add it only after we already have those.
;; note that `request-command-message-data` implicitly wait till jail is ready and
;; calls are made only after that
(let [{:keys [command params]} content
tx-hash (:tx-hash params)]
(handlers-macro/merge-fx cofx
(message-model/update-transactions command tx-hash {:with-delay? true})
(request-command-message-data message)))
;; regular non command message, we can add it right away ;; regular non command message, we can add it right away
(message-model/receive message cofx)))) (message-model/receive message cofx))))

View File

@ -10,6 +10,7 @@
[status-im.chat.models.commands :as commands-model] [status-im.chat.models.commands :as commands-model]
[status-im.utils.clocks :as utils.clocks] [status-im.utils.clocks :as utils.clocks]
[status-im.utils.handlers-macro :as handlers-macro] [status-im.utils.handlers-macro :as handlers-macro]
[status-im.utils.money :as money]
[status-im.transport.utils :as transport.utils] [status-im.transport.utils :as transport.utils]
[status-im.transport.message.core :as transport] [status-im.transport.message.core :as transport]
[status-im.transport.message.v1.protocol :as protocol] [status-im.transport.message.v1.protocol :as protocol]
@ -362,7 +363,9 @@
:keys [prefill prefillBotDb] :keys [prefill prefillBotDb]
:as request} :as request}
{:keys [params command handler-data content-type]} {:keys [params command handler-data content-type]}
network] network
prices
tx-hash]
(let [content (if request (let [content (if request
{:request-command request-command {:request-command request-command
;; TODO janherich this is technically not correct, but works for now ;; TODO janherich this is technically not correct, but works for now
@ -371,8 +374,10 @@
:prefill prefill :prefill prefill
:prefill-bot-db prefillBotDb} :prefill-bot-db prefillBotDb}
{:params (cond-> params {:params (cond-> params
(= (:name command) "send") (= (:name command) constants/command-send)
(assoc :network (ethereum/network-names network)))}) (assoc :network (ethereum/network-names network)
:fiat-amount (money/usd-amount (:amount params) prices)
:tx-hash tx-hash))})
content' (assoc content content' (assoc content
:command (:name command) :command (:name command)
:handler-data handler-data :handler-data handler-data
@ -395,16 +400,29 @@
:show? true} :show? true}
chat))) chat)))
;; dispatch :update-transactions to update confirmations count
;; to verify tx initiated with /send command is confirmed
(defn update-transactions [command-name tx-hash {:keys [with-delay?]} _]
(when (and tx-hash
(= command-name constants/command-send))
(cond-> {:dispatch [:update-transactions]}
with-delay?
(assoc :dispatch-later [{:ms constants/command-send-status-update-interval-ms
:dispatch [:update-transactions]}]))))
(defn send-command (defn send-command
[{{:keys [current-public-key chats network] :as db} :db :keys [now] :as cofx} params] [{{:keys [current-public-key chats network prices] :as db} :db :keys [now] :as cofx} params]
(let [{{:keys [handler-data to-message command] :as content} :command chat-id :chat-id} params (let [{{:keys [handler-data to-message command] :as content} :command chat-id :chat-id} params
;; We send commands to deleted chats as well, i.e. signed later transactions ;; We send commands to deleted chats as well, i.e. signed later transactions
chat (or (get chats chat-id) {:chat-id chat-id}) chat (or (get chats chat-id) {:chat-id chat-id})
request (:request handler-data)] request (:request handler-data)
command-name (:name command)
tx-hash (get-in db [:wallet :send-transaction :tx-hash])]
(handlers-macro/merge-fx cofx (handlers-macro/merge-fx cofx
(upsert-and-send (prepare-command-message current-public-key chat now request content network)) (upsert-and-send (prepare-command-message current-public-key chat now request content network prices tx-hash))
(console-events/console-respond-command-messages command handler-data) (console-events/console-respond-command-messages command handler-data)
(requests-events/request-answered chat-id to-message)))) (requests-events/request-answered chat-id to-message)
(update-transactions command-name tx-hash {:with-delay? false}))))
(defn invoke-console-command-handler (defn invoke-console-command-handler
[{:keys [db] :as cofx} {:keys [command] :as command-params}] [{:keys [db] :as cofx} {:keys [command] :as command-params}]

View File

@ -43,21 +43,20 @@
direction (if outgoing :row-reverse :row)] direction (if outgoing :row-reverse :row)]
(merge message-body-base (merge message-body-base
{:flex-direction direction {:flex-direction direction
:width 260 :width 230
:padding-top (message-padding-top message) :padding-top (message-padding-top message)
:align-self align :align-self align
:align-items align}))) :align-items align})))
(def message-timestamp (def message-timestamp
{:font-size 10 {:font-size 10
:align-self :flex-end :align-self :flex-end})
:opacity 0.5})
(defn message-timestamp-text [justify-timestamp? outgoing] (defn message-timestamp-text [justify-timestamp? outgoing]
(merge message-timestamp (merge message-timestamp
{:color (if outgoing colors/wild-blue-yonder colors/gray)} {:color (if outgoing colors/wild-blue-yonder colors/gray)}
(when justify-timestamp? {:position :absolute (when justify-timestamp? {:position :absolute
:bottom 10 :bottom 6
:right 12}))) :right 12})))
(defn message-timestamp-placeholder-text [outgoing] (defn message-timestamp-placeholder-text [outgoing]
@ -106,13 +105,13 @@
(def delivery-view (def delivery-view
{:flex-direction :row {:flex-direction :row
:margin-top 2 :margin-top 4
:opacity 0.5}) :opacity 0.5})
(def delivery-text (def delivery-text
{:color styles/color-gray4 {:color styles/color-gray4
:margin-left 5 :margin-left 5
:font-size 14}) :font-size 12})
(def not-sent-view (def not-sent-view
(assoc delivery-view (assoc delivery-view
@ -163,21 +162,17 @@
(when-not (= content-type constants/content-type-emoji) (when-not (= content-type constants/content-type-emoji)
{:background-color (if outgoing colors/hawkes-blue styles/color-white)}) {:background-color (if outgoing colors/hawkes-blue styles/color-white)})
(when (= content-type constants/content-type-command) (when (= content-type constants/content-type-command)
{:padding-top 10 {:padding-top 12
:padding-bottom 14}))) :padding-bottom 10})))
(def author (def author
{:color styles/color-gray4 {:color styles/color-gray4
:margin-bottom 4 :margin-bottom 4
:font-size 12}) :font-size 12})
(def command-request-view
{:padding-right 16})
(defn command-request-message-view [outgoing] (defn command-request-message-view [outgoing]
{:border-radius 14 {:border-radius 14
:padding-vertical 10 :padding-vertical 4
:padding-right 28
:background-color (if outgoing colors/hawkes-blue styles/color-white)}) :background-color (if outgoing colors/hawkes-blue styles/color-white)})
(def command-request-from-text (def command-request-from-text
@ -214,10 +209,68 @@
:width 12 :width 12
:height 13}) :height 13})
(def command-request-separator-line
{:background-color colors/gray-light
:height 1
:border-radius 8
:margin-top 10})
(def command-request-button
{:align-items :center
:padding-top 8})
(defn command-request-button-text [answered?]
{:font-size 15
:color (if answered? colors/gray colors/blue)})
(def command-request-text-view (def command-request-text-view
{:margin-top 4 {:margin-top 4
:height 14}) :height 14})
(defn command-request-header-text [outgoing]
{:font-size 12
:color (if outgoing colors/wild-blue-yonder colors/gray)})
(def command-request-network-text
{:color colors/red})
(def command-request-row
{:flex-direction :row
:margin-top 6})
(def command-request-fiat-amount-row
{:margin-top 6})
(def command-request-fiat-amount-text
{:font-size 12
:color colors/black})
(def command-request-timestamp-row
{:margin-top 6})
(defn command-request-timestamp-text [outgoing]
{:font-size 12
:color (if outgoing colors/wild-blue-yonder colors/gray)})
(defstyle command-request-amount-text
{:font-size 22
:ios {:letter-spacing -0.5}
:color colors/black})
(defn command-amount-currency-separator [outgoing]
{:opacity 0
:color (if outgoing colors/hawkes-blue colors/white)})
(defn command-request-currency-text [outgoing]
{:font-size 22
:letter-spacing 1
:color (if outgoing colors/wild-blue-yonder colors/gray)})
(def command-request-recipient-text
{:color colors/blue
:font-size 14
:line-height 18})
(def content-command-view (def content-command-view
{:flex-direction :column {:flex-direction :column
:align-items :flex-start}) :align-items :flex-start})
@ -238,6 +291,74 @@
{:margin-top 8 {:margin-top 8
:margin-horizontal 0})) :margin-horizontal 0}))
(def command-send-message-view
{:flex-direction :column
:align-items :flex-start})
(def command-send-amount-row
{:flex-direction :row
:justify-content :space-between})
(def command-send-amount
{:flex-direction :column
:align-items :flex-end
:max-width 250})
(defstyle command-send-amount-text
{:font-size 22
:color colors/blue
:ios {:letter-spacing -0.5}})
(def command-send-currency
{:flex-direction :column
:align-items :flex-end})
(defn command-send-currency-text [outgoing]
{:font-size 22
:margin-left 4
:letter-spacing 1
:color (if outgoing colors/wild-blue-yonder colors/blue-transparent-40)})
(def command-send-fiat-amount
{:flex-direction :column
:justify-content :flex-end
:margin-top 6})
(def command-send-fiat-amount-text
{:font-size 12
:color colors/black})
(def command-send-recipient-text
{:color colors/blue
:font-size 14
:line-height 18})
(defn command-send-timestamp [outgoing]
{:color (if outgoing colors/wild-blue-yonder colors/gray)
:margin-top 6
:font-size 12})
(def command-send-status-container
{:margin-top 6
:flex-direction :row})
(defn command-send-status-icon [outgoing]
{:background-color (if outgoing
colors/blue-darker
colors/blue-transparent)
:width 24
:height 24
:border-radius 16
:padding-top 4
:padding-left 4})
(defstyle command-send-status-text
{:color colors/blue
:android {:margin-top 3}
:ios {:margin-top 4}
:margin-left 6
:font-size 12})
(def audio-container (def audio-container
{:flex-direction :row {:flex-direction :row
:align-items :center}) :align-items :center})

View File

@ -401,3 +401,15 @@
:<- [:get-active-chats] :<- [:get-active-chats]
(fn [chats _] (fn [chats _]
(apply + (map (comp count :unviewed-messages) (vals chats))))) (apply + (map (comp count :unviewed-messages) (vals chats)))))
(reg-sub
:transaction-confirmed?
(fn [db [_ tx-hash]]
(-> (get-in db [:wallet :transactions tx-hash :confirmations] "0")
(js/parseInt)
(pos?))))
(reg-sub
:wallet-transaction-exists?
(fn [db [_ tx-hash]]
(not (nil? (get-in db [:wallet :transactions tx-hash])))))

View File

@ -58,14 +58,64 @@
:font :default} :font :default}
"03:39"]]]) "03:39"]]])
(defview message-content-command (defview send-command-status [tx-hash outgoing]
[{:keys [content params] :as message}] (letsubs [confirmed? [:transaction-confirmed? tx-hash]
(letsubs [command [:get-command (:command-ref content)] tx-exists? [:wallet-transaction-exists? tx-hash]]
network [:network-name]] [react/touchable-highlight {:on-press #(when tx-exists?
(let [preview (:preview content) (re-frame/dispatch [:show-transaction-details tx-hash]))}
{:keys [color] icon-path :icon} command [react/view style/command-send-status-container
send-network (get-in content [:params :network]) [vector-icons/icon (if confirmed? :icons/check :icons/dots)
{:color colors/blue
:container-style (style/command-send-status-icon outgoing)}]
[react/view
[react/text {:style style/command-send-status-text}
(i18n/label (cond
confirmed? :status-confirmed
tx-exists? :status-pending
:else :status-tx-not-found))]]]]))
(defview message-content-command-send
[{:keys [content timestamp-str outgoing group-chat]}]
(letsubs [network [:network-name]]
(let [{{:keys [amount fiat-amount tx-hash] send-network :network} :params} content
recipient-name (get-in content [:params :bot-db :public :recipient])
network-mismatch? (and (seq send-network) (not= network send-network))] network-mismatch? (and (seq send-network) (not= network send-network))]
[react/view style/command-send-message-view
[react/view
[react/view style/command-send-amount-row
[react/view style/command-send-amount
[react/text {:style style/command-send-amount-text
:font :medium}
amount
[react/text {:style (style/command-amount-currency-separator outgoing)}
"."]
[react/text {:style (style/command-send-currency-text outgoing)
:font :default}
(i18n/label :eth)]]]]
(when fiat-amount
[react/view style/command-send-fiat-amount
[react/text {:style style/command-send-fiat-amount-text}
(str "~ " fiat-amount " " (i18n/label :usd-currency))]])
(when (and group-chat
recipient-name)
[react/text {:style style/command-send-recipient-text}
(str
(i18n/label :send-sending-to)
" "
recipient-name)])
[react/view
[react/text {:style (style/command-send-timestamp outgoing)}
(str (i18n/label :sent-at) " " timestamp-str)]]
[send-command-status tx-hash outgoing]
(when network-mismatch?
[react/text send-network])]])))
;; Used for command messages with markup generated on JS side
(defview message-content-command-with-markup
[{:keys [content params]}]
(letsubs [command [:get-command (:command-ref content)]]
(let [preview (:preview content)
{:keys [color] icon-path :icon} command]
[react/view style/content-command-view [react/view style/content-command-view
(when color (when color
[react/view style/command-container [react/view style/command-container
@ -78,21 +128,29 @@
[react/icon icon-path style/command-image]]) [react/icon icon-path style/command-image]])
(if (:markup preview) (if (:markup preview)
;; Markup was defined for command in jail, generate hiccup and render it ;; Markup was defined for command in jail, generate hiccup and render it
(cond-> (commands.utils/generate-hiccup (:markup preview)) (commands.utils/generate-hiccup (:markup preview))
network-mismatch? (conj [react/text send-network]))
;; Display preview if it's defined (as a string), in worst case, render params ;; Display preview if it's defined (as a string), in worst case, render params
[react/text {:style style/command-text [react/text {:style style/command-text
:font :default} :font :default}
(or preview (str params))])]))) (or preview (str params))])])))
(defview message-timestamp [t justify-timestamp? outgoing] (defn message-content-command
[react/text {:style (style/message-timestamp-text justify-timestamp? outgoing)} t]) [message]
(let [{{:keys [command preview]} :content} message]
(if (and (= command constants/command-send)
(nil? preview))
[message-content-command-send message]
[message-content-command-with-markup message])))
(defview message-timestamp [t justify-timestamp? outgoing command?]
(when-not command?
[react/text {:style (style/message-timestamp-text justify-timestamp? outgoing)} t]))
(defn message-view (defn message-view
[{:keys [timestamp-str outgoing] :as message} content {:keys [justify-timestamp?]}] [{:keys [timestamp-str outgoing] :as message} content {:keys [justify-timestamp?]}]
[react/view (style/message-view message) [react/view (style/message-view message)
content content
[message-timestamp timestamp-str justify-timestamp? outgoing]]) [message-timestamp timestamp-str justify-timestamp? outgoing (get-in message [:content :command])]])
(def replacements (def replacements
{"\\*[^*]+\\*" {:font-weight :bold} {"\\*[^*]+\\*" {:font-weight :bold}
@ -381,4 +439,5 @@
(let [incoming-group (and group-chat (not outgoing))] (let [incoming-group (and group-chat (not outgoing))]
[message-content message-body (merge message [message-content message-body (merge message
{:current-public-key current-public-key {:current-public-key current-public-key
:group-chat group-chat
:incoming-group incoming-group})])]]]) :incoming-group incoming-group})])]]])

View File

@ -2,6 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r] [reagent.core :as r]
[status-im.i18n :as i18n]
[status-im.ui.components.react :refer [view [status-im.ui.components.react :refer [view
animated-view animated-view
text text
@ -10,6 +11,8 @@
touchable-highlight]] touchable-highlight]]
[status-im.chat.styles.message.message :as st] [status-im.chat.styles.message.message :as st]
[status-im.chat.models.commands :as commands] [status-im.chat.models.commands :as commands]
[status-im.utils.datetime :as datetime]
[status-im.utils.money :as money]
[status-im.commands.utils :as commands-utils] [status-im.commands.utils :as commands-utils]
[status-im.ui.components.animation :as anim] [status-im.ui.components.animation :as anim]
[taoensso.timbre :as log])) [taoensso.timbre :as log]))
@ -74,24 +77,27 @@
[icon command-icon st/command-request-image])]]))}))) [icon command-icon st/command-request-image])]]))})))
(defview message-content-command-request (defview message-content-command-request
[{:keys [message-id content outgoing] :as message}] [{:keys [message-id content outgoing timestamp timestamp-str group-chat]}]
(letsubs [command [:get-command (:request-command-ref content)] (letsubs [command [:get-command (:request-command-ref content)]
answered? [:is-request-answered? message-id] answered? [:is-request-answered? message-id]
status-initialized? [:get :status-module-initialized?] status-initialized? [:get :status-module-initialized?]
network [:network-name]] network [:network-name]
prices [:prices]]
(let [{:keys [prefill prefill-bot-db prefillBotDb params preview] (let [{:keys [prefill prefill-bot-db prefillBotDb params preview]
text-content :text} content text-content :text} content
command (if (and params command) command (if (and params command)
(merge command {:prefill prefill (merge command {:prefill prefill
:prefill-bot-db (or prefill-bot-db prefillBotDb)}) :prefill-bot-db (or prefill-bot-db prefillBotDb)})
command) command)
request-network (:network params) {:keys [amount] request-network :network} params
recipient-name (get-in params [:bot-db :public :recipient])
usd-amount (money/usd-amount amount prices)
network-mismatch? (and request-network (not= request-network network)) network-mismatch? (and request-network (not= request-network network))
on-press-handler (cond on-press-handler (cond
network-mismatch? nil network-mismatch? nil
(:execute-immediately? command) #(dispatch [:execute-command-immediately command]) (:execute-immediately? command) #(dispatch [:execute-command-immediately command])
(and (not answered?) status-initialized?) #(set-chat-command message-id command))] (and (not answered?) status-initialized?) #(set-chat-command message-id command))]
[view st/command-request-view [view
[touchable-highlight [touchable-highlight
{:on-press on-press-handler} {:on-press on-press-handler}
[view (st/command-request-message-view outgoing) [view (st/command-request-message-view outgoing)
@ -99,12 +105,44 @@
[view (commands-utils/generate-hiccup (:markup preview)) [view (commands-utils/generate-hiccup (:markup preview))
(when network-mismatch? (when network-mismatch?
[text request-network])] [text request-network])]
[text {:style st/style-message-text [view
[view
[text {:style (st/command-request-header-text outgoing)}
(i18n/label :transaction-request)]]
[view st/command-request-row
[text {:style st/command-request-amount-text
:font :medium}
amount
[text {:style (st/command-amount-currency-separator outgoing)}
"."]
[text {:style (st/command-request-currency-text outgoing)
:font :default} :font :default}
(or preview text-content (:content content))])]] (i18n/label :eth)]]]
(when (:request-text command) [view st/command-request-fiat-amount-row
[view st/command-request-text-view [text {:style st/command-request-fiat-amount-text}
[text {:style st/style-sub-text (str "~ " usd-amount " " (i18n/label :usd-currency))]]
:font :default} (when (and group-chat
(:request-text command)]]) recipient-name)
[request-button message-id command on-press-handler]]))) [text {:style st/command-request-recipient-text}
(str
(i18n/label :request-requesting-from)
" "
recipient-name)])
(when network-mismatch?
[text {:style st/command-request-network-text}
(str (i18n/label :on) " " request-network)])
[view st/command-request-timestamp-row
[text {:style (st/command-request-timestamp-text outgoing)}
(str
(datetime/timestamp->mini-date timestamp)
" "
(i18n/label :at)
" "
timestamp-str)]]
(when-not outgoing
[view
[view st/command-request-separator-line]
[view st/command-request-button
[text {:style (st/command-request-button-text answered?)
:on-press on-press-handler}
(i18n/label (if answered? :command-button-sent :command-button-send))]]])])]]])))

View File

@ -14,6 +14,10 @@
(def content-type-placeholder "placeholder") (def content-type-placeholder "placeholder")
(def content-type-emoji "emoji") (def content-type-emoji "emoji")
(def command-send "send")
(def command-request "request")
(def command-send-status-update-interval-ms 60000)
(def min-password-length 6) (def min-password-length 6)
(def max-chat-name-length 20) (def max-chat-name-length 20)
(def response-suggesstion-resize-duration 100) (def response-suggesstion-resize-duration 100)

View File

@ -102,7 +102,9 @@
;;messages ;;messages
:status-sending "Sending..." :status-sending "Sending..."
:status-pending "Pending" :status-pending "Pending"
:status-confirmed "Confirmed"
:status-sent "Sent" :status-sent "Sent"
:status-tx-not-found "TX not found"
:status-seen-by-everyone "Seen by everyone" :status-seen-by-everyone "Seen by everyone"
:status-seen "Seen" :status-seen "Seen"
:status-delivered "Delivered" :status-delivered "Delivered"
@ -111,6 +113,7 @@
:message-not-sent "Message not sent" :message-not-sent "Message not sent"
:resend-message "Resend" :resend-message "Resend"
:delete-message "Delete message" :delete-message "Delete message"
:sent-at "Sent at"
;;datetime ;;datetime
:datetime-ago-format "{{number}} {{time-intervals}} {{ago}}" :datetime-ago-format "{{number}} {{time-intervals}} {{ago}}"
@ -317,6 +320,13 @@
;;commands ;;commands
:chat-send-eth "{{amount}} ETH" :chat-send-eth "{{amount}} ETH"
:transaction-request "Transaction Request"
:command-button-send "Send"
:command-button-sent "Sent"
:command-requesting "Requesting "
:command-sending "Send transaction "
:request-requesting-from "from "
:send-sending-to "to "
;;new-group ;;new-group
:new-group "New group" :new-group "New group"
@ -389,6 +399,7 @@
:recent-recipients "Contacts" :recent-recipients "Contacts"
:to "To" :to "To"
:from "From" :from "From"
:at "at"
:data "Data" :data "Data"
:got-it "Got it" :got-it "Got it"
:block "Block" :block "Block"

View File

@ -16,6 +16,9 @@
(def gray-notifications "#4A5054cc") ;; Used for notifications background (def gray-notifications "#4A5054cc") ;; Used for notifications background
(def gray-border "#ececf0") (def gray-border "#ececf0")
(def blue "#4360df") ;; Used as main wallet color, and ios home add button (def blue "#4360df") ;; Used as main wallet color, and ios home add button
(def blue-transparent "rgba(67, 96, 223, 0.2)")
(def blue-transparent-40 "rgba(67, 96, 223, 0.4)")
(def blue-darker "#c4cced")
(def blue-dark "#3147ac") ;; Used as secondary wallet color (icon background) (def blue-dark "#3147ac") ;; Used as secondary wallet color (icon background)
(def hawkes-blue "#dce2fb") ;; Outgoing chat messages background (def hawkes-blue "#dce2fb") ;; Outgoing chat messages background
(def wild-blue-yonder "#707caf") ;; Text color for outgoing messages timestamp (def wild-blue-yonder "#707caf") ;; Text color for outgoing messages timestamp

View File

@ -84,6 +84,8 @@
:icons/newchat (components.svg/slurp-svg "./resources/icons/newchat.svg") :icons/newchat (components.svg/slurp-svg "./resources/icons/newchat.svg")
:icons/logo (components.svg/slurp-svg "./resources/icons/logo.svg") :icons/logo (components.svg/slurp-svg "./resources/icons/logo.svg")
:icons/camera (components.svg/slurp-svg "./resources/icons/camera.svg") :icons/camera (components.svg/slurp-svg "./resources/icons/camera.svg")
:icons/check (components.svg/slurp-svg "./resources/icons/check.svg")
:icons/dots (components.svg/slurp-svg "./resources/icons/dots.svg")
:icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg")}) :icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg")})
(defn normalize-property-name [n] (defn normalize-property-name [n]

View File

@ -2,6 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[clojure.string :as str] [clojure.string :as str]
[status-im.constants :as constants]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.screens.home.styles :as styles] [status-im.ui.screens.home.styles :as styles]
[status-im.ui.components.styles :as component.styles] [status-im.ui.components.styles :as component.styles]
@ -12,10 +13,22 @@
[status-im.utils.gfycat.core :as gfycat] [status-im.utils.gfycat.core :as gfycat]
[status-im.constants :as const] [status-im.constants :as const]
[status-im.ui.components.colors :as colors] [status-im.ui.components.colors :as colors]
[status-im.ui.components.chat-preview :as chat-preview]
[status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen] [status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.common.common :as components.common])) [status-im.ui.components.common.common :as components.common]))
(defn command-short-preview
[{:keys [command] {:keys [amount]} :params}]
[chat-preview/text {}
(str
(i18n/label (if (= command constants/command-request)
:command-requesting
:command-sending))
(i18n/label-number amount)
" "
(i18n/label :eth))])
(defn message-content-text [{:keys [content] :as message}] (defn message-content-text [{:keys [content] :as message}]
[react/view styles/last-message-container [react/view styles/last-message-container
(cond (cond
@ -38,6 +51,9 @@
(and (:command content) (-> content :short-preview :markup)) (and (:command content) (-> content :short-preview :markup))
(commands-utils/generate-hiccup (-> content :short-preview :markup)) (commands-utils/generate-hiccup (-> content :short-preview :markup))
(contains? #{constants/command-request constants/command-send} (:command content))
[command-short-preview content]
:else :else
[react/text {:style styles/last-message-text [react/text {:style styles/last-message-text
:number-of-lines 1 :number-of-lines 1

View File

@ -27,10 +27,11 @@
(spec/def ::advanced? boolean?) (spec/def ::advanced? boolean?)
(spec/def ::whisper-identity (spec/nilable string?)) (spec/def ::whisper-identity (spec/nilable string?))
(spec/def ::method (spec/nilable string?)) (spec/def ::method (spec/nilable string?))
(spec/def ::tx-hash (spec/nilable string?))
(spec/def :wallet/send-transaction (allowed-keys (spec/def :wallet/send-transaction (allowed-keys
:opt-un [::amount ::to ::to-name ::amount-error ::asset-error ::amount-text ::password :opt-un [::amount ::to ::to-name ::amount-error ::asset-error ::amount-text ::password
::waiting-signal? ::signing? ::id ::later? ::waiting-signal? ::signing? ::id ::later?
::camera-flashlight ::in-progress? ::camera-flashlight ::in-progress?
::wrong-password? ::from-chat? ::symbol ::advanced? ::wrong-password? ::from-chat? ::symbol ::advanced?
::gas ::gas-price ::whisper-identity ::method])) ::gas ::gas-price ::whisper-identity ::method ::tx-hash]))

View File

@ -261,7 +261,7 @@
true true
(update-in [:wallet :transactions-unsigned] dissoc id) (update-in [:wallet :transactions-unsigned] dissoc id)
true true
(update-in [:wallet :send-transaction] merge clear-send-properties))} (update-in [:wallet :send-transaction] merge clear-send-properties {:tx-hash hash}))}
(if modal? (if modal?
(cond-> {:dispatch [:navigate-back]} (cond-> {:dispatch [:navigate-back]}
(= method constants/web3-send-transaction) (= method constants/web3-send-transaction)

View File

@ -138,3 +138,11 @@
(defn sufficient-funds? [amount balance] (defn sufficient-funds? [amount balance]
(when (and amount balance) (when (and amount balance)
(.greaterThanOrEqualTo balance amount))) (.greaterThanOrEqualTo balance amount)))
(defn usd-amount [amount-str prices]
(-> amount-str
(js/parseFloat)
bignumber
(crypto->fiat (get-in prices [:ETH :USD :price]))
(with-precision 2)
str))