Add chat commands

Signed-off-by: yenda <eric@status.im>
This commit is contained in:
yenda 2019-11-25 14:33:43 +01:00
parent e220ecbb0a
commit 84828891a0
No known key found for this signature in database
GPG Key ID: 0095623C0069DCE6
34 changed files with 937 additions and 218 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "tiny-warning.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tiny-warning@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tiny-warning@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

View File

@ -10,7 +10,6 @@
[status-im.i18n :as i18n]
[status-im.mailserver.core :as mailserver]
[status-im.transport.message.protocol :as transport.protocol]
[status-im.tribute-to-talk.core :as tribute-to-talk]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.navigation :as navigation]
@ -227,8 +226,7 @@
(when platform/desktop?
(mark-messages-seen chat-id))
(when (and (one-to-one-chat? cofx chat-id) (not (contact.db/contact-exists? db chat-id)))
(contact.core/create-contact chat-id))
(tribute-to-talk/check-tribute chat-id)))
(contact.core/create-contact chat-id))))
(fx/defn navigate-to-chat
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
@ -294,5 +292,4 @@
[cofx identity]
(fx/merge (assoc-in cofx [:db :contacts/identity] identity)
(contact.core/create-contact identity)
(tribute-to-talk/check-tribute identity)
(navigation/navigate-to-cofx :profile nil)))

View File

@ -16,7 +16,6 @@
[status-im.transport.message.protocol :as protocol]
[status-im.transport.message.transit :as transit]
[status-im.transport.utils :as transport.utils]
[status-im.tribute-to-talk.core :as tribute-to-talk]
[status-im.ui.components.react :as react]
[status-im.utils.clocks :as utils.clocks]
[status-im.utils.datetime :as time]
@ -58,11 +57,31 @@
:body (str body-first-line (:text content))
:prioritary? (not (chat-model/multi-user-chat? cofx chat-id))}))
(fx/defn rebuild-message-list
[{:keys [db]} chat-id]
{:db (assoc-in db [:chats chat-id :message-list]
(message-list/add-many nil (vals (get-in db [:chats chat-id :messages]))))})
(fx/defn hide-message
"Hide chat message, rebuild message-list"
[{:keys [db] :as cofx} chat-id {:keys [seen message-id]}]
(fx/merge cofx
{:db (update-in db [:chats chat-id :messages] dissoc message-id)}
#(when (not seen)
(fx/merge %
{:db (update-in db [:chats chat-id]
update
:unviewed-messages-count dec)}
(data-store.messages/mark-messages-seen chat-id [message-id])))
(rebuild-message-list chat-id)))
(fx/defn add-message
[{:keys [db] :as cofx}
{{:keys [chat-id message-id timestamp from] :as message} :message
{{:keys [chat-id message-id replace timestamp from] :as message} :message
:keys [current-chat?]}]
(let [current-public-key (multiaccounts.model/current-public-key cofx)
message-to-be-removed (when replace
(get-in db [:chats chat-id :messages replace]))
prepared-message (prepare-message message chat-id current-chat?)]
(when (and platform/desktop?
(not= from current-public-key)
@ -71,20 +90,23 @@
(let [{:keys [title body prioritary?]} (build-desktop-notification cofx message)]
(.displayNotification react/desktop-notification title body prioritary?)))
(fx/merge cofx
{:db (cond->
(-> db
;; We should not be always adding to the list, as it does not make sense
;; if the chat has not been initialized, but run into
;; some troubles disabling it, so next time
(update-in [:chats chat-id :messages] assoc message-id prepared-message)
(update-in [:chats chat-id :message-list] message-list/add prepared-message))
(and (not current-chat?)
(not= from current-public-key))
(update-in [:chats chat-id :loaded-unviewed-messages-ids]
(fnil conj #{}) message-id))}
(when message-to-be-removed
(hide-message chat-id message-to-be-removed))
(fn [{:keys [db]}]
{:db (cond->
(-> db
;; We should not be always adding to the list, as it does not make sense
;; if the chat has not been initialized, but run into
;; some troubles disabling it, so next time
(update-in [:chats chat-id :messages] assoc message-id prepared-message)
(update-in [:chats chat-id :message-list] message-list/add prepared-message))
(and (not current-chat?)
(not= from current-public-key))
(update-in [:chats chat-id :loaded-unviewed-messages-ids]
(fnil conj #{}) message-id))})
(when (and platform/desktop?
(not (system-message? prepared-message)))
(chat-model/update-dock-badge-label)))))
(fx/defn add-received-message
@ -175,11 +197,6 @@
:on-error #(log/error "failed to re-send message" %)}]}
(update-message-status chat-id message-id :sending)))
(fx/defn rebuild-message-list
[{:keys [db]} chat-id]
{:db (assoc-in db [:chats chat-id :message-list]
(message-list/add-many nil (vals (get-in db [:chats chat-id :messages]))))})
(fx/defn delete-message
"Deletes chat message, rebuild message-list"
[{:keys [db] :as cofx} chat-id message-id]
@ -200,10 +217,7 @@
(fx/defn send-message
[{:keys [db now] :as cofx} {:keys [chat-id] :as message}]
(let [{:keys [chats]} db
message-data (-> message
(tribute-to-talk/add-transaction-hash db))]
(protocol/send-chat-message cofx message-data)))
(protocol/send-chat-message cofx message))
(fx/defn toggle-expand-message
[{:keys [db]} chat-id message-id]

View File

@ -131,19 +131,15 @@
(.prev iter)
e))
(defn insert-message
"Insert a message in the list, pull it's left and right messages, calculate
its positional metadata, and update the left & right messages if necessary,
this operation is O(logN) for insertion, and O(logN) for the updates, as
we need to re-find (there's probably a better way)"
[old-message-list {:keys [key] :as prepared-message}]
(let [tree (.insert old-message-list prepared-message prepared-message)
iter (.find tree prepared-message)
(defn update-message
"Update the message and siblings with positional info"
[tree message]
(let [iter (.find tree message)
previous-message (when (.-hasPrev iter)
(get-prev-element iter))
next-message (when (.-hasNext iter)
(get-next-element iter))
message-with-pos-data (add-group-info prepared-message previous-message next-message)]
message-with-pos-data (add-group-info message previous-message next-message)]
(cond->
(.update iter message-with-pos-data)
@ -156,6 +152,28 @@
(-> (.find previous-message)
(.update (update-previous-message message-with-pos-data previous-message))))))
(defn remove-message
"Remove a message in the list"
[tree prepared-message]
(let [iter (.find tree prepared-message)]
(if (not iter)
tree
(let [new-tree (.remove iter)
next-message (when (.-hasNext iter)
(get-next-element iter))]
(if (not next-message)
new-tree
(update-message new-tree next-message))))))
(defn insert-message
"Insert a message in the list, pull it's left and right messages, calculate
its positional metadata, and update the left & right messages if necessary,
this operation is O(logN) for insertion, and O(logN) for the updates, as
we need to re-find (there's probably a better way)"
[old-message-list prepared-message]
(let [tree (.insert old-message-list prepared-message prepared-message)]
(update-message tree prepared-message)))
(defn add [message-list message]
(insert-message (or message-list (dependencies/rb-tree compare-fn))
(prepare-message message)))

View File

@ -0,0 +1,42 @@
(ns status-im.commands.core
(:require
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]))
(fx/defn handle-prepare-accept-request-address-for-transaction
{:events [::prepare-accept-request-address-for-transaction]}
[{:keys [db]} message]
{:db (assoc db
:commands/select-account
{:message message
:from (ethereum/get-default-account (:multiaccount/accounts db))})})
(fx/defn set-selected-account
{:events [::set-selected-account]}
[{:keys [db]} _ account]
{:db (-> (assoc-in db [:commands/select-account :from] account)
(assoc :bottom-sheet/show? false))})
(fx/defn handle-accept-request-address-for-transaction
{:events [::accept-request-address-for-transaction]}
[{:keys [db]} message-id address]
{:db (dissoc db :commands/select-account)
::json-rpc/call [{:method "shhext_acceptRequestAddressForTransaction"
:params [message-id address]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})
(fx/defn handle-decline-request-address-for-transaction
{:events [::decline-request-address-for-transaction]}
[cofx message-id]
{::json-rpc/call [{:method "shhext_declineRequestAddressForTransaction"
:params [message-id]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})
(fx/defn handle-decline-request-transaction
{:events [::decline-request-transaction]}
[cofx message-id]
{::json-rpc/call [{:method "shhext_declineRequestTransaction"
:params [message-id]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})

View File

@ -7,15 +7,24 @@
(def ms-in-bg-for-require-bioauth 5000)
(def content-type-text 1)
(def content-type-sticker 2)
(def content-type-status 3)
(def content-type-emoji 4)
(def ^:const content-type-text 1)
(def ^:const content-type-sticker 2)
(def ^:const content-type-status 3)
(def ^:const content-type-emoji 4)
(def ^:const content-type-command 5)
(def message-type-one-to-one 1)
(def message-type-public-group 2)
(def message-type-private-group 3)
(def message-type-private-group-system-message 4)
(def ^:const message-type-one-to-one 1)
(def ^:const message-type-public-group 2)
(def ^:const message-type-private-group 3)
(def ^:const message-type-private-group-system-message 4)
(def ^:const command-state-request-address-for-transaction 1)
(def ^:const command-state-request-address-for-transaction-declined 2)
(def ^:const command-state-request-address-for-transaction-accepted 3)
(def ^:const command-state-request-transaction 4)
(def ^:const command-state-request-transaction-declined 5)
(def ^:const command-state-transaction-pending 6)
(def ^:const command-state-transaction-sent 7)
(def desktop-content-types
#{content-type-text content-type-emoji content-type-status})

View File

@ -19,7 +19,10 @@
(fx/defn load-contacts
{:events [::contacts-loaded]}
[{:keys [db] :as cofx} all-contacts]
(let [contacts-list (map #(vector (:public-key %) %) all-contacts)
(let [contacts-list (map #(vector (:public-key %) (if (empty? (:address %))
(dissoc % :address)
%))
all-contacts)
contacts (into {} contacts-list)
tr-to-talk-enabled? (-> db tribute-to-talk/get-settings tribute-to-talk/enabled?)]
(fx/merge cofx
@ -123,12 +126,10 @@
(cond-> {:public-key public-key
:photo-path profile-image
:name name
:address (or address
(:address contact)
(ethereum/public-key->address public-key))
:last-updated timestamp-ms
:system-tags (conj (get contact :system-tags #{})
:contact/request-received)})]
:contact/request-received)}
address (assoc :address address))]
(upsert-contact cofx contact-props)))))
(fx/defn initialize-contacts [cofx]

View File

@ -27,10 +27,10 @@
(spec/def :contact/tribute (spec/nilable int?))
(spec/def :contact/tribute-transaction (spec/nilable string?))
(spec/def :contact/contact (spec/keys :req-un [:contact/address
:contact/public-key
(spec/def :contact/contact (spec/keys :req-un [:contact/public-key
:contact/system-tags]
:opt-un [:contact/name
:contact/address
:contact/photo-path
:contact/last-online
:contact/last-updated
@ -66,7 +66,6 @@
(let [alias (gfycat/generate-gfy public-key)]
{:alias alias
:name alias
:address (ethereum/public-key->address public-key)
:identicon (identicon/identicon public-key)
:public-key public-key
:system-tags #{}}))

View File

@ -23,6 +23,7 @@
(-> message
(clojure.set/rename-keys {:id :message-id
:whisperTimestamp :whisper-timestamp
:commandParameters :command-parameters
:messageType :message-type
:localChatId :chat-id
:contentType :content-type
@ -31,6 +32,8 @@
:outgoingStatus :outgoing-status})
(update :outgoing-status keyword)
(update :command-parameters clojure.set/rename-keys {:transactionHash :transaction-hash
:commandState :command-state})
(assoc :content {:chat-id (:chatId message)
:text (:text message)
:sticker (:sticker message)

View File

@ -66,6 +66,13 @@
"shhext_deleteChat" {}
"shhext_saveContact" {}
"shhext_verifyENSNames" {}
"shhext_requestAddressForTransaction" {}
"shhext_requestTransaction" {}
"shhext_acceptRequestAddressForTransaction" {}
"shhext_declineRequestAddressForTransaction" {}
"shhext_declineRequestTransaction" {}
"shhext_sendTransaction" {}
"shhext_acceptRequestTransaction" {}
"status_chats" {}
"wallet_getTransfers" {}
"wallet_getTokensBalances" {}

View File

@ -119,15 +119,17 @@
:BrowsersConfig {:Enabled true}
:PermissionsConfig {:Enabled true}
:MailserversConfig {:Enabled true}
:EnableNTPSync true
:WhisperConfig {:Enabled true
:LightClient true
:MinimumPoW 0.001
:EnableNTPSync true}
:MinimumPoW 0.001}
:ShhextConfig
{:BackupDisabledDataDir (utils.platform/no-backup-directory)
:InstallationID installation-id
:MaxMessageDeliveryAttempts config/max-message-delivery-attempts
:MailServerConfirmations config/mailserver-confirmations-enabled?
:VerifyTransactionURL "https://mainnet.infura.io/v3/f315575765b14720b32382a61a89341a"
:VerifyTransactionChainID 1
:DataSyncEnabled true
:PFSEnabled true}
:RequireTopics (get-topics current-network)

View File

@ -3,6 +3,7 @@
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.ethereum.abi-spec :as abi-spec]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.tokens :as tokens]
@ -81,7 +82,8 @@
{:events [:signing.ui/sign-is-pressed]}
[{{:signing/keys [sign tx] :as db} :db :as cofx}]
(let [{:keys [in-progress? password]} sign
{:keys [tx-obj gas gasPrice message]} tx]
{:keys [tx-obj gas gasPrice message]} tx
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
(if message
(sign-message cofx)
(let [tx-obj-to-send (merge tx-obj
@ -92,8 +94,8 @@
(when-not in-progress?
{:db (update db :signing/sign assoc :error nil :in-progress? true)
:signing/send-transaction-fx {:tx-obj tx-obj-to-send
:hashed-password (ethereum/sha3 (security/safe-unmask-data password))
:cb #(re-frame/dispatch [:signing/transaction-completed % tx-obj-to-send])}})))))
:hashed-password hashed-password
:cb #(re-frame/dispatch [:signing/transaction-completed % tx-obj-to-send hashed-password])}})))))
(fx/defn prepare-unconfirmed-transaction
[{:keys [db now]} hash {:keys [value gasPrice gas data to from]} symbol amount]
@ -203,11 +205,46 @@
(when (and (not in-progress?) (seq queue))
(show-sign cofx))))
(fx/defn send-transaction-message
{:events [::send-transaction-message]}
[cofx chat-id transaction-hash signature]
{::json-rpc/call [{:method "shhext_sendTransaction"
:params [chat-id transaction-hash (:result (types/json->clj signature))]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})
(fx/defn send-accept-request-transaction-message
{:events [::send-accept-transaction-message]}
[cofx message-id transaction-hash signature]
{::json-rpc/call [{:method "shhext_acceptRequestTransaction"
:params [transaction-hash message-id (:result (types/json->clj signature))]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})
(fx/defn transaction-result
[{:keys [db] :as cofx} result tx-obj]
(let [{:keys [on-result symbol amount]} (get db :signing/tx)]
(fx/merge cofx
{:db (dissoc db :signing/tx :signing/in-progress? :signing/sign)
{:db (dissoc db :signing/tx :signing/in-progress? :signing/sign)
:signing/show-transaction-result nil}
(prepare-unconfirmed-transaction result tx-obj symbol amount)
(check-queue)
#(when on-result
{:dispatch (conj on-result result)}))))
(fx/defn command-transaction-result
[{:keys [db] :as cofx} result hashed-password tx-obj]
(let [{:keys [on-result symbol amount]} (get db :signing/tx)]
(fx/merge cofx
{:db (dissoc db :signing/tx :signing/in-progress? :signing/sign)
:signing.fx/sign-message
{:params {:data (str (get-in db [:multiaccount :public-key])
(subs result 2))
:password hashed-password
:account (:from tx-obj)}
:on-completed
#(re-frame/dispatch
(if (:message-id tx-obj)
[::send-accept-transaction-message (:message-id tx-obj) result %]
[::send-transaction-message (:chat-id tx-obj) result %]))}
:signing/show-transaction-result nil}
(prepare-unconfirmed-transaction result tx-obj symbol amount)
(check-queue)
@ -241,12 +278,14 @@
(fx/defn transaction-completed
{:events [:signing/transaction-completed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[cofx response tx-obj]
[cofx response tx-obj hashed-password]
(let [cofx-in-progress-false (assoc-in cofx [:db :signing/sign :in-progress?] false)
{:keys [result error]} (types/json->clj response)]
(if error
(transaction-error cofx-in-progress-false error)
(transaction-result cofx-in-progress-false result tx-obj))))
(if (:command? tx-obj)
(command-transaction-result cofx-in-progress-false result hashed-password tx-obj)
(transaction-result cofx-in-progress-false result tx-obj)))))
(fx/defn discard
"Discrad transaction signing"

View File

@ -166,6 +166,9 @@
(reg-root-key-sub :wallet/custom-token-screen :wallet/custom-token-screen)
(reg-root-key-sub :wallet/prepare-transaction :wallet/prepare-transaction)
;;commands
(reg-root-key-sub :commands/select-account :commands/select-account)
;;ethereum
(reg-root-key-sub :ethereum/current-block :ethereum/current-block)
@ -599,54 +602,55 @@
(fn [[contacts chats multiaccount]]
(chat.db/active-chats contacts chats multiaccount)))
(defn enrich-current-one-to-one-chat
[{:keys [contact] :as current-chat} my-public-key ttt-settings
chain-keyword prices currency]
(let [{:keys [tribute-to-talk]} contact
{:keys [disabled? snt-amount message]} tribute-to-talk
whitelisted-by? (whitelist/whitelisted-by? contact)
loading? (and (not whitelisted-by?)
(not tribute-to-talk))
show-input? (or whitelisted-by?
disabled?)
token (case chain-keyword
:mainnet :SNT
:STT)
tribute-status (if loading?
:loading
(tribute-to-talk.db/tribute-status contact))
tribute-label (tribute-to-talk.db/status-label tribute-status snt-amount)]
;; TODO: this is no useful without tribute to talk
#_(defn enrich-current-one-to-one-chat
[{:keys [contact] :as current-chat} my-public-key ttt-settings
chain-keyword prices currency]
(let [{:keys [tribute-to-talk]} contact
{:keys [disabled? snt-amount message]} tribute-to-talk
whitelisted-by? (whitelist/whitelisted-by? contact)
loading? (and (not whitelisted-by?)
(not tribute-to-talk))
show-input? (or whitelisted-by?
disabled?)
token (case chain-keyword
:mainnet :SNT
:STT)
tribute-status (if loading?
:loading
(tribute-to-talk.db/tribute-status contact))
tribute-label (tribute-to-talk.db/status-label tribute-status snt-amount)]
(cond-> (assoc current-chat
:tribute-to-talk/tribute-status tribute-status
:tribute-to-talk/tribute-label tribute-label)
(cond-> (assoc current-chat
:tribute-to-talk/tribute-status tribute-status
:tribute-to-talk/tribute-label tribute-label)
(#{:required :pending :paid} tribute-status)
(assoc :tribute-to-talk/snt-amount
(tribute-to-talk.db/from-wei snt-amount)
:tribute-to-talk/message
message
:tribute-to-talk/fiat-amount (if snt-amount
(money/fiat-amount-value
snt-amount
token
(-> currency :code keyword)
prices)
"0")
:tribute-to-talk/fiat-currency (:code currency)
:tribute-to-talk/token (str " " (name token)))
(#{:required :pending :paid} tribute-status)
(assoc :tribute-to-talk/snt-amount
(tribute-to-talk.db/from-wei snt-amount)
:tribute-to-talk/message
message
:tribute-to-talk/fiat-amount (if snt-amount
(money/fiat-amount-value
snt-amount
token
(-> currency :code keyword)
prices)
"0")
:tribute-to-talk/fiat-currency (:code currency)
:tribute-to-talk/token (str " " (name token)))
(tribute-to-talk.db/enabled? ttt-settings)
(assoc :tribute-to-talk/received? (tribute-to-talk.db/tribute-received?
contact))
(tribute-to-talk.db/enabled? ttt-settings)
(assoc :tribute-to-talk/received? (tribute-to-talk.db/tribute-received?
contact))
(= tribute-status :required)
(assoc :tribute-to-talk/on-share-my-profile
#(re-frame/dispatch
[:profile/share-profile-link my-public-key]))
(= tribute-status :required)
(assoc :tribute-to-talk/on-share-my-profile
#(re-frame/dispatch
[:profile/share-profile-link my-public-key]))
show-input?
(assoc :show-input? true))))
show-input?
(assoc :show-input? true))))
(defn enrich-current-chat
[{:keys [messages chat-id might-have-join-time-messages?] :as chat}
@ -683,16 +687,8 @@
:<- [:mailserver/ranges]
:<- [:chats/content-layout-height]
:<- [:chats/current-chat-ui-prop :input-height]
:<- [:tribute-to-talk/settings]
:<- [:ethereum/chain-keyword]
:<- [:prices]
:<- [:wallet/currency]
(fn [[{:keys [group-chat
chat-id
contact
messages]
:as current-chat} my-public-key ranges height
input-height ttt-settings chain-keyword prices currency]]
(fn [[{:keys [group-chat chat-id contact messages] :as current-chat}
my-public-key ranges height input-height]]
(when current-chat
(cond-> (enrich-current-chat current-chat ranges height input-height)
(empty? messages)
@ -707,8 +703,14 @@
(assoc :show-input? true)
(not group-chat)
(enrich-current-one-to-one-chat my-public-key ttt-settings
chain-keyword prices currency)))))
(assoc :show-input? true)))))
(re-frame/reg-sub
:current-chat/one-to-one-chat?
:<- [:chats/current-raw-chat]
(fn [current-chat]
(not (or (chat.models/group-chat? current-chat)
(chat.models/public-chat? current-chat)))))
(re-frame/reg-sub
:chats/current-chat-message
@ -1124,6 +1126,13 @@
"0"))
"...")))
(re-frame/reg-sub
:wallet/chain-tokens
:<- [:wallet/all-tokens]
:<- [:ethereum/chain-keyword]
(fn [[all-tokens chain]]
(get all-tokens chain)))
(re-frame/reg-sub
:wallet/sorted-chain-tokens
:<- [:wallet/all-tokens]
@ -1235,6 +1244,21 @@
;;WALLET TRANSACTIONS ==================================================================================================
(re-frame/reg-sub
:wallet/accounts
:<- [:wallet]
(fn [wallet]
(get wallet :accounts)))
(re-frame/reg-sub
:wallet/account-by-transaction-hash
:<- [:wallet/accounts]
(fn [accounts [_ hash]]
(some (fn [[address account]]
(when-let [transaction (get-in account [:transactions hash])]
(assoc transaction :address address)))
accounts)))
(re-frame/reg-sub
:wallet/transactions
:<- [:wallet]
@ -2038,6 +2062,32 @@
(not (nil? amount))
(not offline?))))))
(re-frame/reg-sub
:wallet.request/prepare-transaction-with-balance
:<- [:wallet/prepare-transaction]
:<- [:wallet]
:<- [:offline?]
:<- [:wallet/all-tokens]
:<- [:ethereum/chain-keyword]
(fn [[{:keys [symbol from to amount-text] :as transaction}
wallet offline? all-tokens chain]]
(let [balance (get-in wallet [:accounts (:address from) :balance])
{:keys [decimals] :as token} (tokens/asset-for all-tokens chain symbol)
{:keys [value error]} (wallet.db/parse-amount amount-text decimals)
amount (money/formatted->internal value symbol decimals)
{:keys [amount-error] :as transaction-new}
(assoc transaction
:amount-error error)]
(assoc transaction-new
:amount amount
:balance balance
:token (assoc token :amount (get balance (:symbol token)))
:sign-enabled? (and to
from
(nil? amount-error)
(not (nil? amount))
(not offline?))))))
;; NETWORK SETTINGS
(defn- filter-networks [network-type]

View File

@ -64,4 +64,4 @@
(views/defview animated-bottom-panel [val signing-view]
(views/letsubs [{window-height :height} [:dimensions/window]]
[bottom-panel (when val (select-keys val [:from :contact :amount :token :approve? :message])) signing-view window-height]))
[bottom-panel (when val (select-keys val [:from :contact :amount :token :approve? :message])) signing-view window-height]))

View File

@ -54,7 +54,6 @@
:caption {:font-size 12}
:timestamp {:font-size 10
:letter-spacing 1
:text-transform :uppercase}})
(defn get-style

View File

@ -37,7 +37,7 @@
:height panel-height
:transform [{:translateY bottom-anim-value}]
:opacity alpha-value}}
[react/view
[react/view {:style {:flex-direction :row}}
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:wallet/prepare-transaction-from-chat])}
[react/view {:width 128 :height 128 :justify-content :space-between
@ -47,13 +47,12 @@
:justify-content :center}
[icons/icon :main-icons/send {:color colors/white}]]
[react/text {:typography :medium} (i18n/label :t/send-transaction)]]]
;;TODO not implemented yet
#_[react/touchable-highlight
{:on-press #(re-frame/dispatch [:wallet/prepare-transaction-from-chat])}
[react/view {:width 128 :height 128 :justify-content :space-between
:padding-horizontal 10 :padding-vertical 12 :margin-top 8
:background-color (colors/alpha colors/orange 0.2) :border-radius 16 :margin-left 8}
[react/view {:background-color colors/orange :width 40 :height 40 :border-radius 20 :align-items :center
:justify-content :center}
[icons/icon :main-icons/receive {:color colors/white}]]
[react/text {:typography :medium} (i18n/label :t/request-transaction)]]]]]))
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:wallet/prepare-request-transaction-from-chat])}
[react/view {:width 128 :height 128 :justify-content :space-between
:padding-horizontal 10 :padding-vertical 12
:background-color (colors/alpha colors/orange 0.2) :border-radius 16 :margin-left 8}
[react/view {:background-color colors/orange :width 40 :height 40 :border-radius 20 :align-items :center
:justify-content :center}
[icons/icon :main-icons/receive {:color colors/white}]]
[react/text {:typography :medium} (i18n/label :t/request-transaction)]]]]]))

View File

@ -155,6 +155,7 @@
input-text [:chats/current-chat-input-text]
result-box [:chats/current-chat-ui-prop :result-box]
input-bottom-sheet [:chats/current-chat-ui-prop :input-bottom-sheet]
one-to-one-chat? [:current-chat/one-to-one-chat?]
state-text (reagent/atom "")]
{:component-will-unmount #(when platform/desktop?
(re-frame/dispatch [:chat.ui/set-chat-input-text @state-text]))
@ -176,7 +177,7 @@
[input-view {:single-line-input? single-line-input? :set-text set-text :state-text state-text}]
(when (and input-text-empty? mainnet?)
[stickers/button (= :stickers input-bottom-sheet)])
(when (and input-text-empty?) ;;TODO show only for 1-1 chats?
(when (and one-to-one-chat? input-text-empty? mainnet?)
[extensions/button (= :extensions input-bottom-sheet)])
(when-not input-text-empty?
(if platform/desktop?

View File

@ -1,15 +1,20 @@
(ns status-im.ui.screens.chat.message.message
(:require [re-frame.core :as re-frame]
[status-im.commands.core :as commands]
[status-im.constants :as constants]
[status-im.utils.http :as http]
[status-im.i18n :as i18n]
[status-im.ethereum.eip55 :as eip55]
[reagent.core :as reagent]
[status-im.ui.components.colors :as colors]
[status-im.utils.security :as security]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.popup-menu.views :as desktop.pop-up]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.react :as react]
[status-im.utils.money :as money]
[status-im.ethereum.transactions.core :as transactions]
[status-im.ui.screens.chat.message.sheets :as sheets]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.chat.styles.message.message :as style]
@ -201,6 +206,244 @@
[react/image {:style {:margin 10 :width 140 :height 140}
:source {:uri (contenthash/url (-> content :sticker :hash))}}]])
(defn- final-status? [command-state]
(or (= command-state constants/command-state-request-address-for-transaction-declined)
(= command-state constants/command-state-request-transaction-declined)
(= command-state constants/command-state-transaction-sent)))
(defn- command-pending-status
[command-state direction to transaction-type]
[react/view {:style {:flex-direction :row
:height 28
:align-items :center
:border-width 1
:border-color colors/gray-lighter
:border-radius 16
:padding-horizontal 8
:margin-right 12
:margin-bottom 2}}
[vector-icons/icon :tiny-icons/tiny-pending
{:width 16
:height 16
:color colors/gray
:container-style {:margin-right 6}}]
[react/text {:style {:color colors/gray
:font-weight "500"
:line-height 16
:margin-right 4
:font-size 13}}
(if (and (or (= command-state constants/command-state-request-transaction)
(= command-state constants/command-state-request-address-for-transaction-accepted))
(= direction :incoming))
(str (i18n/label :t/shared) " '" (:name @(re-frame/subscribe [:account-by-address to])) "'")
(i18n/label (cond
(= command-state constants/command-state-transaction-pending)
:t/status-pending
(= command-state constants/command-state-request-address-for-transaction)
:t/address-requested
(= command-state constants/command-state-request-address-for-transaction-accepted)
:t/address-request-accepted
(= command-state constants/command-state-transaction-sent)
(case transaction-type
:pending :t/status-pending
:failed :t/transaction-failed
:t/status-confirmed)
(= command-state constants/command-state-request-transaction)
:t/address-received)))]])
(defn- command-final-status
[command-state direction transaction-type]
[react/view {:style {:flex-direction :row
:height 28
:align-items :center
:border-width 1
:border-color colors/gray-lighter
:border-radius 16
:padding-horizontal 8
:margin-right 12
:margin-bottom 2}}
(if (or (= command-state constants/command-state-request-address-for-transaction-declined)
(= command-state constants/command-state-request-transaction-declined)
(= :failed transaction-type))
[vector-icons/icon :tiny-icons/tiny-warning
{:width 16
:height 16
:container-style {:margin-right 6}}]
(if (= :pending transaction-type)
[vector-icons/icon :tiny-icons/tiny-pending
{:color colors/gray
:width 16
:height 16
:container-style {:margin-right 6}}]
[vector-icons/icon :tiny-icons/tiny-check
{:width 16
:height 16
:container-style {:margin-right 6}}]))
[react/text {:style (merge {:margin-right 4
:line-height 16
:font-size 13}
(if (= transaction-type :pending)
{:color colors/gray}
{:font-weight "500"}))}
(i18n/label (if (or (= command-state constants/command-state-request-address-for-transaction-declined)
(= command-state constants/command-state-request-transaction-declined))
:t/transaction-declined
(case direction
:outgoing (case transaction-type
:pending :t/status-pending
:failed :t/transaction-failed
:t/status-confirmed)
:incoming :t/status-confirmed)))]])
(defn- command-status-and-timestamp
[command-state direction to timestamp-str transaction-type]
[react/view {:style {:flex-direction :row
:align-items :flex-end
:justify-content :space-between}}
(if (final-status? command-state)
[command-final-status command-state direction transaction-type]
[command-pending-status command-state direction to transaction-type])
[react/text {:style {:font-size 10
:line-height 12
:text-align-vertical :bottom
:color colors/gray}}
timestamp-str]])
(defn- command-actions
[accept-label on-accept on-decline]
[react/view
[react/touchable-highlight
{:on-press #(do (react/dismiss-keyboard!)
(on-accept))
:style {:border-color colors/gray-lighter
:border-top-width 1
:margin-top 8
:margin-horizontal -12
:padding-horizontal 15
:padding-vertical 10}}
[react/text {:style {:text-align :center
:color colors/blue
:font-weight "500"
:font-size 15
:line-height 22}}
(i18n/label accept-label)]]
(when on-decline
[react/touchable-highlight
{:on-press on-decline
:style {:border-color colors/gray-lighter
:border-top-width 1
:margin-horizontal -12
:padding-top 10}}
[react/text {:style {:text-align :center
:color colors/blue
:font-size 15
:line-height 22}}
(i18n/label :t/decline)]])])
(defn- command-transaction-info
[contract value]
(let [{:keys [symbol icon decimals color] :as token}
(if (seq contract)
(get @(re-frame/subscribe [:wallet/chain-tokens])
contract
transactions/default-erc20-token)
@(re-frame/subscribe [:ethereum/native-currency]))
amount (money/internal->formatted value symbol decimals)
{:keys [code] :as currency}
@(re-frame/subscribe [:wallet/currency])
prices @(re-frame/subscribe [:prices])
amount-fiat
(money/fiat-amount-value amount symbol (keyword code) prices)]
[react/view {:style {:flex-direction :row
:margin-top 8
:margin-bottom 12}}
(if icon
[react/image (-> icon
(update :source #(%))
(assoc-in [:style :height] 24)
(assoc-in [:style :width] 24))]
[react/view {:style {:margin-right 14
:padding-vertical 2
:justify-content :flex-start
:max-width 40
:align-items :center
:align-self :stretch}}
[chat-icon/custom-icon-view-list (:name token) color 24]])
[react/view {:style {:margin-left 6}}
[react/text {:style {:margin-bottom 2
:font-size 20
:line-height 24}}
(str amount " " (name symbol))]
[react/text {:style {:font-size 12
:line-height 16
:color colors/gray}}
(str amount-fiat " " code)]]]))
(defn calculate-direction [outgoing command-state]
(case command-state
(constants/command-state-request-address-for-transaction-accepted
constants/command-state-request-address-for-transaction-declined
constants/command-state-request-transaction)
(if outgoing :incoming :outgoing)
(if outgoing :outgoing :incoming)))
(defmethod message-content constants/content-type-command
[wrapper {:keys [message-id
chat-id
outgoing
command-parameters
timestamp-str] :as message}]
(let [{:keys [contract value address command-state transaction-hash]} command-parameters
direction (calculate-direction outgoing command-state)
transaction (when transaction-hash
@(re-frame/subscribe
[:wallet/account-by-transaction-hash
transaction-hash]))]
[wrapper (assoc message :outgoing (= direction :outgoing))
[react/touchable-highlight
{:on-press #(when (:address transaction)
(re-frame/dispatch [:wallet.ui/show-transaction-details
transaction-hash (:address transaction)]))}
[react/view {:padding-horizontal 12
:padding-bottom 10
:padding-top 10
:margin-top 4
:border-width 1
:border-color colors/gray-lighter
:border-radius 16
(case direction
:outgoing :border-bottom-right-radius
:incoming :border-bottom-left-radius) 4
:background-color :white}
[react/text {:style {:font-size 13
:line-height 18
:font-weight "500"
:color colors/gray}}
(case direction
:outgoing (str "↑ " (i18n/label :t/outgoing-transaction))
:incoming (str "↓ " (i18n/label :t/incoming-transaction)))]
[command-transaction-info contract value]
[command-status-and-timestamp
command-state direction address timestamp-str (:type transaction)]
(when (not outgoing)
(cond
(= command-state constants/command-state-request-transaction)
[command-actions
:t/sign-and-send
#(re-frame/dispatch [:wallet.ui/accept-request-transaction-button-clicked-from-command chat-id command-parameters])
#(re-frame/dispatch [::commands/decline-request-transaction message-id])]
(= command-state constants/command-state-request-address-for-transaction-accepted)
[command-actions
:t/sign-and-send
#(re-frame/dispatch [:wallet.ui/accept-request-transaction-button-clicked-from-command chat-id command-parameters])]
(= command-state constants/command-state-request-address-for-transaction)
[command-actions
:t/accept-and-share-address
#(re-frame/dispatch [::commands/prepare-accept-request-address-for-transaction message])
#(re-frame/dispatch [::commands/decline-request-address-for-transaction message-id])]))]]]))
(defmethod message-content :default
[wrapper {:keys [content-type] :as message}]
[wrapper message
@ -215,14 +458,16 @@
(defn message-not-sent-text
[chat-id message-id]
[react/touchable-highlight
{:on-press (fn [] (if platform/desktop?
(desktop.pop-up/show-desktop-menu
(desktop.pop-up/get-message-menu-items chat-id message-id))
(do
(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (sheets/options chat-id message-id)
:content-height 200}])
(react/dismiss-keyboard!))))}
{:on-press
(fn [] (if platform/desktop?
(desktop.pop-up/show-desktop-menu
(desktop.pop-up/get-message-menu-items chat-id message-id))
(do
(re-frame/dispatch
[:bottom-sheet/show-sheet
{:content (sheets/options chat-id message-id)
:content-height 200}])
(react/dismiss-keyboard!))))}
[react/view style/not-sent-view
[react/text {:style style/not-sent-text}
(i18n/label (if platform/desktop?

View File

@ -12,7 +12,6 @@
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
[status-im.utils.platform :as platform]
[status-im.ui.screens.wallet.send.views :as wallet.send]
[status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings]
[status-im.ui.screens.keycard.views :as keycard]
[status-im.ui.screens.home.sheet.views :as home.sheet]
@ -170,6 +169,8 @@
:persistNavigationState (when js/goog.DEBUG persist-state)
:loadNavigationState (when js/goog.DEBUG load-state)}]
[wallet/prepare-transaction]
[wallet/request-transaction]
[wallet/select-account]
[signing/signing]
[bottom-sheet]
[popover/popover]]]))})))

View File

@ -19,19 +19,19 @@
(:code currency)
#(re-frame/dispatch [:wallet.send/set-symbol (:symbol %)]))}]))
(defn render-account [field]
(defn render-account [field event]
(fn [account]
[list-item/list-item
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
:title (:name account)
:on-press #(re-frame/dispatch [:wallet.send/set-field field account])}]))
:on-press #(re-frame/dispatch [event field account])}]))
(views/defview accounts-list [field]
(views/defview accounts-list [field event]
(views/letsubs [accounts [:multiaccount/accounts]
accounts-whithout-watch [:accounts-without-watch-only]]
[list/flat-list {:data (if (= :to field) accounts accounts-whithout-watch)
:key-fn :address
:render-fn (render-account field)}]))
:render-fn (render-account field event)}]))
(defn- request-camera-permissions []
(let [options {:handler :wallet.send/qr-scanner-result
@ -50,7 +50,7 @@
(defn show-accounts-list []
(re-frame/dispatch [:bottom-sheet/hide-sheet])
(js/setTimeout #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [accounts-list :to])
{:content (fn [] [accounts-list :to :wallet.send/set-field])
:content-height 300}]) 400))
(defn choose-recipient []

View File

@ -2,6 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview letsubs] :as views])
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.commands.core :as commands]
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.screens.wallet.send.styles :as styles]
@ -19,24 +20,24 @@
[status-im.utils.utils :as utils]
[status-im.ui.components.button :as button]))
(defn header [small-screen?]
(defn header [{:keys [label small-screen? on-cancel]}]
[react/view (styles/header small-screen?)
[react/view {:flex 1}
[react/text {:style (merge {:typography :title-bold} (when small-screen? {:font-size 15}))}
(i18n/label :t/send-transaction)]]
(i18n/label (or label :t/send-transaction))]]
[button/button {:type :secondary
:container-style {:padding-horizontal 24}
:label (i18n/label :t/cancel)
:on-press #(re-frame/dispatch [:set :wallet/prepare-transaction nil])}]])
:on-press on-cancel}]])
(defn asset-selector [{:keys [token from]}]
(defn asset-selector [{:keys [request? token from]}]
(let [{:keys [name icon color]} token]
[react/touchable-highlight
{:on-press #(do
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/assets (:address from)])
:content-height 300}]))}
{:on-press (when-not request? #(do
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/assets (:address from)])
:content-height 300}])))}
[react/view {:style {:flex-direction :row
:align-items :center
:margin-left 16}
@ -47,9 +48,10 @@
[chat-icon/custom-icon-view-list name color 32])
[react/text {:style {:margin-left 8}}
(wallet.utils/display-symbol token)]
[icons/icon :main-icons/dropdown {:color colors/gray}]]]))
(when-not request?
[icons/icon :main-icons/dropdown {:color colors/gray}])]]))
(defn render-account [account {:keys [amount decimals] :as token}]
(defn render-account [account {:keys [amount decimals] :as token} event]
[list-item/list-item
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
:title (:name account)
@ -60,7 +62,7 @@
:on-press #(do
(re-frame/dispatch [:dismiss-keyboard])
(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/accounts-list :from])
{:content (fn [] [sheets/accounts-list :from event])
:content-height 300}]))}])
(defn render-contact [contact from-chat?]
@ -80,13 +82,75 @@
:accessories [:chevron]}]))
(views/defview sheet [_]
(views/letsubs [{:keys [amount-error amount-text from token to sign-enabled? from-chat?] :as tx}
(views/letsubs [{:keys [amount-error amount-text
request?
from token to sign-enabled? from-chat?] :as tx}
[:wallet.send/prepare-transaction-with-balance]
window-height [:dimensions/window-height]
keyboard-height [:keyboard-height]]
(let [small-screen? (< (- window-height keyboard-height) 450)]
[react/view {:style (styles/sheet small-screen?)}
[header small-screen?]
[header {:small-screen? small-screen?
:on-cancel #(re-frame/dispatch [:wallet/cancel-transaction-command])}]
[react/view {:flex-direction :row :padding-horizontal 24 :align-items :center
:margin-vertical (if small-screen? 8 16)}
[react/text-input
{:style {:font-size (if small-screen? 24 38)
:color (when amount-error colors/red)
:flex-shrink 1}
:keyboard-type :numeric
:accessibility-label :amount-input
:default-value amount-text
:editable (not request?)
:auto-focus true
:on-change-text #(re-frame/dispatch [:wallet.send/set-amount-text %])
:placeholder "0.0 "}]
[asset-selector tx]
(when amount-error
[tooltip/tooltip (if from
amount-error
(i18n/label :t/select-account-first))
{:bottom-value 2
:font-size 12}])]
[components/separator]
(when-not small-screen?
[list-item/list-item {:type :section-header :title :t/from}])
[react/view {:flex-direction :row :flex 1 :align-items :center}
(when small-screen?
[react/i18n-text {:style {:width 50 :text-align :right :color colors/gray} :key :t/from}])
[react/view {:flex 1}
[render-account from token :wallet.send/set-field]]]
(when-not small-screen?
[list-item/list-item {:type :section-header :title :t/to}])
[react/view {:flex-direction :row :flex 1 :align-items :center}
(when small-screen?
[react/i18n-text {:style {:width 50 :text-align :right :color colors/gray} :key :t/to}])
[react/view {:flex 1}
[render-contact to from-chat?]]]
[toolbar/toolbar
{:center
{:label :t/wallet-send
:accessibility-label :send-transaction-bottom-sheet
:disabled? (not sign-enabled?)
:on-press #(re-frame/dispatch
[(cond
request?
:wallet.ui/sign-transaction-button-clicked-from-request
from-chat?
:wallet.ui/sign-transaction-button-clicked-from-chat
:else
:wallet.ui/sign-transaction-button-clicked) tx])}}]])))
(views/defview request-sheet [_]
(views/letsubs [{:keys [amount-error amount-text from token to sign-enabled? from-chat?] :as tx}
[:wallet.request/prepare-transaction-with-balance]
window-height [:dimensions/window-height]
keyboard-height [:keyboard-height]]
(let [small-screen? (< (- window-height keyboard-height) 450)]
[react/view {:style (styles/sheet small-screen?)}
[header {:small-screen? small-screen?
:label :t/request-transaction
:on-cancel #(re-frame/dispatch [:wallet/cancel-transaction-command])}]
[react/view {:flex-direction :row :padding-horizontal 24 :align-items :center
:margin-vertical (if small-screen? 8 16)}
[react/text-input
@ -97,32 +161,54 @@
:accessibility-label :amount-input
:default-value amount-text
:auto-focus true
:on-change-text #(re-frame/dispatch [:wallet.send/set-amount-text %])
:on-change-text #(re-frame/dispatch [:wallet.request/set-amount-text %])
:placeholder "0.0 "}]
[asset-selector tx]
(when amount-error
[tooltip/tooltip amount-error {:bottom-value 2
:font-size 12}])]
[components/separator]
(when-not small-screen?
[list-item/list-item {:type :section-header :title :t/from}])
[react/view {:flex-direction :row :flex 1 :align-items :center}
(when small-screen?
[react/i18n-text {:style {:width 50 :text-align :right :color colors/gray} :key :t/from}])
[react/view {:flex 1}
[render-account from token]]]
(when-not small-screen?
[list-item/list-item {:type :section-header :title :t/to}])
[react/view {:flex-direction :row :flex 1 :align-items :center}
(when small-screen?
[react/i18n-text {:style {:width 50 :text-align :right :color colors/gray} :key :t/to}])
[react/view {:flex 1}
[render-contact to from-chat?]]]
[render-account from token :wallet.request/set-field]]]
[toolbar/toolbar
{:center {:label :t/wallet-send
:accessibility-label :send-transaction-bottom-sheet
:disabled? (not sign-enabled?)
:on-press #(re-frame/dispatch [:wallet.ui/sign-transaction-button-clicked tx])}}]])))
{:center
{:label :t/wallet-request
:accessibility-label :request-transaction-bottom-sheet
:disabled? (not sign-enabled?)
:on-press #(re-frame/dispatch
[:wallet.ui/request-transaction-button-clicked tx])}}]])))
(views/defview select-account-sheet [{:keys [from message]}]
(views/letsubs [window-height [:dimensions/window-height]
keyboard-height [:keyboard-height]]
(let [small-screen? (< (- window-height keyboard-height) 450)]
[react/view {:style (styles/sheet small-screen?)}
[header {:small-screen? small-screen?
:label :t/select-account
:on-cancel #(re-frame/dispatch [:set :commands/select-account nil])}]
[react/view {:flex-direction :row :padding-horizontal 24 :align-items :center
:margin-vertical (if small-screen? 8 16)}]
(when-not small-screen?
[list-item/list-item {:type :section-header :title :t/from}])
[react/view {:flex-direction :row :flex 1 :align-items :center}
(when small-screen?
[react/i18n-text {:style {:width 50 :text-align :right :color colors/gray} :key :t/from}])
[react/view {:flex 1}
[render-account from nil ::commands/set-selected-account]]]
[toolbar/toolbar
{:center
{:label :t/select
:accessibility-label :select-account-bottom-sheet
:disabled? (nil? from)
:on-press #(re-frame/dispatch
[::commands/accept-request-address-for-transaction
(:message-id message)
(:address from)])}}]])))
(defview prepare-transaction []
(letsubs [tx [:wallet/prepare-transaction]]
@ -130,6 +216,26 @@
;;we use select-keys here because we don't want to update view if other keys in map are changed
;; and because modal screen (qr code scanner) can't be opened over bottom sheet we have to use :modal-opened?
;; to hide our transaction panel
(when (and tx (not (:modal-opened? tx)))
(when (and tx
(not (:modal-opened? tx))
(not (:request-command? tx)))
(select-keys tx [:from-chat?]))
sheet]))
sheet]))
(defview request-transaction []
(letsubs [tx [:wallet/prepare-transaction]]
[bottom-panel/animated-bottom-panel
;;we use select-keys here because we don't want to update view if other keys in map are changed
;; and because modal screen (qr code scanner) can't be opened over bottom sheet we have to use :modal-opened?
;; to hide our transaction panel
(when (and tx
(not (:modal-opened? tx))
(:request-command? tx))
(select-keys tx [:from-chat? :request?]))
request-sheet]))
(defview select-account []
(letsubs [data [:commands/select-account]]
[bottom-panel/animated-bottom-panel
data
select-account-sheet]))

View File

@ -3,6 +3,7 @@
[re-frame.core :as re-frame]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.constants :as constants]
[status-im.chat.models.message :as chat.message]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.json-rpc :as json-rpc]
@ -343,7 +344,6 @@
(flatten (map keys (vals balances))))]
(fx/merge cofx
(multiaccounts.update/multiaccount-update
cofx
:wallet/visible-tokens (assoc visible-tokens
chain
chain-visible-tokens)
@ -366,29 +366,151 @@
[{:keys [db]} amount]
{:db (assoc-in db [:wallet/prepare-transaction :amount-text] amount)})
(fx/defn set-and-validate-request-amount
{:events [:wallet.request/set-amount-text]}
[{:keys [db]} amount]
{:db (assoc-in db [:wallet/prepare-transaction :amount-text] amount)})
(fx/defn sign-transaction-button-clicked-from-chat
{:events [:wallet.ui/sign-transaction-button-clicked-from-chat]}
[{:keys [db] :as cofx} {:keys [to amount from token request? from-chat? gas gasPrice]}]
(let [{:keys [symbol address]} token
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
from-address (:address from)
identity (:current-chat-id db)]
(fx/merge cofx
{:db (-> db
(update-in [:chat-ui-props identity] dissoc :input-bottom-sheet)
(dissoc :wallet/prepare-transaction))
;;TODO from chat, send request message or if ens name sign tx and send tx message
::json-rpc/call [{:method "shhext_requestAddressForTransaction"
:params [(:current-chat-id db)
from-address
amount
(when-not (= symbol :ETH)
address)]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})))
(fx/defn request-transaction-button-clicked-from-chat
{:events [:wallet.ui/request-transaction-button-clicked]}
[{:keys [db] :as cofx} {:keys [to amount from token from-chat? gas gasPrice]}]
(let [{:keys [symbol address]} token
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
from-address (:address from)
identity (:current-chat-id db)]
(fx/merge cofx
{:db (-> db
(update-in [:chat-ui-props identity] dissoc :input-bottom-sheet)
(dissoc db :wallet/prepare-transaction))
::json-rpc/call [{:method "shhext_requestTransaction"
:params [(:public-key to)
amount
(when-not (= symbol :ETH)
address)
from-address]
:on-success #(re-frame/dispatch [:transport/message-sent % 1])}]})))
(fx/defn accept-request-transaction-button-clicked-from-command
{:events [:wallet.ui/accept-request-transaction-button-clicked-from-command]}
[{:keys [db] :as cofx} chat-id {:keys [address value from id contract] :as request-parameters}]
(let [identity (:current-chat-id db)
all-tokens (:wallet/all-tokens db)
current-network-string (:networks/current-network db)
prices (:prices db)
all-networks (:networks/networks db)
current-network (get all-networks current-network-string)
chain (ethereum/network->chain-keyword current-network)
{:keys [symbol icon decimals] :as token}
(if (seq contract)
(get (get all-tokens chain) contract)
(tokens/native-currency chain))
amount-text (str (money/internal->formatted value symbol decimals))]
{:db (assoc db :wallet/prepare-transaction
{:from (ethereum/get-default-account (:multiaccount/accounts db))
:to (or (get-in db [:contacts/contacts identity])
(-> identity
contact.db/public-key->new-contact
contact.db/enrich-contact))
:request-parameters request-parameters
:chat-id chat-id
:symbol symbol
:amount-text amount-text
:request? true
:from-chat? true})}))
(fx/defn sign-transaction-button-clicked-from-request
{:events [:wallet.ui/sign-transaction-button-clicked-from-request]}
[{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice]}]
(let [{:keys [request-parameters]} (:wallet/prepare-transaction db)
{:keys [symbol address]} token
amount-hex (str "0x" (abi-spec/number-to-hex amount))
to-norm (:address request-parameters)
from-address (:address from)]
(fx/merge cofx
{:db (dissoc db :wallet/prepare-transaction)}
(fn [cofx]
(signing/sign cofx {:tx-obj (if (= symbol :ETH)
{:to to-norm
:from from-address
:message-id (:id request-parameters)
:command? true
:value amount-hex}
{:to (ethereum/normalized-hex address)
:from from-address
:command? true
:message-id (:id request-parameters)
:data (abi-spec/encode
"transfer(address,uint256)"
[to-norm amount-hex])
;;Note: data from qr (eip681)
:gas gas
:gasPrice gasPrice})})))))
(fx/defn sign-transaction-button-clicked
{:events [:wallet.ui/sign-transaction-button-clicked]}
[{:keys [db] :as cofx} {:keys [to amount from token from-chat? gas gasPrice]}]
[{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice]}]
(let [{:keys [symbol address]} token
amount-hex (str "0x" (abi-spec/number-to-hex amount))
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
from-address (:address from)]
(fx/merge cofx
{:db (dissoc db :wallet/prepare-transaction)}
#(if from-chat?
nil;;TODO from chat, send request message or if ens name sign tx and send tx message
(signing/sign % {:tx-obj (if (= symbol :ETH)
{:to to-norm
:from from-address
:value amount-hex}
{:to (ethereum/normalized-hex address)
:from from-address
:data (abi-spec/encode
"transfer(address,uint256)"
[to-norm amount-hex])
;;Note: data from qr (eip681)
:gas gas
:gasPrice gasPrice})})))))
(fn [cofx]
(signing/sign cofx {:tx-obj (if (= symbol :ETH)
{:to to-norm
:from from-address
:value amount-hex}
{:to (ethereum/normalized-hex address)
:from from-address
:data (abi-spec/encode
"transfer(address,uint256)"
[to-norm amount-hex])
;;Note: data from qr (eip681)
:gas gas
:gasPrice gasPrice})})))))
(fx/defn sign-transaction-button-clicked-from-command
{:events [:wallet.ui/sign-transaction-button-clicked]}
[{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice]}]
(let [{:keys [symbol address]} token
amount-hex (str "0x" (abi-spec/number-to-hex amount))
to-norm (ethereum/normalized-hex (if (string? to) to (:address to)))
from-address (:address from)]
(fx/merge cofx
{:db (dissoc db :wallet/prepare-transaction)}
(fn [cofx]
(signing/sign cofx {:tx-obj (if (= symbol :ETH)
{:to to-norm
:from from-address
:value amount-hex}
{:to (ethereum/normalized-hex address)
:from from-address
:data (abi-spec/encode
"transfer(address,uint256)"
[to-norm amount-hex])
;;Note: data from qr (eip681)
:gas gas
:gasPrice gasPrice})})))))
(fx/defn set-and-validate-amount-request
{:events [:wallet.request/set-and-validate-amount]}
@ -410,7 +532,7 @@
[{:keys [db]}]
(let [identity (:current-chat-id db)]
{:db (assoc db :wallet/prepare-transaction
{:from (ethereum/get-default-account (get db [:multiaccount/accounts]))
{:from (ethereum/get-default-account (:multiaccount/accounts db))
:to (or (get-in db [:contacts/contacts identity])
(-> identity
contact.db/public-key->new-contact
@ -418,6 +540,20 @@
:symbol :ETH
:from-chat? true})}))
(fx/defn prepare-request-transaction-from-chat
{:events [:wallet/prepare-request-transaction-from-chat]}
[{:keys [db]}]
(let [identity (:current-chat-id db)]
{:db (assoc db :wallet/prepare-transaction
{:from (ethereum/get-default-account (:multiaccount/accounts db))
:to (or (get-in db [:contacts/contacts identity])
(-> identity
contact.db/public-key->new-contact
contact.db/enrich-contact))
:symbol :ETH
:from-chat? true
:request-command? true})}))
(fx/defn prepare-transaction-from-wallet
{:events [:wallet/prepare-transaction-from-wallet]}
[{:keys [db]} account]
@ -427,6 +563,24 @@
:symbol :ETH
:from-chat? false})})
(fx/defn cancel-transaction-command
{:events [:wallet/cancel-transaction-command]}
[{:keys [db]}]
(let [identity (:current-chat-id db)]
{:db (-> db
(dissoc :wallet/prepare-transaction)
(update-in [:chat-ui-props identity] dissoc :input-bottom-sheet))}))
(fx/defn finalize-transaction-from-command
{:events [:wallet/finalize-transaction-from-command]}
[{:keys [db]} account to symbol amount]
{:db (assoc db :wallet/prepare-transaction
{:from account
:to to
:symbol symbol
:amount amount
:from-command? true})})
(fx/defn qr-scanner-allowed
{:events [:wallet.send/qr-scanner-allowed]}
[{:keys [db] :as cofx} options]
@ -449,6 +603,13 @@
{:db (assoc-in db [:wallet/prepare-transaction field] value)}
(bottom-sheet/hide-bottom-sheet)))
(fx/defn wallet-request-set-field
{:events [:wallet.request/set-field]}
[{:keys [db] :as cofx} field value]
(fx/merge cofx
{:db (assoc-in db [:wallet/prepare-transaction field] value)}
(bottom-sheet/hide-bottom-sheet)))
(fx/defn navigate-to-recipient-code
{:events [:wallet.send/navigate-to-recipient-code]}
[{:keys [db] :as cofx}]

View File

@ -3,6 +3,6 @@
"owner": "status-im",
"repo": "status-go",
"version": "v0.39.2",
"commit-sha1": "5546ce8c3001b76a5d741a20177497dce3e30653",
"src-sha256": "1h72gld4hhrhz6g9c2anzzbawxzapswg47d1vdn9w7q7zwm8pisb"
"commit-sha1": "88a1d0111e9a9d51370f14ad6b2c998f4514639b",
"src-sha256": "0vdkjxi3vj6fv5ypq98g6swrq4v020dzm45n9d3vwbk3j7ln6p40"
}

View File

@ -128,6 +128,12 @@
:timestamp 3
:whisper-timestamp 3}]
current-list (s/add-many nil current-messages)]
(testing "removing a message"
(let [updated-list (-> (s/remove-message current-list {:clock-value 106
:message-id "106"})
(s/->seq))]
(is (= 2 (count updated-list)))
(is (= 103 (-> (nth updated-list 1) :clock-value)))))
(testing "inserting a newer message"
(let [new-message {:timestamp 12
:clock-value 112

View File

@ -15,7 +15,6 @@
contacts {"0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f"
{:last-updated 0,
:address "eca8218b5ebeb2c47ba94c1b6e0a779d78fff7bc",
:name "User B",
:photo-path "photo1",
:last-online 0,
@ -23,7 +22,6 @@
"0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f"
:system-tags #{}}}
current-multiaccount {:last-updated 0,
:address "f23d28f538fd8cd4a90c2d96ca89f5bccca5383f",
:signed-up? true,
:sharing-usage-data? false,
:name "User A",
@ -38,7 +36,6 @@
:identicon "generated"
:alias "generated"
:admin? true
:address "71adb0644e2b590e37dafdfea8bd58f0c7668c7f"
:public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"
:system-tags #{}}
{:name "User A"
@ -47,7 +44,6 @@
{:last-updated 0
:name "User B"
:photo-path "photo1"
:address "eca8218b5ebeb2c47ba94c1b6e0a779d78fff7bc"
:last-online 0
:public-key "0x04985040682b77a32bb4bb58268a0719bd24ca4d07c255153fe1eb2ccd5883669627bd1a092d7cc76e8e4b9104327667b19dcda3ac469f572efabe588c38c1985f"
:system-tags #{}}]))))))

View File

@ -19,6 +19,7 @@
:response-to "a"}
:whisper-timestamp 1
:outgoing-status :sending
:command-parameters nil
:outgoing true
:message-type 0
:clock-value 2

View File

@ -6,7 +6,6 @@
[status-im.contact.core :as model]))
(def public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917")
(def address "71adb0644e2b590e37dafdfea8bd58f0c7668c7f")
(deftest handle-contact-update-test
(with-redefs [json-rpc/call (constantly nil)]
@ -16,16 +15,14 @@
public-key
1
{:name "name"
:profile-image "image"
:address "address"})
:profile-image "image"})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it adds a new contact"
(is (= {:public-key public-key
:photo-path "image"
:name "name"
:last-updated 1000
:system-tags #{:contact/request-received}
:address "address"}
:system-tags #{:contact/request-received}}
contact)))))
(testing "the contact is already in contacts"
(testing "timestamp is greater than last-updated"
@ -35,13 +32,11 @@
:photo-path "old-image"
:name "old-name"
:last-updated 0
:system-tags #{:contact/added}
:address "old-address"}}}}
:system-tags #{:contact/added}}}}}
public-key
1
{:name "new-name"
:profile-image "new-image"
:address "new-address"})
:profile-image "new-image"})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it updates the contact and adds contact/request-received to system tags"
(is (= {:public-key public-key
@ -49,8 +44,7 @@
:name "new-name"
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:address "new-address"}
:system-tags #{:contact/added :contact/request-received}}
contact)))))
(testing "timestamp is equal to last-updated"
(let [actual (model/handle-contact-update
@ -59,13 +53,11 @@
:photo-path "old-image"
:name "old-name"
:last-updated 1000
:system-tags #{:contact/added}
:address "old-address"}}}}
:system-tags #{:contact/added}}}}}
public-key
1
{:name "new-name"
:profile-image "new-image"
:address "new-address"})
:profile-image "new-image"})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it does nothing"
(is (nil? actual)))))
@ -76,13 +68,11 @@
:photo-path "old-image"
:name "old-name"
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:address "old-address"}}}}
:system-tags #{:contact/added :contact/request-received}}}}}
public-key
0
{:name "new-name"
:profile-image "new-image"
:address "new-address"})
:profile-image "new-image"})
contact (get-in actual [:db :contacts/contacts public-key])]
(testing "it does nothing"
(is (nil? actual))))))
@ -106,8 +96,7 @@
:name "new-name"
:last-updated 1000
:system-tags #{:contact/added :contact/request-received}
:address address} contact)))))
:system-tags #{:contact/added :contact/request-received}} contact)))))
(testing "the message is coming from us"
(testing "it does not update contacts"
(is (nil? (model/handle-contact-update {:db {:multiaccount {:public-key "me"}}} "me" 1 {})))))))
@ -121,7 +110,6 @@
expected {(str "0x" pk1) {:alias "generated"
:identicon "generated"
:name "name-1"
:address "6dd28d3d14c6ded091ed38a6735350ce92fe1956"
:ens-verified true
:ens-verified-at 1
:public-key (str "0x" pk1)
@ -129,7 +117,6 @@
(str "0x" pk2) {:alias "generated"
:name "name-2"
:identicon "generated"
:address "7ab91a68f65c1365d8071302a71599273acb68a2"
:ens-verified false
:ens-verified-at 2
:public-key (str "0x" pk2)

View File

@ -5,6 +5,7 @@
"about-names-content": "No one can pretend to be you! Youre anonymous by default and never have to reveal your real name. You can register a custom name for a small fee.",
"about-names-title": "Names cant be changed",
"access-key": "Access existing keys",
"accept-and-share-address": "Accept and share address",
"account-added": "Account added",
"account-color": "Account color",
"account-name": "Account name",
@ -28,6 +29,9 @@
"add-to-contacts": "Add to contacts",
"add-to-contacts-text": "By adding a user to your contact list, you share your wallet address",
"address": "Address",
"address-received": "Address received",
"address-requested": "Address requested",
"address-request-accepted": "Address request accepted",
"advanced": "Advanced",
"advanced-settings": "Advanced settings",
"agree-by-continuing": "By continuing you agree\n to our ",
@ -306,6 +310,7 @@
"datetime-today": "today",
"datetime-yesterday": "yesterday",
"decimals": "Decimals",
"decline": "Decline",
"decryption-failed-confirm": "Apply",
"decryption-failed-content": "We were not able to decrypt your data, you might need to create new multiaccount and erase your old data by tapping “Apply”. Clicking on “Cancel”, will try again",
"decryption-failed-title": "We were not able to decrypt your data",
@ -518,6 +523,7 @@
"importing-keycard-multiaccount": "Importing keycard multiaccount",
"in-contacts": "In contacts",
"incoming": "Incoming",
"incoming-transaction": "Incoming transaction",
"incorrect-code": [
"str",
"Sorry the code was incorrect, please enter it again"
@ -755,6 +761,7 @@
"or": "OR",
"or-choose-a-contact": "Or choose a contact",
"outgoing": "Outgoing",
"outgoing-transaction": "Outgoing transaction",
"pair": "Pair devices",
"pair-card": "Pair to this device",
"pair-card-question": "Card is ready to pair",
@ -876,8 +883,11 @@
"security": "Security",
"see-details": "See details",
"see-it-again": "SEE IT AGAIN",
"select-account-first": "Select an account first",
"select-chat": "Select chat to start messaging",
"selected": "Selected",
"select": "Select",
"select-account": "Select account",
"selected-for-you": "Selected for you",
"send-command-payment": "Send a payment",
"send-logs": "Report a bug",
@ -901,6 +911,7 @@
"set-dapp-access-permissions": "Set DApp access permissions",
"settings": "Settings",
"share": "Share",
"shared": "Shared",
"share-address": "Share address",
"share-chat": "Share chat",
"share-contact-code": "Share my chat key",
@ -917,6 +928,7 @@
"show-more": "Show more",
"show-qr": "Show QR code",
"sidechain-text": "Youre on the {{sidechain}} Sidechain.",
"sign-and-send": "Sign and send",
"sign-in": "Unlock",
"sign-in-to-another": "Unlock another multiaccount",
"sign-in-to-status": "Unlock Status",
@ -981,6 +993,7 @@
"token-details": "Token details",
"topic-name-error": "Use only lowercase letters (a to z), numbers & dashes (-). Do not use chat keys",
"transaction": "Transaction",
"transaction-declined": "Transaction declined",
"transaction-description": "Consider it complete after 12 confirmations on the network.",
"transaction-details": "Transaction details",
"transaction-failed": "Transaction failed",