implement new wallet flow

This commit is contained in:
Adrian Tiberius 2016-10-20 16:51:37 +03:00 committed by Roman Volosovskyi
parent 788cbc34f3
commit 083ade766e
30 changed files with 517 additions and 127 deletions

View File

@ -117,7 +117,7 @@ function sendTransaction(params, context) {
}
}
status.command({
var send = {
name: "send",
icon: "money_white",
color: "#5fc48d",
@ -134,4 +134,36 @@ status.command({
},
handler: sendTransaction,
validator: validateBalance
};
status.command(send);
status.response(send);
status.command({
name: "request",
color: "#7099e6",
description: "Transaction request",
params: [{
name: "amount",
type: status.types.NUMBER
}],
preview: function (params) {
return status.components.text(
{},
params.amount + " ETH"
);
},
handler: function (params) {
return {
event: "request",
params: [params.amount]
request: {
command: "send",
params: {
amount: params.amount
},
content: "Requesting " + params.amount + "ETH"
}
};
},
});

View File

@ -1,6 +1,7 @@
var _status_catalog = {
commands: {},
responses: {}
responses: {},
functions: {}
},
status = {};
@ -31,6 +32,7 @@ Command.prototype.create = function (com) {
this.preview = com.preview;
this["suggestions-trigger"] = com.suggestionsTrigger || "on-change";
this.fullscreen = com.fullscreen;
this.request = com.request;
this.addToCatalog();
return this;
@ -153,6 +155,9 @@ var status = {
var response = new Response();
return response.create(h);
},
registerFunction: function (name, fn){
_status_catalog.functions[name] = fn;
},
autorun: function (commandName) {
_status_catalog.autorun = commandName;
},

View File

@ -25,3 +25,13 @@ status.command({
});
status.autorun("browse");
status.registerFunction("send", function (params, context) {
var data = {
from: context.from,
to: params.address,
value: web3.toWei(params.amount, "ether")
};
web3.eth.sendTransaction(data);
})

View File

@ -113,3 +113,56 @@
{:flex 1
:color color-white
:fontSize 16})
;wallet-qr-code.cljs
(def wallet-qr-code
{:flex 1
:flex-direction :column})
(def account-toolbar
{:background-color "#2f3031"
:padding-bottom 45})
(def wallet-account-container
{:flex 1
:flexDirection :row
:height 69
:alignItems :center
:justifyContent :center})
(def qr-code
{:align-items :center
:padding-vertical 40})
(def footer
{:position :absolute
:left 0
:right 0
:bottom 0
:height 166
:background-color "#2f3031"})
(def wallet-info
{:align-items :center
:padding-top 42
:padding-bottom 20})
(def wallet-name-text
{:color color-white
:padding-bottom 5})
(def wallet-address-text
{:color "#999999"
})
(def done-button
{:flex 1
:flex-direction :column
:align-items :center
:height 60
:padding-top 20
:background-color "#7597e4"})
(def done-button-text
{:color color-white})

View File

@ -0,0 +1,44 @@
(ns status-im.accounts.views.wallet-qr-code
(:require-macros [status-im.utils.views :refer [defview]])
(:require [status-im.components.react :refer [view
text
image
touchable-highlight]]
[status-im.components.styles :refer [icon-close]]
[status-im.components.qr-code :refer [qr-code]]
[re-frame.core :refer [dispatch subscribe]]
[status-im.accounts.styles :as st]
[status-im.i18n :refer [label]]
[clojure.string :as s]))
(defview wallet-qr-code []
[{:keys [address photo-path name] :as account} [:get-current-account]
{:keys [amount]} [:get :contacts-click-params]]
[view st/wallet-qr-code
[view st/account-toolbar
[view st/wallet-account-container
[view st/photo-container
[view st/account-photo-container
[image {:source {:uri (if (s/blank? photo-path) :avatar photo-path)}
:style st/photo-image}]]]
[view st/name-container
[text {:style st/name-text
:number-of-lines 1} name]]
[view st/online-container
[touchable-highlight {:onPress #(dispatch [:navigate-back])}
[image {:source {:uri :icon-close-white}
:style icon-close}]]]]]
[view st/qr-code
[qr-code {:value (prn-str {:address address
:amount amount})
:size 200}]]
[view st/footer
[view st/wallet-info
[text {:style st/wallet-name-text} (label :t/main-wallet)]
[text {:style st/wallet-address-text} address]]
[touchable-highlight {:onPress #(dispatch [:navigate-back])}
[view st/done-button
[text {:style st/done-button-text} (label :t/done)]]]]])

View File

@ -7,7 +7,9 @@
[status-im.subs]
[status-im.components.react :refer [app-registry
keyboard
orientation]]
orientation
view
modal]]
[status-im.components.main-tabs :refer [main-tabs]]
[status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]]
@ -28,7 +30,9 @@
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
status-im.data-store.core
[taoensso.timbre :as log]
[status-im.components.status :as status]))
[status-im.components.status :as status]
[status-im.chat.styles.screen :as st]
[status-im.accounts.views.wallet-qr-code :refer [wallet-qr-code]]))
(defn init-back-button-handler! []
(let [new-listener (fn []
@ -55,7 +59,8 @@
(let [signed-up? (subscribe [:signed-up?])
view-id (subscribe [:get :view-id])
account-id (subscribe [:get :current-account-id])
keyboard-height (subscribe [:get :keyboard-height])]
keyboard-height (subscribe [:get :keyboard-height])
modal-view (subscribe [:get :modal])]
(log/debug "Current account: " @account-id)
(r/create-class
{:component-will-mount
@ -75,7 +80,7 @@
(.addListener keyboard
"keyboardDidHide"
#(when-not (= 0 @keyboard-height)
(dispatch [:set :keyboard-height 0]))))
(dispatch [:set :keyboard-height 0]))))
:render
(fn []
(when @view-id
@ -101,14 +106,28 @@
:recover recover
:confirm confirm
:my-profile my-profile)]
[component]))))})))
[view
{:flex 1}
[component]
(when @modal-view
[view
st/chat-modal
[modal {:animation-type :slide
:transparent false
:on-request-close #(dispatch [:navigate-back])}
(let [component (case @modal-view
:qr-scanner qr-scanner
:wallet-qr-code wallet-qr-code
:confirm confirm
:contact-list-modal contact-list)]
[component])]])]))))})))
(defn init [& [env]]
(dispatch-sync [:reset-app])
(.registerComponent app-registry "StatusIm" #(r/reactify-component app-root)
(.registerComponent app-registry "StatusIm" #(r/reactify-component app-root))
(dispatch [:listen-to-network-status!])
(dispatch [:initialize-crypt])
(dispatch [:initialize-geth])
(status/set-soft-input-mode status/adjust-resize)
(dispatch [:load-user-phone-number])
(init-back-button-handler!)))
(init-back-button-handler!))

View File

@ -24,7 +24,8 @@
valid-mobile-number?]]
[status-im.components.status :as status]
[status-im.utils.types :refer [json->clj]]
[status-im.chat.handlers.commands :refer [command-prefix]]
status-im.chat.handlers.commands
[status-im.commands.utils :refer [command-prefix]]
[status-im.chat.utils :refer [console? not-console?]]
[status-im.constants :refer [console-chat-id]]
[status-im.utils.gfycat.core :refer [generate-gfy]]
@ -324,8 +325,9 @@
(when (= current-chat-id wallet-chat-id)
(dispatch [:cancel-command]))
(dispatch [:load-requests! chat-id])
(when-not commands-loaded?
(dispatch [:load-commands! chat-id]))
(if-not commands-loaded?
(dispatch [:load-commands! chat-id])
(dispatch [:invoke-chat-loaded-callbacks chat-id]))
(if (and (seq messages)
(not= (count messages) 1))
db'
@ -333,6 +335,26 @@
load-messages!
init-chat))))
(register-handler :add-chat-loaded-callback
(fn [db [_ chat-id callback]]
(log/debug "Add chat loaded callback: " chat-id callback)
(update-in db [::chat-loaded-callbacks chat-id] conj callback)))
(register-handler ::clear-chat-loaded-callbacks
(fn [db [_ chat-id]]
(log/debug "Clear chat loaded callback: " chat-id)
(assoc-in db [::chat-loaded-callbacks chat-id] nil)))
(register-handler :invoke-chat-loaded-callbacks
(u/side-effect!
(fn [db [_ chat-id]]
(log/debug "Invoking chat loaded callbacks: " chat-id)
(let [callbacks (get-in db [::chat-loaded-callbacks chat-id])]
(log/debug "Invoking chat loaded callbacks: " callbacks)
(doseq [callback callbacks]
(callback))
(dispatch [::clear-chat-loaded-callbacks chat-id])))))
(defn prepare-chat [{:keys [contacts]} chat-id chat]
(let [name (get-in contacts [chat-id :name])]
(merge {:chat-id chat-id

View File

@ -9,14 +9,13 @@
[status-im.i18n :as i18n]
[status-im.utils.datetime :as time]
[status-im.utils.random :as random]
[status-im.utils.platform :as platform]))
(def command-prefix "c ")
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]))
(defn content-by-command
[{:keys [type]} content]
(if (and (= :command type) content)
(subs content (count command-prefix))
(subs content (count cu/command-prefix))
content))
(defn invoke-suggestions-handler!
@ -54,7 +53,7 @@
(after cancel-command!)
(after #(dispatch [:clear-validation-errors]))]
(fn [{:keys [current-chat-id] :as db} [_ content]]
(let [starts-as-command? (str/starts-with? content command-prefix)
(let [starts-as-command? (str/starts-with? content cu/command-prefix)
command? (= :command (current-command db :type))
{:keys [parameter-idx command]} (commands/get-command-input db)
parameter-name (-> command :params (get parameter-idx) :name)]
@ -65,10 +64,10 @@
(assoc db :canceled-command (and command? (not starts-as-command?)))))))
(defn invoke-command-preview!
[{:keys [staged-command] :as db} [_ chat-id]]
[{:keys [staged-command] :as db} [_ command-input chat-id]]
(let [{:keys [command id]} staged-command
{:keys [name type]} command
parameters (:params (commands/get-command-input db))
parameters (:params (or command-input (commands/get-command-input db)))
path [(if (= :command type) :commands :responses)
name
:preview]
@ -88,7 +87,7 @@
(register-handler ::validate!
(u/side-effect!
(fn [_ [_ {:keys [chat-id handler]} {:keys [error result]}]]
(fn [_ [_ command-input {:keys [chat-id handler]} {:keys [error result]}]]
;; todo handle error
(when-not error
(let [{:keys [errors validationHandler parameters]} (:returned result)]
@ -97,18 +96,20 @@
validationHandler
(dispatch [::validation-handler!
command-input
chat-id
validationHandler
parameters])
:else (if handler
(handler)
(dispatch [::finish-command-staging chat-id]))))))))
(dispatch [::finish-command-staging command-input chat-id]))))))))
(register-handler :stage-command
(fn [{:keys [current-chat-id current-account-id] :as db}]
(let [command-input (commands/get-command-input db)
command (commands/get-chat-command db)]
(fn [{:keys [current-chat-id current-account-id] :as db} [_ command-input command]]
(let [command-input (or command-input (commands/get-command-input db))
command (or command (commands/get-chat-command db))]
(log/debug "Staging command 1: " command-input command)
(dispatch [::start-command-validation! {:command-input command-input
:command command
:chat-id current-chat-id
@ -118,9 +119,9 @@
(register-handler ::finish-command-staging
[(after #(dispatch [:start-cancel-command]))
(after invoke-command-preview!)]
(fn [db [_ chat-id]]
(fn [db [_ command-input chat-id]]
(let [db (assoc-in db [:chats chat-id :input-text] nil)
{:keys [command content to-message-id params]} (command-input db)
{:keys [command content to-message-id params]} (or command-input (command-input db))
command-info {:command command
:params params
:to-message to-message-id
@ -140,7 +141,7 @@
[{:keys [current-chat-id] :as db} [_ command-key type]]
(-> db
(commands/set-command-input (or type :commands) command-key)
(assoc-in [:chats current-chat-id :command-input :content] command-prefix)
(assoc-in [:chats current-chat-id :command-input :content] cu/command-prefix)
(assoc :disable-input true)))
(register-handler :set-chat-command
@ -150,6 +151,7 @@
set-chat-command)
(defn set-response-command [db [_ to-message-id command-key]]
(log/debug "set-response-command: " to-message-id command-key)
(-> db
(commands/set-command-input :responses to-message-id command-key)
(assoc :canceled-command false)))
@ -186,9 +188,9 @@
:description (apply i18n/label (wrap-params description))}])))
(def validation-handlers
{:phone (fn [chat-id [number]]
{:phone (fn [command-input chat-id [number]]
(if (pn/valid-mobile-number? number)
(dispatch [::finish-command-staging chat-id])
(dispatch [::finish-command-staging command-input chat-id])
(dispatch-error! chat-id :t/phone-number :t/invalid-phone)))})
(defn validator [name]
@ -196,9 +198,9 @@
(register-handler ::validation-handler!
(u/side-effect!
(fn [_ [_ chat-id name params]]
(fn [_ [_ command-input chat-id name params]]
(when-let [handler (validator name)]
(handler chat-id params)))))
(handler command-input chat-id params)))))
(register-handler ::set-validation-error
(after #(dispatch [:fix-response-height]))
@ -251,7 +253,7 @@
(status/call-jail chat-id
path
parameters
#(dispatch [::validate! data %]))))))
#(dispatch [::validate! command-input data %]))))))
(register-handler :set-command-parameter
(fn [db [_ {:keys [value parameter]}]]

View File

@ -2,7 +2,8 @@
(:require [re-frame.core :refer [after dispatch enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.data-store.requests :as requests]
[status-im.utils.handlers :refer [register-handler] :as u]))
[status-im.utils.handlers :refer [register-handler] :as u]
[taoensso.timbre :as log]))
(defn store-request!
[{:keys [new-request] :as db}]
@ -15,6 +16,7 @@
:type (:command content)
:added (js/Date.)}
request' (update request :type keyword)]
(log/debug "Adding request: " request')
(-> db
(update-in [:chats chat-id :requests] conj request')
(assoc :new-request request))))

View File

@ -7,6 +7,7 @@
[status-im.utils.datetime :as time]
[re-frame.core :refer [enrich after dispatch path]]
[status-im.chat.utils :as cu]
[status-im.commands.utils :as commands-utils]
[status-im.constants :refer [text-content-type
content-type-command
content-type-command-request
@ -18,17 +19,20 @@
[status-im.chat.handlers.console :as console]))
(defn prepare-command
[identity chat-id clock-value
[identity chat-id clock-value request
{:keys [id preview preview-string params command to-message handler-data]}]
(let [content {:command (command :name)
:params params}]
(let [content (or request {:command (command :name)
:params params})]
{:message-id id
:from identity
:to chat-id
:timestamp (time/now-ms)
:content (assoc content :preview preview-string
:handler-data handler-data)
:content-type content-type-command
:handler-data handler-data
:type (name (:type command)))
:content-type (if request
content-type-command-request
content-type-command)
:outgoing true
:preview preview-string
:rendered-preview preview
@ -62,7 +66,7 @@
(u/side-effect!
(fn [_ [_ {:keys [commands message chat-id] :as params}]]
(doseq [{:keys [command] :as message} commands]
(let [params' (assoc params :staged-command message)
(let [params' (assoc params :staged-command message)
command-name (:name (:command message))]
(if (:sent-to-jail? message)
;; todo there could be other reasons for "long-running"
@ -88,11 +92,13 @@
(register-handler :prepare-command!
(u/side-effect!
(fn [{:keys [current-public-key] :as db}
[_ add-to-chat-id {:keys [chat-id staged-command handler-data] :as params}]]
[_ add-to-chat-id {:keys [chat-id staged-command command handler-data] :as params}]]
(let [{:keys [clock-value]} (get-in db [:chats add-to-chat-id])
request (:request (:handler-data command))
command' (->> (assoc staged-command :handler-data handler-data)
(prepare-command current-public-key chat-id clock-value)
(prepare-command current-public-key chat-id clock-value request)
(cu/check-author-direction db chat-id))]
(log/debug "Handler data: " request handler-data (dissoc params :commands :staged-command))
(dispatch [:clear-command chat-id (:id staged-command)])
(dispatch [::send-command! add-to-chat-id (assoc params :command command')])
@ -216,24 +222,25 @@
(register-handler ::send-command-protocol!
(u/side-effect!
(fn [{:keys [web3 current-public-key chats] :as db} [_ {:keys [chat-id command]}]]
(let [{:keys [content message-id clock-value]} command]
(when (cu/not-console? chat-id)
(let [{:keys [public-key private-key]} (chats chat-id)
{:keys [group-chat]} (get-in db [:chats chat-id])
payload {:content content
:content-type content-type-command
:timestamp (datetime/now-ms)
:clock-value clock-value}
options {:web3 web3
:message {:from current-public-key
:message-id message-id
:payload payload}}]
(if group-chat
(protocol/send-group-message! (assoc options
:group-id chat-id
:keypair {:public public-key
:private private-key}))
(protocol/send-message! (assoc-in options
[:message :to] chat-id)))))
(dispatch [:inc-clock chat-id])))))
(fn [{:keys [web3 current-public-key chats] :as db}
[_ {:keys [chat-id command]}]]
(log/debug "sending command: " command)
(when (cu/not-console? chat-id)
(let [{:keys [public-key private-key]} (chats chat-id)
{:keys [group-chat]} (get-in db [:chats chat-id])
payload (-> command
(select-keys [:content :content-type :clock-value])
(assoc :timestamp (datetime/now-ms)))
options {:web3 web3
:message {:from current-public-key
:message-id (:message-id command)
:payload payload}}]
(if group-chat
(protocol/send-group-message! (assoc options
:group-id chat-id
:keypair {:public public-key
:private private-key}))
(protocol/send-message! (assoc-in options
[:message :to] chat-id)))
(dispatch [:inc-clock chat-id]))))))

View File

@ -3,21 +3,70 @@
[status-im.utils.handlers :refer [register-handler]]
[status-im.utils.handlers :as u]
[status-im.utils.types :as t]
[taoensso.timbre :as log]))
[status-im.i18n :refer [label]]
[taoensso.timbre :as log]
[status-im.models.commands :as commands]
[status-im.commands.utils :as cu]
[status-im.components.status :as s]
[status-im.constants :as c]
[cljs.reader :refer [read-string]]))
(def web3 (js/require "web3"))
(defn by-public-key [public-key contacts]
(when-let [{:keys [address]} (contacts public-key)]
(when address {:address address})))
(defn scan-qr-handler
[{:keys [contacts]} [_ _ data]]
(log/debug "scaned qr" data)
(let [data' (read-string data)
data'' (cond
(map? data') data'
(.isAddress web3.prototype data') {:address data'}
(string? data') (by-public-key data' contacts)
:else nil)]
(when data''
(dispatch [:send-to-webview-bridge
{:params data''
:event (name :webview-send-transaction)}]))))
(register-handler :webview-address-from-qr
(u/side-effect! scan-qr-handler))
(register-handler :set-webview-bridge
(fn [db [_ bridge]]
(assoc db :webview-bridge bridge)))
(defn contacts-click-handler [whisper-identity]
#(dispatch [:chat-with-command whisper-identity :send]))
(defn contacts-click-handler [whisper-identity action params]
(log/debug "Contact clicked: " whisper-identity action params)
(dispatch [:navigate-back])
(when action
(if (= whisper-identity :qr-scan)
(if (= action :send)
(dispatch [:show-scan-qr :webview-address-from-qr])
(dispatch [:navigate-to-modal :wallet-qr-code]))
(dispatch [:chat-with-command whisper-identity action params]))))
(register-handler ::send-command
(u/side-effect!
(fn [db [_ command-key params]]
(let [command (commands/get-response-or-command :commands db command-key)
command-input {:content (str cu/command-prefix "0")
:command command
:parameter-idx 0
:params {"amount" (:amount params)}
:to-message-id nil}]
(log/debug "Staging command: " command-key command command-input)
(dispatch [:stage-command command-input command])))))
(defn chat-with-command
[_ [_ whisper-identity command]]
(dispatch [:start-chat whisper-identity {} :navigate-back])
[_ [_ whisper-identity command-key params]]
(dispatch [:remove-contacts-click-handler])
(let [callback #(dispatch [:set-chat-command command])]
(dispatch [:add-commands-loading-callback whisper-identity callback])))
(dispatch [:add-chat-loaded-callback whisper-identity
#(dispatch [::send-command command-key params])])
(dispatch [:start-chat whisper-identity]))
(register-handler :chat-with-command
(u/side-effect! chat-with-command))
@ -25,15 +74,47 @@
(register-handler :webview-bridge-message
(u/side-effect!
(fn [_ [_ message-string]]
(let [message (t/json->clj message-string)
event (keyword (:event message))]
(let [{:keys [event options] :as message} (t/json->clj message-string)
event' (keyword event)
params (:data options)]
(log/debug (str "message from webview: " message))
(case event
:webview-send-transaction (dispatch [:navigate-to :contact-list contacts-click-handler])
(log/error (str "Unknown event: " event)))))))
(case event'
:webview-send-transaction (dispatch [:show-contacts-menu contacts-click-handler :send params])
:webview-receive-transaction (dispatch [:show-contacts-menu contacts-click-handler :request params])
:webview-scan-qr (dispatch [:show-scan-qr :webview-address-from-qr])
:webview-send-eth (dispatch [:webview-send-eth! params])
(log/error (str "Unknown event: " event')))))))
(register-handler :show-contacts-menu
(after #(dispatch [:navigate-to-modal :contact-list-modal]))
(fn [db [_ click-handler action params]]
(assoc db :contacts-click-handler click-handler
:contacts-click-action action
:contacts-click-params params)))
(def qr-context {:toolbar-title (label :t/address)})
(register-handler :show-scan-qr
(after #(dispatch [:navigate-to-modal :qr-scanner qr-context]))
(fn [db [_ click-handler]]
(assoc-in db [:qr-codes qr-context] click-handler)))
(register-handler :send-to-webview-bridge
(u/side-effect!
(fn [{:keys [webview-bridge]} [_ data]]
(when webview-bridge
(.sendToBridge webview-bridge (t/clj->json data))))))
(register-handler :webview-send-eth!
(u/side-effect!
(fn [{:keys [current-account-id]} [_ {:keys [amount address]}]]
(let [context {:from current-account-id}
path [:functions :send]
parameters {:context context
:parameters {:amount amount
:address address}}]
(s/call-jail c/wallet-chat-id
path
parameters
(fn [data]
(log/debug :webview-send-eth-callback data)))))))

View File

@ -5,6 +5,7 @@
animated-view
text
icon
modal
touchable-highlight
list-view
list-item]]

View File

@ -191,3 +191,10 @@
(def bottom-info-row-text2
{:color "#888888"})
(def chat-modal
{:position :absolute
:left 0
:top 0
:right 0
:bottom 0})

View File

@ -49,16 +49,17 @@
(reaction (get-in @db [:command-suggestions @chat-id])))))
(register-sub :get-commands
(fn [db _]
(reaction (commands/get-commands @db))))
(fn [db [_ chat-id]]
(let [current-chat (or chat-id (@db :current-chat-id))]
(reaction (or (get-in @db [:chats current-chat :commands]) {})))))
(register-sub :get-chat-by-id
(fn [_ [_ chat-id]]
(reaction (chats/get-by-id chat-id))))
(register-sub :get-responses
(fn [db _]
(let [current-chat (@db :current-chat-id)]
(fn [db [_ chat-id]]
(let [current-chat (or chat-id (@db :current-chat-id))]
(reaction (or (get-in @db [:chats current-chat :responses]) {})))))
(register-sub :get-commands-and-responses

View File

@ -104,7 +104,10 @@
(str params))]))
(defview message-content-command [{:keys [content rendered-preview chat-id to from outgoing] :as message}]
[commands [:get-commands-and-responses (if outgoing to from)]
[commands [(if (= (:type content) "response")
:get-responses
:get-commands)
(if outgoing to from)]
current-chat-id [:get-current-chat-id]
contact-chat [:get-in [:chats (if outgoing to from)]]]
(let [{:keys [command params]} (parse-command-message-content commands content)
@ -341,6 +344,7 @@
:message-id message-id}])))
:reagent-render
(fn [{:keys [outgoing group-chat] :as message}]
(log/debug "I HAVE A MESSAGE: " message)
[message-container message
[view
(let [incoming-group (and group-chat (not outgoing))]

View File

@ -9,11 +9,13 @@
touchable-highlight]]
[status-im.chat.styles.message :as st]
[status-im.models.commands :refer [parse-command-request]]
[status-im.components.animation :as anim]))
[status-im.components.animation :as anim]
[taoensso.timbre :as log]))
(def request-message-icon-scale-delay 600)
(defn set-chat-command [message-id command]
(log/debug "set-chat-command: " message-id command)
(dispatch [:set-response-chat-command message-id (keyword (:name command))]))
(defn label [command]
@ -76,7 +78,8 @@
status-initialized? (subscribe [:get :status-module-initialized?])]
(fn [{:keys [message-id content from incoming-group]}]
(let [commands @commands-atom
{:keys [command content]} (parse-command-request commands content)]
{:keys [command content]} (parse-command-request commands content)
_ (log/debug "message-content: " command content)]
[view st/comand-request-view
[touchable-highlight
{:on-press (when (and (not @answered?) @status-initialized?)

View File

@ -25,7 +25,8 @@
[status-im.utils.datetime :as dt]
[taoensso.timbre :as log]
[status-im.utils.name :refer [shortened-name]]
[status-im.utils.js-resources :as js-res]))
[status-im.utils.js-resources :as js-res]
[status-im.commands.utils :as cu]))
(defn drag-icon []
[view st/drag-container
@ -117,7 +118,7 @@
(when-not (= "about:blank" url)
(if loading
(dispatch [:set-web-view-url url])
(dispatch [:set-chat-command-content (str "c " url)])))))
(dispatch [:set-chat-command-content (str cu/command-prefix url)])))))
(defn web-view-error []
(r/as-element

View File

@ -21,6 +21,7 @@
{:keys [result error]}]]
(let [{:keys [context returned]} result
{handler-error :error} returned]
(log/debug "command handler: " result error parameters)
(cond
handler-error
(log/debug :error-from-handler handler-error

View File

@ -59,6 +59,7 @@
(status/parse-jail identity file
(fn [result]
(let [{:keys [error result]} (json->clj result)]
(log/debug "Error parsing commands: " error result)
(if error
(dispatch [::loading-failed! identity ::error-in-jail error])
(if identity
@ -125,7 +126,8 @@
(after save-commands-js!)
(after #(dispatch [:check-autorun]))
(after (fn [_ [id]]
(dispatch [:invoke-commands-loading-callbacks id])))]
(dispatch [:invoke-commands-loading-callbacks id])
(dispatch [:invoke-chat-loaded-callbacks id])))]
add-commands)
(reg-handler ::add-all-commands

View File

@ -6,6 +6,8 @@
[re-frame.core :refer [dispatch trim-v debug]]
[status-im.utils.handlers :refer [register-handler]]))
(def command-prefix "c ")
(defn json->clj [json]
(when-not (= json "undefined")
(js->clj (.parse js/JSON json) :keywordize-keys true)))

View File

@ -30,6 +30,13 @@
[db [_ _ click-handler]]
(assoc db :contacts-click-handler click-handler))
(register-handler :remove-contacts-click-handler
(fn [db]
(dissoc db
:contacts-click-handler
:contacts-click-action)))
(defn save-contact
[_ [_ contact]]
(contacts/save contact))

View File

@ -211,3 +211,8 @@
(def qr-input
{:margin-right 42})
(def scan-qr-icon
{:margin 18
:width 25
:height 19})

View File

@ -8,6 +8,18 @@
(defn on-press [whisper-identity]
#(dispatch [:start-chat whisper-identity {} :navigation-replace]))
(defn letter-view [letter]
[view st/letter-container
(when letter
[text {:style st/letter-text} letter])])
(defview contact-view-with-letter [{:keys [whisper-identity letter] :as contact} click-handler action params]
[touchable-highlight
{:onPress #(click-handler whisper-identity action params)}
[view st/contact-container
[letter-view letter]
[contact-inner-view contact]]])
(defview contact-view [{:keys [whisper-identity] :as contact}]
[chat [:get-chat whisper-identity]]
[touchable-highlight

View File

@ -6,16 +6,20 @@
touchable-highlight
list-view
list-item]]
[status-im.contacts.views.contact :refer [contact-view on-press]]
[status-im.contacts.views.contact :refer [contact-view
on-press
contact-view-with-letter]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.styles :refer [toolbar-background1]]
[status-im.components.drawer.view :refer [drawer-view open-drawer]]
[status-im.components.styles :refer [icon-search]]
[status-im.components.styles :refer [icon-search
icon-back]]
[status-im.contacts.styles :as st]
[status-im.utils.listview :as lw]
[status-im.i18n :refer [label]]
[status-im.utils.platform :refer [platform-specific]]))
[status-im.utils.platform :refer [platform-specific]]
[status-im.contacts.views.contact-inner :refer [contact-inner-view]]))
(defn new-group-chat-view []
[touchable-highlight
@ -29,21 +33,42 @@
[text {:style st/name-text}
(label :t/new-group-chat)]]]]])
(defn render-row [click-handler]
(defn render-row [chat-modal click-handler action params]
(fn [row _ _]
(list-item
[contact-view row
(or click-handler
(let [whisper-identity (:whisper-identity row)]
(on-press whisper-identity)))])))
(if chat-modal
[contact-view-with-letter row click-handler action params]
[contact-view row
(or click-handler
(let [whisper-identity (:whisper-identity row)]
(on-press whisper-identity)))]))))
(defn qr-scan [click-handler action]
[touchable-highlight
{:onPress #(click-handler :qr-scan action)}
[view st/contact-container
[view st/contact-inner-container
[image {:source {:uri :icon_menu_group}
:style st/scan-qr-icon}]
[view st/info-container
[text {:style st/name-text
:number-of-lines 1}
(label :t/scan-qr)]]]]])
(defview contact-list-toolbar []
[group [:get :contacts-group]]
[group [:get :contacts-group]
modal [:get :modal]]
[view
[status-bar]
[toolbar {:title (label (if (= group :dapps)
:t/contacts-group-dapps
:t/contacts-group-new-chat))
[toolbar {:title (label (if-not group
:t/contacts
(if (= group :dapps)
:t/contacts-group-dapps
:t/contacts-group-new-chat)))
:nav-action (when modal
{:handler #(dispatch [:navigate-back])
:image {:source {:uri :icon_back}
:style icon-back}})
:background-color toolbar-background1
:style (get-in platform-specific [:component-styles :toolbar])
:actions [{:image {:source {:uri :icon_search}
@ -53,21 +78,26 @@
(defview contact-list []
[contacts [:contacts-with-letters]
group [:get :contacts-group]
click-handler [:get :contacts-click-handler]]
modal [:get :modal]
click-handler [:get :contacts-click-handler]
action [:get :contacts-click-action]
params [:get :contacts-click-params]]
(let [show-new-group-chat? (and (= group :people)
(get-in platform-specific [:chats :new-chat-in-toolbar?]))]
[drawer-view
[view st/contacts-list-container
[contact-list-toolbar]
;; todo add stub
(when modal
[qr-scan click-handler action])
(when contacts
[list-view {:dataSource (lw/to-datasource contacts)
:enableEmptySections true
:renderRow (render-row click-handler)
:renderRow (render-row modal click-handler action params)
:renderHeader #(list-item
[view
(if show-new-group-chat?
[new-group-chat-view])
[view st/spacing-top]])
[view
(if show-new-group-chat?
[new-group-chat-view])
[view st/spacing-top]])
:renderFooter #(list-item [view st/spacing-bottom])
:style st/contacts-list}])]]))

View File

@ -3,7 +3,9 @@
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.handlers]
[status-im.subs]
[status-im.components.react :refer [app-registry
[status-im.components.react :refer [view
modal
app-registry
keyboard
orientation]]
[status-im.components.main-tabs :refer [main-tabs]]
@ -24,7 +26,9 @@
[status-im.profile.screen :refer [profile my-profile]]
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
status-im.data-store.core
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[status-im.chat.styles.screen :as st]
[status-im.accounts.views.wallet-qr-code :refer [wallet-qr-code]]))
(defn orientation->keyword [o]
(keyword (.toLowerCase o)))
@ -38,7 +42,7 @@
(defn app-root []
(let [signed-up? (subscribe [:signed-up?])
_ (log/debug "signed up: " @signed-up?)
modal-view (subscribe [:get :modal])
view-id (subscribe [:get :view-id])
account-id (subscribe [:get :current-account-id])
keyboard-height (subscribe [:get :keyboard-height])]
@ -86,7 +90,21 @@
:login login
:confirm confirm
:my-profile my-profile)]
[component]))))})))
[view
{:flex 1}
[component]
(when @modal-view
[view
st/chat-modal
[modal {:animation-type :slide
:transparent false
:on-request-close #(dispatch [:navigate-back])}
(let [component (case @modal-view
:qr-scanner qr-scanner
:wallet-qr-code wallet-qr-code
:confirm confirm
:contact-list-modal contact-list)]
[component])]])]))))})))
(defn init []
(dispatch-sync [:reset-app])

View File

@ -70,4 +70,5 @@
(update content :command #((keyword %) commands)))
(defn parse-command-request [commands content]
(log/debug "parse-command-request: " commands content)
(update content :command #((keyword %) commands)))

View File

@ -24,6 +24,11 @@
(defmethod preload-data! :default [db _] db)
(defn -preload-data! [{:keys [was-modal?] :as db} & args]
(if was-modal?
(dissoc db :was-modal)
(apply preload-data! db args)))
(register-handler :navigate-forget
(enrich preload-data!)
(fn [db [_ new-view-id]]
@ -36,16 +41,25 @@
db
(push-view db new-view-id))))
(register-handler :navigate-to-modal
(enrich preload-data!)
(fn [db [_ modal-view]]
(assoc db :modal modal-view)))
(register-handler :navigation-replace
(enrich preload-data!)
(fn [db [_ view-id]]
(replace-view db view-id)))
(register-handler :navigate-back
(enrich preload-data!)
(fn [{:keys [navigation-stack view-id] :as db} _]
(if (>= 1 (count navigation-stack))
db
(enrich -preload-data!)
(fn [{:keys [navigation-stack view-id modal] :as db} _]
(cond
modal (assoc db :modal nil
:was-modal? true)
(>= 1 (count navigation-stack)) db
:else
(let [[previous-view-id :as navigation-stack'] (pop navigation-stack)
first-in-stack (first navigation-stack)]
(if (= view-id first-in-stack)
@ -67,10 +81,6 @@
(fn [db [_]]
(assoc db :prev-tab-view-id nil)))
(register-handler :remove-contacts-click-handler
(fn [db]
(dissoc db :contacts-click-handler)))
(defn show-profile
[db [_ identity]]
(-> db

View File

@ -4,20 +4,25 @@
[status-im.components.react :refer [view
image]]
[status-im.components.camera :refer [camera]]
[status-im.components.styles :refer [icon-search]]
[status-im.components.styles :refer [icon-search
icon-back]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.styles :refer [toolbar-background1]]
[status-im.qr-scanner.styles :as st]
[status-im.utils.types :refer [json->clj]]
[status-im.components.styles :as cst]
[clojure.string :as str]))
(defn qr-scanner-toolbar [title]
(defview qr-scanner-toolbar [title]
[modal [:get :modal]]
[view
[status-bar]
[toolbar {:title title
:background-color toolbar-background1
:nav-action (when modal
{:handler #(dispatch [:navigate-back])
:image {:source {:uri :icon_back}
:style icon-back}})
:actions [{:image {:source {:uri :icon_lock_white}
:style icon-search}
:handler #()}]}]])
@ -30,6 +35,7 @@
(let [data (-> (.-data code)
(str/replace #"ethereum:" ""))]
(dispatch [:set-qr-code identifier data])))
:barCodeTypes [:qr]
:style st/barcode-scanner}]
[view st/rectangle-container
[view st/rectangle

View File

@ -30,7 +30,7 @@
(assoc-in [:confirm-transactions :password] 0)))
(defn on-unlock
[ids password previous-view-id]
[ids password]
(dispatch [:set :wrong-password? false])
(doseq [id ids]
(status/complete-transaction
@ -38,15 +38,13 @@
password
#(dispatch [:transaction-completed
{:id id
:response %
:previous-view-id previous-view-id}]))))
:response %}]))))
(register-handler :accept-transactions
(u/side-effect!
(fn [{:keys [transactions navigation-stack]} [_ password]]
(let [ids (keys transactions)
previous-view-id (second navigation-stack)]
(on-unlock ids password previous-view-id)))))
(fn [{:keys [transactions]} [_ password]]
(let [ids (keys transactions)]
(on-unlock ids password)))))
(register-handler :deny-transactions
(u/side-effect!
@ -125,7 +123,7 @@
(remove-pending-message db message-id)))
(register-handler :transaction-queued
(after #(dispatch [:navigate-to :confirm]))
(after #(dispatch [:navigate-to-modal :confirm]))
(fn [db [_ {:keys [id message_id args]}]]
(let [{:keys [from to value]} args
transaction {:id id
@ -137,7 +135,7 @@
(register-handler :transaction-completed
(u/side-effect!
(fn [{:keys [transactions]} [_ {:keys [id response previous-view-id]}]]
(fn [{:keys [transactions]} [_ {:keys [id response]}]]
(let [{:keys [hash error] :as parsed-response} (t/json->clj response)
{:keys [message-id]} (transactions id)]
(log/debug :parsed-response parsed-response)
@ -148,7 +146,7 @@
:message-id message-id}])
(dispatch [::check-completed-transaction!
{:message-id message-id}])
(dispatch [:navigation-replace previous-view-id]))
(dispatch [:navigate-back]))
(dispatch [::remove-transaction id])))))))
(register-handler ::add-transactions-hash

View File

@ -201,6 +201,10 @@
:recover-access "Recover access"
:add-account "Add account"
;wallet-qr-code
:done "Done"
:main-wallet "Main Wallet"
;validation
:invalid-phone "Invalid phone number"
:amount "Amount"