merge develop

Former-commit-id: 04440181b2
This commit is contained in:
Adrian Tiberius 2016-07-18 21:33:41 +03:00
commit a479ae3e15
30 changed files with 528 additions and 227 deletions

View File

@ -128,7 +128,12 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE
} }
@ReactMethod @ReactMethod
public void startNode(Callback callback) { public void startNode(Callback callback, Callback onAlreadyRunning) {
if(GethService.isRunning()){
onAlreadyRunning.invoke();
return;
}
Activity currentActivity = getCurrentActivity(); Activity currentActivity = getCurrentActivity();

View File

@ -213,7 +213,7 @@ public class GethService extends Service {
String address = data.getString("address"); String address = data.getString("address");
String password = data.getString("password"); String password = data.getString("password");
// TODO: remove third argument // TODO: remove third argument
String result = Statusgo.Login(address, password); String result = Statusgo.UnlockAccount(address, password, 0);
Log.d(TAG, "Unlocked account: " + result); Log.d(TAG, "Unlocked account: " + result);
Bundle replyData = new Bundle(); Bundle replyData = new Bundle();

View File

@ -10,7 +10,7 @@
[prismatic/schema "1.0.4"] [prismatic/schema "1.0.4"]
^{:voom {:repo "git@github.com:status-im/status-lib.git" ^{:voom {:repo "git@github.com:status-im/status-lib.git"
:branch "master"}} :branch "master"}}
[status-im/protocol "0.1.1-20160630_153846-gbf92f5f"] [status-im/protocol "0.1.1-20160706_085008-ge61756a"]
[natal-shell "0.1.6"] [natal-shell "0.1.6"]
[com.andrewmcveigh/cljs-time "0.4.0"]] [com.andrewmcveigh/cljs-time "0.4.0"]]
:plugins [[lein-cljsbuild "1.1.1"] :plugins [[lein-cljsbuild "1.1.1"]

View File

@ -138,6 +138,12 @@ status.response({
name: "phone", name: "phone",
description: "Send phone number", description: "Send phone number",
color: "#5fc48d", color: "#5fc48d",
validator: function (params) {
return {
validationHandler: "phone",
parameters: [params.value]
};
},
params: [{ params: [{
name: "phone", name: "phone",
type: status.types.PHONE, type: status.types.PHONE,
@ -156,6 +162,16 @@ status.command({
name: "help", name: "help",
description: "Help", description: "Help",
color: "#7099e6", color: "#7099e6",
/* Validator example
validator: function (params) {
if (params.value != "3") {
var error = status.components.view(
{backgroundColor: "red"},
[status.components.text({}, "ooops :(")]
);
return {errors: [error]}
}
},*/
params: [{ params: [{
name: "query", name: "query",
type: status.types.TEXT type: status.types.TEXT

View File

@ -22,6 +22,7 @@ Command.prototype.create = function (com) {
this.name = com.name; this.name = com.name;
this.description = com.description; this.description = com.description;
this.handler = com.handler; this.handler = com.handler;
this.validator = com.validator;
this.color = com.color; this.color = com.color;
this.icon = com.icon; this.icon = com.icon;
this.params = com.params || []; this.params = com.params || [];
@ -83,13 +84,13 @@ function scrollView(options, elements) {
} }
var status = { var status = {
command: function (n, d, h) { command: function (h) {
var command = new Command(); var command = new Command();
return command.create(n, d, h); return command.create(h);
}, },
response: function (n, d, h) { response: function (h) {
var response = new Response(); var response = new Response();
return response.create(n, d, h); return response.create(h);
}, },
types: { types: {
TEXT: 'text', TEXT: 'text',

View File

@ -2,7 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
text text-class
text-input text-input
image image
linear-gradient linear-gradient
@ -26,7 +26,7 @@
(def toolbar-title (def toolbar-title
[view toolbar-title-container [view toolbar-title-container
[text {:style (merge toolbar-title-text {:color color-white})} [text-class {:style (merge toolbar-title-text {:color color-white})}
(label :t/login)]]) (label :t/login)]])
(defview address-input [address] (defview address-input [address]
@ -83,9 +83,9 @@
[view st/recover-text-container [view st/recover-text-container
[touchable-highlight [touchable-highlight
{:on-press #()} {:on-press #()}
[text {:style st/recover-text} (label :t/recover-access)]]] [text-class {:style st/recover-text} (label :t/recover-access)]]]
[view st/connect-button-container [view st/connect-button-container
[touchable-highlight [touchable-highlight
{:on-press #(dispatch [:login-account address password])} {:on-press #(dispatch [:login-account address password])}
[view st/connect-button [view st/connect-button
[text {:style st/connect-button-text} (label :t/connect)]]]]]]) [text-class {:style st/connect-button-text} (label :t/connect)]]]]]])

View File

@ -42,6 +42,7 @@
(defn app-root [] (defn app-root []
(let [signed-up (subscribe [:get :signed-up]) (let [signed-up (subscribe [:get :signed-up])
_ (log/debug "signed up: " @signed-up)
view-id (subscribe [:get :view-id]) view-id (subscribe [:get :view-id])
account (subscribe [:get :user-identity]) account (subscribe [:get :user-identity])
keyboard-height (subscribe [:get :keyboard-height])] keyboard-height (subscribe [:get :keyboard-height])]
@ -59,15 +60,21 @@
"keyboardDidShow" "keyboardDidShow"
(fn [e] (fn [e]
(let [h (.. e -endCoordinates -height)] (let [h (.. e -endCoordinates -height)]
(when-not (= h keyboard-height) (when-not (= h @keyboard-height)
(dispatch [:set :keyboard-height h]))))) (dispatch [:set :keyboard-height h])))))
(.addListener device-event-emitter (.addListener device-event-emitter
"keyboardDidHide" "keyboardDidHide"
(when-not (= 0 keyboard-height) (when-not (= 0 @keyboard-height)
#(dispatch [:set :keyboard-height 0])))) #(dispatch [:set :keyboard-height 0]))))
:render :render
(fn [] (fn []
(let [startup-view (if @account @view-id (if (contains? #{:login :chat} @view-id) @view-id :accounts))] (let [startup-view (if @account
(if @signed-up
@view-id
:chat)
(if (contains? #{:login :chat} @view-id)
@view-id
:accounts))]
(log/debug startup-view) (log/debug startup-view)
(case (if true startup-view :chat) (case (if true startup-view :chat)
:discovery [main-tabs] :discovery [main-tabs]

View File

@ -21,10 +21,13 @@
[status-im.utils.phone-number :refer [format-phone-number]] [status-im.utils.phone-number :refer [format-phone-number]]
[status-im.utils.datetime :as time] [status-im.utils.datetime :as time]
[status-im.components.react :refer [geth]] [status-im.components.react :refer [geth]]
[status-im.utils.logging :as log]
[status-im.components.jail :as j] [status-im.components.jail :as j]
[status-im.utils.types :refer [json->clj]] [status-im.utils.types :refer [json->clj]]
[status-im.commands.utils :refer [generate-hiccup]])) [status-im.commands.utils :refer [generate-hiccup]]
status-im.chat.handlers.commands
status-im.chat.handlers.animation
status-im.chat.handlers.requests
status-im.chat.handlers.unviewed-messages))
(register-handler :set-show-actions (register-handler :set-show-actions
(fn [db [_ show-actions]] (fn [db [_ show-actions]]
@ -53,81 +56,15 @@
(assoc-in [:chats current-chat-id :command-input] {}) (assoc-in [:chats current-chat-id :command-input] {})
(update-in [:chats current-chat-id :input-text] safe-trim)))) (update-in [:chats current-chat-id :input-text] safe-trim))))
(defn invoke-suggestions-handler!
[{:keys [current-chat-id canceled-command] :as db} _]
(when-not canceled-command
(let [{:keys [command content]} (get-in db [:chats current-chat-id :command-input])
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:params
0
:suggestions]
params {:value content}]
(j/call current-chat-id
path
params
#(dispatch [:suggestions-handler {:command command
:content content
:chat-id current-chat-id} %])))))
(register-handler :start-cancel-command (register-handler :start-cancel-command
(u/side-effect! (u/side-effect!
(fn [db _] (fn [db _]
(dispatch [:animate-cancel-command])))) (dispatch [:animate-cancel-command]))))
(def command-prefix "c ")
(defn cancel-command!
[{:keys [canceled-command]}]
(when canceled-command
(dispatch [:start-cancel-command])))
(register-handler :set-chat-command-content
[(after invoke-suggestions-handler!)
(after cancel-command!)]
(fn [{:keys [current-chat-id] :as db} [_ content]]
(let [starts-as-command? (str/starts-with? content command-prefix)
path [:chats current-chat-id :command-input :command :type]
command? (= :command (get-in db path))]
(as-> db db
(commands/set-chat-command-content db content)
(assoc-in db [:chats current-chat-id :input-text] nil)
(assoc db :canceled-command (and command? (not starts-as-command?)))))))
(defn update-input-text (defn update-input-text
[{:keys [current-chat-id] :as db} text] [{:keys [current-chat-id] :as db} text]
(assoc-in db [:chats current-chat-id :input-text] text)) (assoc-in db [:chats current-chat-id :input-text] text))
(defn invoke-command-preview!
[{:keys [current-chat-id staged-command]} _]
(let [{:keys [command content]} staged-command
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:preview]
params {:value content}]
(j/call current-chat-id
path
params
#(dispatch [:command-preview current-chat-id %]))))
(register-handler :stage-command
(after invoke-command-preview!)
(fn [{:keys [current-chat-id] :as db} _]
(let [db (update-input-text db nil)
{:keys [command content to-msg-id]}
(get-in db [:chats current-chat-id :command-input])
content' (if (= :command (:type command))
(subs content 2)
content)
command-info {:command command
:content content'
:to-message to-msg-id}]
(-> db
(commands/stage-command command-info)
(assoc :staged-command command-info)))))
(register-handler :set-message-input [] (register-handler :set-message-input []
(fn [db [_ input]] (fn [db [_ input]]
(assoc db :message-input input))) (assoc db :message-input input)))
@ -138,15 +75,6 @@
(when-let [message-input (:message-input db)] (when-let [message-input (:message-input db)]
(.blur message-input))))) (.blur message-input)))))
(register-handler :set-response-chat-command
[(after invoke-suggestions-handler!)
(after #(dispatch [:command-edit-mode]))
(after #(dispatch [:set-chat-input-text ""]))]
(fn [db [_ to-msg-id command-key]]
(-> db
(commands/set-response-chat-command to-msg-id command-key)
(assoc :canceled-command false))))
(defn update-text (defn update-text
[{:keys [current-chat-id] :as db} [_ text]] [{:keys [current-chat-id] :as db} [_ text]]
(let [suggestions (get-in db [:command-suggestions current-chat-id])] (let [suggestions (get-in db [:command-suggestions current-chat-id])]
@ -215,6 +143,11 @@
(fn [db [_ {:keys [chat-id msg-id]}]] (fn [db [_ {:keys [chat-id msg-id]}]]
(set-message-shown db chat-id msg-id))) (set-message-shown db chat-id msg-id)))
(defn default-delivery-status [chat-id]
(if (console? chat-id)
:seen
:pending))
(defn prepare-message (defn prepare-message
[{:keys [identity current-chat-id] :as db} _] [{:keys [identity current-chat-id] :as db} _]
(let [text (get-in db [:chats current-chat-id :input-text]) (let [text (get-in db [:chats current-chat-id :input-text])
@ -227,6 +160,7 @@
:to current-chat-id :to current-chat-id
:from identity :from identity
:content-type text-content-type :content-type text-content-type
:delivery-status (default-delivery-status current-chat-id)
:outgoing true :outgoing true
:timestamp (time/now-ms)})] :timestamp (time/now-ms)})]
(if command (if command
@ -242,6 +176,7 @@
:to chat-id :to chat-id
:content content :content content
:content-type content-type-command :content-type content-type-command
:delivery-status (default-delivery-status chat-id)
:outgoing true :outgoing true
:preview preview-string :preview preview-string
:rendered-preview preview :rendered-preview preview
@ -283,12 +218,10 @@
[{:keys [new-message current-chat-id] :as db} _] [{:keys [new-message current-chat-id] :as db} _]
(when (and new-message (not-console? current-chat-id)) (when (and new-message (not-console? current-chat-id))
(let [{:keys [group-chat]} (get-in db [:chats current-chat-id]) (let [{:keys [group-chat]} (get-in db [:chats current-chat-id])
content (:content new-message)] message (select-keys new-message [:content :msg-id])]
(if group-chat (if group-chat
(api/send-group-user-msg {:group-id current-chat-id (api/send-group-user-msg (assoc message :group-id current-chat-id))
:content content}) (api/send-user-msg (assoc message :to current-chat-id))))))
(api/send-user-msg {:to current-chat-id
:content content})))))
(defn save-message-to-realm! (defn save-message-to-realm!
[{:keys [new-message current-chat-id]} _] [{:keys [new-message current-chat-id]} _]
@ -322,13 +255,6 @@
params params
#(dispatch [:command-handler! com %]))))) #(dispatch [:command-handler! com %])))))
(defn handle-commands
[{:keys [new-commands]}]
(doseq [{{content :content} :content
handler :handler} new-commands]
(when handler
(handler content))))
(register-handler :send-chat-msg (register-handler :send-chat-msg
(-> prepare-message (-> prepare-message
((enrich prepare-staged-commans)) ((enrich prepare-staged-commans))
@ -341,21 +267,7 @@
((after save-commands-to-realm!)) ((after save-commands-to-realm!))
((after dispatch-responded-requests!)) ((after dispatch-responded-requests!))
;; todo maybe it is better to track if it was handled or not ;; todo maybe it is better to track if it was handled or not
((after invoke-commands-handlers!)) ((after invoke-commands-handlers!))))
((after handle-commands))))
(register-handler :unstage-command
(fn [db [_ staged-command]]
(commands/unstage-command db staged-command)))
(register-handler :set-chat-command
[(after invoke-suggestions-handler!)
(after #(dispatch [:command-edit-mode]))]
(fn [{:keys [current-chat-id] :as db} [_ command-key]]
(-> db
(commands/set-chat-command command-key)
(assoc-in [:chats current-chat-id :command-input :content] "c ")
(assoc :disable-input true))))
(register-handler :init-console-chat (register-handler :init-console-chat
(fn [db [_]] (fn [db [_]]
@ -426,6 +338,7 @@
(assoc db :loaded-chats (chats/chats-list))) (assoc db :loaded-chats (chats/chats-list)))
(register-handler :initialize-chats (register-handler :initialize-chats
(after #(dispatch [:load-unviewed-messages!]))
((enrich initialize-chats) load-chats!)) ((enrich initialize-chats) load-chats!))
(defn store-message! (defn store-message!
@ -434,20 +347,27 @@
(defn dispatch-request! (defn dispatch-request!
[{:keys [new-message]} [_ {chat-id :from}]] [{:keys [new-message]} [_ {chat-id :from}]]
(log/debug "Dispatching request: " new-message)
(when (= (:content-type new-message) content-type-command-request) (when (= (:content-type new-message) content-type-command-request)
(dispatch [:add-request chat-id new-message]))) (dispatch [:add-request chat-id new-message])))
(defn receive-message (defn receive-message
[db [_ {chat-id :from :as message}]] [db [_ {chat-id :from :as message}]]
(let [message' (check-author-direction db chat-id message)] (let [message' (-> db
(check-author-direction chat-id message)
(assoc :delivery-status :pending))]
(-> db (-> db
(add-message-to-db chat-id message') (add-message-to-db chat-id message')
(assoc :new-message message')))) (assoc :new-message message'))))
(defn dispatch-unviewed-message!
[{:keys [new-message]} [_ {chat-id :from}]]
(let [{:keys [msg-id]} new-message]
(dispatch [:add-unviewed-message chat-id msg-id])))
(register-handler :received-msg (register-handler :received-msg
[(after store-message!) [(after store-message!)
(after dispatch-request!)] (after dispatch-request!)
(after dispatch-unviewed-message!)]
receive-message) receive-message)
(register-handler :group-received-msg (register-handler :group-received-msg
@ -553,6 +473,7 @@
(assoc-in db [:edit-mode current-chat-id] mode))) (assoc-in db [:edit-mode current-chat-id] mode)))
(register-handler :command-edit-mode (register-handler :command-edit-mode
(after #(dispatch [:clear-validation-errors]))
(edit-mode-handler :command)) (edit-mode-handler :command))
(register-handler :text-edit-mode (register-handler :text-edit-mode
@ -574,3 +495,13 @@
(dispatch [:fix-commands-suggestions-height])))))] (dispatch [:fix-commands-suggestions-height])))))]
(fn [db [_ h]] (fn [db [_ h]]
(assoc db :layout-height h))) (assoc db :layout-height h)))
(register-handler :send-seen!
(after (fn [_ [_ chat-id message-id]]
(when-not (console? chat-id))
(dispatch [:msg-seen chat-id message-id])))
(u/side-effect!
(fn [_ [_ chat-id message-id]]
(when-not (console? chat-id)
(api/send-seen chat-id message-id)))))

View File

@ -3,6 +3,7 @@
[status-im.utils.handlers :refer [register-handler]] [status-im.utils.handlers :refer [register-handler]]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.chat.constants :refer [input-height request-info-height [status-im.chat.constants :refer [input-height request-info-height
suggestions-header-height
minimum-command-suggestions-height minimum-command-suggestions-height
response-height-normal minimum-suggestion-height]] response-height-normal minimum-suggestion-height]]
[status-im.constants :refer [response-input-hiding-duration]])) [status-im.constants :refer [response-input-hiding-duration]]))
@ -15,45 +16,54 @@
([name middleware handler] ([name middleware handler]
(register-handler name [(path :animations) middleware] handler))) (register-handler name [(path :animations) middleware] handler)))
(animation-handler :animate-cancel-command (register-handler :animate-cancel-command
(after #(dispatch [:text-edit-mode])) (after #(dispatch [:text-edit-mode]))
(fn [db _] (fn [{:keys [current-chat-id] :as db} _]
(assoc db :to-response-height input-height))) (assoc-in db [:animations :to-response-height current-chat-id] input-height)))
(def response-height (+ input-height response-height-normal)) (def response-height (+ input-height response-height-normal))
(defn update-response-height [db] (defn update-response-height
(assoc-in db [:animations :to-response-height] response-height)) [{:keys [current-chat-id] :as db}]
(assoc-in db [:animations :to-response-height current-chat-id] response-height))
(register-handler :animate-command-suggestions (register-handler :animate-command-suggestions
(fn [{:keys [current-chat-id] :as db} _] (fn [{chat-id :current-chat-id :as db} _]
(let [suggestions? (seq (get-in db [:command-suggestions current-chat-id])) (let [suggestions? (seq (get-in db [:command-suggestions chat-id]))
current (get-in db [:animations :command-suggestions-height]) current (get-in db [:animations :command-suggestions-height chat-id])
height (if suggestions? middle-height input-height) height (if suggestions? middle-height input-height)
changed? (if (and suggestions? changed? (if (and suggestions?
(not (nil? current)) (not (nil? current))
(not= input-height current)) (not= input-height current))
identity inc)] identity inc)]
(-> db (-> db
(update :animations assoc :command-suggestions-height height) (assoc-in [:animations :command-suggestions-height chat-id] height)
(update-in [:animations :commands-height-changed] changed?))))) (update-in [:animations :commands-height-changed] changed?)))))
(defn get-minimum-height (defn get-minimum-height
[{:keys [current-chat-id] :as db}] [{:keys [current-chat-id] :as db}]
(let [path [:chats current-chat-id :command-input :command :type] (let [path [:chats current-chat-id :command-input :command :type]
type (get-in db path)] type (get-in db path)
errors (get-in db [:validation-errors current-chat-id])
custom-errors (get-in db [:custom-validation-errors current-chat-id])
validation-height (if (or (seq errors) (seq custom-errors))
request-info-height
0)]
(+ validation-height
(if (= :response type) (if (= :response type)
minimum-suggestion-height minimum-suggestion-height
input-height))) (if (zero? validation-height)
input-height
(+ input-height suggestions-header-height))))))
(register-handler :animate-show-response (register-handler :animate-show-response
[(after #(dispatch [:command-edit-mode]))] ;[(after #(dispatch [:command-edit-mode]))]
(fn [{:keys [current-chat-id] :as db}] (fn [{:keys [current-chat-id] :as db}]
(let [suggestions? (seq (get-in db [:suggestions current-chat-id])) (let [suggestions? (seq (get-in db [:suggestions current-chat-id]))
height (if suggestions? height (if suggestions?
middle-height middle-height
(get-minimum-height db))] (get-minimum-height db))]
(assoc-in db [:animations :to-response-height] height)))) (assoc-in db [:animations :to-response-height current-chat-id] height))))
(defn fix-height (defn fix-height
[height-key height-signal-key suggestions-key minimum] [height-key height-signal-key suggestions-key minimum]
@ -64,7 +74,7 @@
under-middle-position? (<= current middle-height) under-middle-position? (<= current middle-height)
over-middle-position? (not under-middle-position?) over-middle-position? (not under-middle-position?)
suggestions (get-in db [suggestions-key current-chat-id]) suggestions (get-in db [suggestions-key current-chat-id])
old-fixed (get-in db [:animations height-key]) old-fixed (get-in db [:animations height-key current-chat-id])
new-fixed (cond (not suggestions) new-fixed (cond (not suggestions)
(minimum db) (minimum db)
@ -89,7 +99,7 @@
(and under-middle-position? moving-down?) (and under-middle-position? moving-down?)
(minimum db))] (minimum db))]
(-> db (-> db
(assoc-in [:animations height-key] new-fixed) (assoc-in [:animations height-key current-chat-id] new-fixed)
(update-in [:animations height-signal-key] inc))))) (update-in [:animations height-signal-key] inc)))))
(defn commands-min-height (defn commands-min-height

View File

@ -0,0 +1,188 @@
(ns status-im.chat.handlers.commands
(:require [re-frame.core :refer [enrich after dispatch]]
[status-im.utils.handlers :refer [register-handler] :as u]
[status-im.components.jail :as j]
[status-im.models.commands :as commands]
[clojure.string :as str]
[status-im.commands.utils :as cu]
[status-im.utils.phone-number :as pn]
[status-im.i18n :as i18n]))
(def command-prefix "c ")
(defn invoke-suggestions-handler!
[{:keys [current-chat-id canceled-command] :as db} _]
(when-not canceled-command
(let [{:keys [command content]} (get-in db [:chats current-chat-id :command-input])
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:params
0
:suggestions]
params {:value content}]
(j/call current-chat-id
path
params
#(dispatch [:suggestions-handler {:command command
:content content
:chat-id current-chat-id} %])))))
(defn cancel-command!
[{:keys [canceled-command]}]
(when canceled-command
(dispatch [:start-cancel-command])))
(register-handler :set-chat-command-content
[(after invoke-suggestions-handler!)
(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)
path [:chats current-chat-id :command-input :command :type]
command? (= :command (get-in db path))]
(as-> db db
(commands/set-chat-command-content db content)
(assoc-in db [:chats current-chat-id :input-text] nil)
(assoc db :canceled-command (and command? (not starts-as-command?)))))))
(defn invoke-command-preview!
[{:keys [staged-command]} [_ chat-id]]
(let [{:keys [command content]} staged-command
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:preview]
params {:value content}]
(j/call chat-id
path
params
#(dispatch [:command-preview chat-id %]))))
(defn content-by-command
[{:keys [type]} content]
(if (= :command type)
(subs content 2)
content))
(defn command-input
([{:keys [current-chat-id] :as db}]
(command-input db current-chat-id))
([db chat-id]
(get-in db [:chats chat-id :command-input])))
(register-handler ::validate!
(u/side-effect!
(fn [_ [_ {:keys [chat-id]} {:keys [error result]}]]
;; todo handle error
(when-not error
(let [{:keys [errors validationHandler parameters]} result]
(cond errors
(dispatch [::add-validation-errors chat-id errors])
validationHandler
(dispatch [::validation-handler!
chat-id
validationHandler
parameters])
:else (dispatch [::finish-command-staging chat-id])))))))
(defn start-validate! [db]
(let [{:keys [content command chat-id] :as data} (::command db)
{:keys [name type]} command
path [(if (= :command type) :commands :responses)
name
:validator]
params {:value content}]
(j/call chat-id
path
params
#(dispatch [::validate! data %]))))
(register-handler :stage-command
(after start-validate!)
(fn [{:keys [current-chat-id] :as db}]
(let [{:keys [command content]} (command-input db)
content' (content-by-command command content)]
(-> db
(assoc ::command {:content content'
:command command
:chat-id current-chat-id})
(assoc-in [:disable-staging current-chat-id] true)))))
(register-handler ::finish-command-staging
[(after #(dispatch [:start-cancel-command]))
(after invoke-command-preview!)]
(fn [db [_ chat-id]]
(let [db (assoc-in db [:chats chat-id :input-text] nil)
{:keys [command content to-msg-id]} (command-input db)
content' (content-by-command command content)
command-info {:command command
:content content'
:to-message to-msg-id}]
(-> db
(commands/stage-command command-info)
(assoc :staged-command command-info)
(assoc-in [:disable-staging chat-id] true)))))
(register-handler :unstage-command
(fn [db [_ staged-command]]
(commands/unstage-command db staged-command)))
(defn set-chat-command
[{:keys [current-chat-id] :as db} [_ command-key]]
(-> db
(commands/set-chat-command command-key)
(assoc-in [:chats current-chat-id :command-input :content] command-prefix)
(assoc :disable-input true)))
(register-handler :set-chat-command
[(after invoke-suggestions-handler!)
(after #(dispatch [:command-edit-mode]))]
set-chat-command)
(defn set-response-command [db [_ to-msg-id command-key]]
(-> db
(commands/set-response-chat-command to-msg-id command-key)
(assoc :canceled-command false)))
(register-handler :set-response-chat-command
[(after invoke-suggestions-handler!)
(after #(dispatch [:command-edit-mode]))
(after #(dispatch [:set-chat-input-text ""]))]
set-response-command)
(register-handler ::add-validation-errors
(fn [db [_ chat-id errors]]
(assoc-in db [:custom-validation-errors chat-id]
(map cu/generate-hiccup errors))))
(register-handler :clear-validation-errors
(fn [db]
(dissoc db :validation-errors :custom-validation-errors)))
(def validation-handlers
{:phone (fn [chat-id [number]]
(if (pn/valid-mobile-number? number)
(dispatch [::finish-command-staging chat-id])
(dispatch [::set-validation-error
chat-id
{:title (i18n/label :t/phone-number)
:description (i18n/label :t/invalid-phone)}])))})
(defn validator [name]
(validation-handlers (keyword name)))
(register-handler ::validation-handler!
(u/side-effect!
(fn [_ [_ chat-id name params]]
(when-let [handler (validator name)]
(handler chat-id params)))))
(register-handler ::set-validation-error
(after #(dispatch [:fix-response-height]))
(fn [db [_ chat-id error]]
(assoc-in db [:validation-errors chat-id] [error])))

View File

@ -0,0 +1,44 @@
(ns status-im.chat.handlers.unviewed-messages
(:require [re-frame.core :refer [after enrich path dispatch]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.persistence.realm.core :as realm]))
(defn delivered-messages []
(-> (realm/get-by-fields
:account :msgs
{:delivery-status :delivered
:outgoing false})
(realm/collection->map)))
(defn set-unviewed-messages [db]
(let [messages (->> (::raw-unviewed-messages db)
(group-by :chat-id)
(map (fn [[id messages]]
[id {:messages-ids (map :msg-id messages)
:count (count messages)}]))
(into {}))]
(-> db
(assoc :unviewed-messages messages)
(dissoc ::raw-unviewed-messages))))
(defn load-messages! [db]
(let [messages (delivered-messages)]
(assoc db ::raw-unviewed-messages messages)))
(register-handler ::set-unviewed-messages set-unviewed-messages)
(register-handler :load-unviewed-messages!
(after #(dispatch [::set-unviewed-messages]))
load-messages!)
(register-handler :add-unviewed-message
(path :unviewed-messages)
(fn [db [_ chat-id message-id]]
(-> db
(update-in [chat-id :messages-ids] conj message-id)
(update-in [chat-id :count] inc))))
(register-handler :remove-unviewed-messages
(path :unviewed-messages)
(fn [db [_ chat-id]]
(dissoc db chat-id)))

View File

@ -0,0 +1,17 @@
(ns status-im.chat.styles.command-validation
(:require [status-im.components.styles :as st]
[status-im.chat.constants :as constants]))
(def messages-container
{:background-color :red
:height constants/request-info-height
:padding-left 16
:padding-top 14})
(def title
{:color :white
:font-size 12
:font-family st/font})
(def description
(assoc title :opacity 0.69))

View File

@ -172,3 +172,29 @@
(fn [_ [_ message-id]] (fn [_ [_ message-id]]
(let [requests (subscribe [:get-requests])] (let [requests (subscribe [:get-requests])]
(reaction (not (some #(= message-id (:message-id %)) @requests)))))) (reaction (not (some #(= message-id (:message-id %)) @requests))))))
(register-sub :validation-errors
(fn [db]
(let [current-chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:validation-errors @current-chat-id])))))
(register-sub :custom-validation-errors
(fn [db]
(let [current-chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:custom-validation-errors @current-chat-id])))))
(register-sub :unviewed-messages-count
(fn [db [_ chat-id]]
(reaction (get-in @db [:unviewed-messages chat-id :count]))))
(register-sub :command-suggestions-height
(fn [db]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction
(get-in @db [:animations :command-suggestions-height @chat-id])))))
(register-sub :response-height
(fn [db]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction
(get-in @db [:animations :to-response-height @chat-id])))))

View File

@ -15,8 +15,7 @@
(dispatch [:set-chat-command-content message])) (dispatch [:set-chat-command-content message]))
(defn send-command [] (defn send-command []
(dispatch [:stage-command]) (dispatch [:stage-command]))
(cancel-command-input))
(defn valid? [message validator] (defn valid? [message validator]
(if validator (if validator

View File

@ -0,0 +1,30 @@
(ns status-im.chat.views.command-validation
(:require-macros [status-im.utils.views :refer [defview]])
(:require [status-im.components.react :as c]
[status-im.chat.styles.command-validation :as st]
[status-im.utils.listview :as lw]))
(defn message [{:keys [title description]}]
(c/list-item
[c/view
[c/text st/title title]
[c/text st/description description]]))
(defn messages-list [errors]
[c/list-view {:renderRow message
:keyboardShouldPersistTaps true
:dataSource (lw/to-datasource errors)
:style st/messages-container}])
(defview validation-messages []
[validation-messages [:validation-errors]
custom-errors [:custom-validation-errors]
command? [:command?]]
[c/view
(cond (seq custom-errors)
(vec (concat [c/view] custom-errors))
(seq validation-messages)
[messages-list validation-messages]
:else nil)])

View File

@ -120,20 +120,23 @@
[message-content-audio {:content content [message-content-audio {:content content
:content-type content-type}]]]) :content-type content-type}]]])
(defn message-delivery-status [{:keys [delivery-status]}] (defview message-delivery-status
[{:keys [delivery-status msg-id to] :as m}]
[status [:get-in [:message-status to msg-id]]]
[view st/delivery-view [view st/delivery-view
[image {:source (case delivery-status [image {:source (case (or status delivery-status)
:delivered {:uri :icon_ok_small}
:seen {:uri :icon_ok_small} :seen {:uri :icon_ok_small}
:seen-by-everyone {:uri :icon_ok_small} :seen-by-everyone {:uri :icon_ok_small}
:failed res/delivery-failed-icon) :failed res/delivery-failed-icon
nil)
:style st/delivery-image}] :style st/delivery-image}]
[text {:style st/delivery-text} [text {:style st/delivery-text}
(case delivery-status (case (or status delivery-status)
:delivered "Delivered" :delivered "Sent"
:seen "Seen" :seen "Seen"
:seen-by-everyone "Seen by everyone" :seen-by-everyone "Seen by everyone"
:failed "Failed")]]) :failed "Failed"
"Pending")]])
(defn member-photo [{:keys [photo-path]}] (defn member-photo [{:keys [photo-path]}]
[view st/photo-view [view st/photo-view
@ -159,12 +162,11 @@
[message-delivery-status {:delivery-status delivery-status}])]]])) [message-delivery-status {:delivery-status delivery-status}])]]]))
(defn message-body (defn message-body
[{:keys [outgoing] :as message} content] [{:keys [outgoing delivery-status] :as message} content]
(let [delivery-status :seen]
[view (st/message-body message) [view (st/message-body message)
content content
(when (and outgoing delivery-status) (when outgoing
[message-delivery-status {:delivery-status delivery-status}])])) [message-delivery-status message])])
(defn message-container-animation-logic [{:keys [to-value val callback]}] (defn message-container-animation-logic [{:keys [to-value val callback]}]
(fn [_] (fn [_]
@ -203,7 +205,18 @@
(into [view] children))) (into [view] children)))
(defn chat-message (defn chat-message
[{:keys [outgoing delivery-status timestamp new-day group-chat] [{:keys [outgoing delivery-status timestamp new-day group-chat msg-id chat-id]
:as message}]
(let [status (subscribe [:get-in [:message-status chat-id msg-id]])]
(r/create-class
{:component-did-mount
(fn []
(when (and (not outgoing)
(not= :seen delivery-status)
(not= :seen @status))
(dispatch [:send-seen! chat-id msg-id])))
:reagent-render
(fn [{:keys [outgoing delivery-status timestamp new-day group-chat]
:as message}] :as message}]
[message-container message [message-container message
;; TODO there is no new-day info in message ;; TODO there is no new-day info in message
@ -216,4 +229,4 @@
incoming-group-message-body incoming-group-message-body
message-body) message-body)
(merge message {:delivery-status (keyword delivery-status) (merge message {:delivery-status (keyword delivery-status)
:incoming-group incoming-group})])]]) :incoming-group incoming-group})])]])})))

View File

@ -2,6 +2,7 @@
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe]] (:require [re-frame.core :refer [subscribe]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
text
animated-view animated-view
icon icon
touchable-highlight touchable-highlight
@ -48,20 +49,19 @@
input-options) input-options)
(if command? input-command input-message)]) (if command? input-command input-message)])
(defview plain-message-input-view [{:keys [input-options validator]}] (defview plain-message-input-view [{:keys [input-options]}]
[command? [:command?] [command? [:command?]
{:keys [type] :as command} [:get-chat-command] {:keys [type] :as command} [:get-chat-command]
input-command [:get-chat-command-content] input-command [:get-chat-command-content]
valid-plain-message? [:valid-plain-message?] valid-plain-message? [:valid-plain-message?]]
valid-command? [:valid-command? validator]]
[view st/input-container [view st/input-container
[view st/input-view [view st/input-view
[plain-message/commands-button] [plain-message/commands-button]
[message-input-container [message-input-container
[message-input input-options validator]] [message-input input-options]]
;; TODO emoticons: not implemented ;; TODO emoticons: not implemented
[plain-message/smile-button] [plain-message/smile-button]
(when (if command? valid-command? valid-plain-message?) (when (or command? valid-plain-message?)
(let [on-press (if command? (let [on-press (if command?
command/send-command command/send-command
plain-message/send)] plain-message/send)]

View File

@ -18,8 +18,7 @@
(defn get-options [{:keys [type placeholder]} command-type] (defn get-options [{:keys [type placeholder]} command-type]
(let [options (case (keyword type) (let [options (case (keyword type)
:phone {:input-options {:keyboardType :phone-pad} :phone {:input-options {:keyboardType :phone-pad}}
:validator valid-mobile-number?}
:password {:input-options {:secureTextEntry true}} :password {:input-options {:secureTextEntry true}}
:number {:input-options {:keyboardType :numeric}} :number {:input-options {:keyboardType :numeric}}
;; todo maybe nil is fine for now :) ;; todo maybe nil is fine for now :)

View File

@ -15,7 +15,8 @@
[status-im.chat.styles.dragdown :as ddst] [status-im.chat.styles.dragdown :as ddst]
[status-im.components.animation :as anim] [status-im.components.animation :as anim]
[status-im.chat.suggestions-responder :as resp] [status-im.chat.suggestions-responder :as resp]
[status-im.chat.constants :as c])) [status-im.chat.constants :as c]
[status-im.chat.views.command-validation :as cv]))
(defn drag-icon [] (defn drag-icon []
[view st/drag-container [view st/drag-container
@ -58,14 +59,14 @@
[icon :drag_down ddst/drag-down-icon]])))) [icon :drag_down ddst/drag-down-icon]]))))
(defn container-animation-logic [{:keys [to-value val]}] (defn container-animation-logic [{:keys [to-value val]}]
(let [to-value @to-value] (when-let [to-value @to-value]
(when-not (= to-value (.-_value val)) (when-not (= to-value (.-_value val))
(anim/start (anim/spring val {:toValue to-value}))))) (anim/start (anim/spring val {:toValue to-value})))))
(defn container [response-height & children] (defn container [response-height & children]
(let [;; todo to-response-height, cur-response-height must be specific (let [;; todo to-response-height, cur-response-height must be specific
;; for each chat ;; for each chat
to-response-height (subscribe [:animations :to-response-height]) to-response-height (subscribe [:response-height])
changed (subscribe [:animations :response-height-changed]) changed (subscribe [:animations :response-height-changed])
context {:to-value to-response-height context {:to-value to-response-height
:val response-height} :val response-height}
@ -83,8 +84,7 @@
(defview placeholder [] (defview placeholder []
[suggestions [:get-content-suggestions]] [suggestions [:get-content-suggestions]]
(when (seq suggestions) [view st/input-placeholder])
[view st/input-placeholder]))
(defview response-suggestions-view [] (defview response-suggestions-view []
[suggestions [:get-content-suggestions]] [suggestions [:get-content-suggestions]]
@ -95,4 +95,5 @@
[container response-height [container response-height
[request-info response-height] [request-info response-height]
[response-suggestions-view] [response-suggestions-view]
[cv/validation-messages]
[placeholder]])) [placeholder]]))

View File

@ -104,7 +104,7 @@
(defn container [h & elements] (defn container [h & elements]
(let [;; todo to-response-height, cur-response-height must be specific (let [;; todo to-response-height, cur-response-height must be specific
;; for each chat ;; for each chat
to-response-height (subscribe [:animations :command-suggestions-height]) to-response-height (subscribe [:command-suggestions-height])
changed (subscribe [:animations :commands-height-changed]) changed (subscribe [:animations :commands-height-changed])
context {:to-value to-response-height context {:to-value to-response-height
:val h} :val h}

View File

@ -6,9 +6,10 @@
[status-im.utils.utils :refer [truncate-str]] [status-im.utils.utils :refer [truncate-str]]
[status-im.utils.datetime :as time])) [status-im.utils.datetime :as time]))
(defn chat-list-item-inner-view (defview chat-list-item-inner-view
[{:keys [chat-id name color new-messages-count [{:keys [chat-id name color new-messages-count
online group-chat contacts] :as chat}] online group-chat contacts] :as chat}]
[unviewed-messages [:unviewed-messages-count chat-id]]
(let [last-message (first (:messages chat))] (let [last-message (first (:messages chat))]
[view st/chat-container [view st/chat-container
[view st/chat-icon-container [view st/chat-icon-container
@ -43,6 +44,6 @@
(when (:timestamp last-message) (when (:timestamp last-message)
[text {:style st/datetime-text} [text {:style st/datetime-text}
(time/to-short-str (:timestamp last-message))])]) (time/to-short-str (:timestamp last-message))])])
(when (pos? new-messages-count) (when (pos? unviewed-messages)
[view st/new-messages-container [view st/new-messages-container
[text {:style st/new-messages-text} new-messages-count]])]])) [text {:style st/new-messages-text} unviewed-messages]])]]))

View File

@ -17,7 +17,11 @@
(def app-registry (get-react-property "AppRegistry")) (def app-registry (get-react-property "AppRegistry"))
(def navigator (get-class "Navigator")) (def navigator (get-class "Navigator"))
(def text (get-class "Text")) (def text-class (get-class "Text"))
(defn text
([s] [text-class s])
([{:keys [style] :as opts} s]
[text-class (if style opts {:style opts}) s]))
(def view (get-class "View")) (def view (get-class "View"))
(def image (get-class "Image")) (def image (get-class "Image"))
(def touchable-highlight-class (get-class "TouchableHighlight")) (def touchable-highlight-class (get-class "TouchableHighlight"))

View File

@ -7,7 +7,6 @@
(.isAddress js/Web3.prototype s)) (.isAddress js/Web3.prototype s))
(defn unique-identity? [identity] (defn unique-identity? [identity]
(println identity)
(not (realm/exists? :account :contacts :whisper-identity identity))) (not (realm/exists? :account :contacts :whisper-identity identity)))
(defn valid-length? [identity] (defn valid-length? [identity]

View File

@ -40,8 +40,7 @@
:whisper-identity "" :whisper-identity ""
:phone-number ""} :phone-number ""}
:disable-group-creation false :disable-group-creation false
:animations {:to-response-height 0.1 :animations {;; todo clear this
;; todo clear this
:tabs-bar-value (anim/create-value 0)}}) :tabs-bar-value (anim/create-value 0)}})
(def protocol-initialized-path [:protocol-initialized]) (def protocol-initialized-path [:protocol-initialized])

View File

@ -12,7 +12,6 @@
[status-im.utils.handlers :refer [register-handler] :as u] [status-im.utils.handlers :refer [register-handler] :as u]
[status-im.models.protocol :as protocol] [status-im.models.protocol :as protocol]
status-im.chat.handlers status-im.chat.handlers
status-im.chat.handlers.animation
status-im.group-settings.handlers status-im.group-settings.handlers
status-im.navigation.handlers status-im.navigation.handlers
status-im.contacts.handlers status-im.contacts.handlers
@ -23,8 +22,7 @@
status-im.commands.handlers.jail status-im.commands.handlers.jail
status-im.qr-scanner.handlers status-im.qr-scanner.handlers
status-im.accounts.handlers status-im.accounts.handlers
status-im.protocol.handlers status-im.protocol.handlers))
status-im.chat.handlers.requests))
;; -- Middleware ------------------------------------------------------------ ;; -- Middleware ------------------------------------------------------------
;; ;;
@ -108,7 +106,9 @@
(u/side-effect! (u/side-effect!
(fn [db _] (fn [db _]
(log/debug "Starting node") (log/debug "Starting node")
(.startNode geth (fn [result] (node-started db result)))))) (.startNode geth
(fn [result] (node-started db result))
#(log/debug "Geth already initialized")))))
(register-handler :crypt-initialized (register-handler :crypt-initialized
(u/side-effect! (u/side-effect!

View File

@ -1,11 +1,5 @@
(ns status-im.models.commands (ns status-im.models.commands
(:require [clojure.string :refer [join split]] (:require [status-im.db :as db]))
[clojure.walk :refer [stringify-keys keywordize-keys]]
[re-frame.core :refer [subscribe dispatch]]
[status-im.db :as db]
[status-im.components.animation :as anim]
[status-im.components.styles :refer [color-blue color-dark-mint]]
[status-im.i18n :refer [label]]))
(defn get-commands [{:keys [current-chat-id] :as db}] (defn get-commands [{:keys [current-chat-id] :as db}]
(or (get-in db [:chats current-chat-id :commands]) {})) (or (get-in db [:chats current-chat-id :commands]) {}))

View File

@ -26,7 +26,8 @@
(defn save-message (defn save-message
;; todo remove chat-id parameter ;; todo remove chat-id parameter
[chat-id {:keys [msg-id content] [chat-id {:keys [delivery-status msg-id content]
:or {delivery-status :pending}
:as message}] :as message}]
(when-not (r/exists? :account :msgs :msg-id msg-id) (when-not (r/exists? :account :msgs :msg-id msg-id)
(r/write :account (r/write :account
@ -38,8 +39,8 @@
message message
{:chat-id chat-id {:chat-id chat-id
:content content' :content content'
:timestamp (timestamp) :delivery-status delivery-status
:delivery-status nil})] :timestamp (timestamp)})]
(r/create :account :msgs message' true)))))) (r/create :account :msgs message' true))))))
(defn command-type? [type] (defn command-type? [type]

View File

@ -4,7 +4,7 @@
(:require [status-im.utils.handlers :as u] (:require [status-im.utils.handlers :as u]
[status-im.utils.logging :as log] [status-im.utils.logging :as log]
[status-im.protocol.api :as api] [status-im.protocol.api :as api]
[re-frame.core :refer [dispatch debug]] [re-frame.core :refer [dispatch after]]
[status-im.utils.handlers :refer [register-handler]] [status-im.utils.handlers :refer [register-handler]]
[status-im.models.contacts :as contacts] [status-im.models.contacts :as contacts]
[status-im.protocol.api :refer [init-protocol]] [status-im.protocol.api :refer [init-protocol]]
@ -18,8 +18,8 @@
(register-handler :initialize-protocol (register-handler :initialize-protocol
(u/side-effect! (u/side-effect!
(fn [db [_ account]] (fn [{:keys [user-identity] :as db} [_ account]]
(init-protocol account (make-handler db))))) (init-protocol (or account user-identity) (make-handler db)))))
(register-handler :protocol-initialized (register-handler :protocol-initialized
(fn [db [_ identity]] (fn [db [_ identity]]
@ -102,16 +102,28 @@
(log/debug action msg-id from group-id identity) (log/debug action msg-id from group-id identity)
(participant-invited-to-group-msg group-id identity from msg-id)))) (participant-invited-to-group-msg group-id identity from msg-id))))
(register-handler :acked-msg (defn update-message! [status]
(u/side-effect! (fn [_ [_ _ msg-id]]
(fn [_ [action from msg-id]]
(log/debug action from msg-id)
(messages/update-message! {:msg-id msg-id (messages/update-message! {:msg-id msg-id
:delivery-status :delivered})))) :delivery-status status})))
(defn update-message-status [status]
(fn [db [_ from msg-id]]
(let [current-status (get-in db [:message-status from msg-id])]
(if-not (= :seen current-status)
(assoc-in db [:message-status from msg-id] status)
db))))
(register-handler :acked-msg
(after (update-message! :delivered))
(update-message-status :delivered))
(register-handler :msg-delivery-failed (register-handler :msg-delivery-failed
(u/side-effect! (after (update-message! :failed))
(fn [_ [action msg-id]] (update-message-status :failed))
(log/debug action msg-id)
(messages/update-message! {:msg-id msg-id (register-handler :msg-seen
:delivery-status :failed})))) [(after (update-message! :seen))
(after (fn [_ [_ chat-id]]
(dispatch [:remove-unviewed-messages chat-id])))]
(update-message-status :seen))

View File

@ -22,8 +22,10 @@
(dispatch [:received-msg (assoc payload :from from :to to)])) (dispatch [:received-msg (assoc payload :from from :to to)]))
:msg-acked (let [{:keys [msg-id from]} event] :msg-acked (let [{:keys [msg-id from]} event]
(dispatch [:acked-msg from msg-id])) (dispatch [:acked-msg from msg-id]))
:delivery-failed (let [{:keys [msg-id]} event] :msg-seen (let [{:keys [msg-id from]} event]
(dispatch [:msg-delivery-failed msg-id])) (dispatch [:msg-seen from msg-id]))
:delivery-failed (let [{:keys [msg-id from]} event]
(dispatch [:msg-delivery-failed from msg-id]))
:new-group-chat (let [{:keys [from group-id identities group-name]} event] :new-group-chat (let [{:keys [from group-id identities group-name]} event]
(dispatch [:group-chat-invite-received from group-id identities group-name])) (dispatch [:group-chat-invite-received from group-id identities group-name]))
:new-group-msg (let [{from :from :new-group-msg (let [{from :from

View File

@ -140,4 +140,6 @@
;users ;users
:add-account "Add account" :add-account "Add account"
;validation
:invalid-phone "Invalid phone number"
}) })