Merge pull request #149 from status-im/feature/commands-responses

Commands/responses in console chat

Former-commit-id: 6984515330
This commit is contained in:
Jarrad 2016-06-30 16:52:27 +02:00 committed by GitHub
commit cd564d43ab
48 changed files with 881 additions and 452 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

View File

@ -1,10 +1,40 @@
status.command({
name: "location",
description: "Send location",
color: "#9a5dcf"
color: "#9a5dcf",
preview: function (params) {
var text = status.components.text(
{
style: {
marginTop: 5,
marginHorizontal: 0,
fontSize: 14,
fontFamily: "font",
color: "black"
}
}, params.value);
var uri = "https://maps.googleapis.com/maps/api/staticmap?center="
+ params.value
+ "&size=100x100&maptype=roadmap&key=AIzaSyBNsj1qoQEYPb3IllmWMAscuXW0eeuYqAA&language=en"
+ "&markers=size:mid%7Ccolor:0xff0000%7Clabel:%7C"
+ params.value;
var image = status.components.image(
{
source: {uri: uri},
style: {
width: 100,
height: 100
}
}
);
return status.components.view({}, [text, image]);
}
}).param({
name: "address",
type: status.types.STRING
type: status.types.TEXT,
placeholder: "Address"
});
var phones = [
@ -110,8 +140,9 @@ status.response({
color: "#5fc48d",
params: [{
name: "phone",
type: status.types.PHONE_NUMBER,
suggestions: phoneSuggestions
type: status.types.PHONE,
suggestions: phoneSuggestions,
placeholder: "Phone number"
}],
handler: function (params) {
return {
@ -127,7 +158,7 @@ status.command({
color: "#7099e6",
params: [{
name: "query",
type: status.types.STRING
type: status.types.TEXT
}]
});

View File

@ -92,8 +92,9 @@ var status = {
return response.create(n, d, h);
},
types: {
STRING: 'string',
PHONE_NUMBER: 'phone-number',
TEXT: 'text',
NUMBER: 'number',
PHONE: 'phone',
PASSWORD: 'password'
},
events: {

View File

@ -39,7 +39,8 @@
(defn app-root []
(let [signed-up (subscribe [:get :signed-up])
view-id (subscribe [:get :view-id])]
view-id (subscribe [:get :view-id])
keyboard-height (subscribe [:get :keyboard-height])]
(r/create-class
{:component-will-mount
(fn []
@ -53,10 +54,12 @@
"keyboardDidShow"
(fn [e]
(let [h (.. e -endCoordinates -height)]
(dispatch [:set :keyboard-height h]))))
(when-not (= h keyboard-height)
(dispatch [:set :keyboard-height h])))))
(.addListener device-event-emitter
"keyboardDidHide"
#(dispatch [:set :keyboard-height 0])))
(when-not (= 0 keyboard-height)
#(dispatch [:set :keyboard-height 0]))))
:render
(fn []
(case (if @signed-up @view-id :chat)
@ -82,7 +85,6 @@
(dispatch [:initialize-protocol])
(dispatch [:load-user-phone-number])
(dispatch [:load-contacts])
;; load commands from remote server (todo: uncomment)
(dispatch [:init-console-chat])
(dispatch [:init-chat])
(init-back-button-handler!)

View File

@ -4,3 +4,6 @@
(def request-info-height 61)
(def response-height-normal 211)
(def minimum-suggestion-height (+ input-height request-info-height))
(def suggestions-header-height 22)
(def minimum-command-suggestions-height
(+ input-height suggestions-header-height))

View File

@ -1,5 +1,5 @@
(ns status-im.chat.handlers
(:require [re-frame.core :refer [register-handler enrich after debug dispatch]]
(:require [re-frame.core :refer [enrich after debug dispatch]]
[status-im.models.commands :as commands]
[clojure.string :as str]
[status-im.components.styles :refer [default-chat-color]]
@ -7,18 +7,21 @@
[status-im.protocol.api :as api]
[status-im.models.messages :as messages]
[status-im.constants :refer [text-content-type
content-type-command]]
content-type-command
content-type-command-request
default-number-of-messages]]
[status-im.utils.random :as random]
[status-im.chat.sign-up :as sign-up-service]
[status-im.models.chats :as chats]
[status-im.navigation.handlers :as nav]
[status-im.utils.handlers :as u]
[status-im.utils.handlers :refer [register-handler] :as u]
[status-im.persistence.realm :as r]
[status-im.handlers.server :as server]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.utils.phone-number :refer [format-phone-number]]
[status-im.utils.datetime :as time]
[status-im.components.jail :as j]
[status-im.utils.types :refer [json->clj]]
[status-im.commands.utils :refer [generate-hiccup]]))
(register-handler :set-show-actions
@ -26,12 +29,17 @@
(assoc db :show-actions show-actions)))
(register-handler :load-more-messages
debug
(fn [{:keys [current-chat-id] :as db} _]
(let [messages-path [:chats current-chat-id :messages]
messages (get-in db messages-path)
new-messages (messages/get-messages current-chat-id (count messages))]
(update-in db messages-path concat new-messages))))
(let [all-loaded? (get-in db [:chats current-chat-id :all-loaded?])]
(if all-loaded?
db
(let [messages-path [:chats current-chat-id :messages]
messages (get-in db messages-path)
new-messages (messages/get-messages current-chat-id (count messages))
all-loaded? (> default-number-of-messages (count new-messages))]
(-> db
(update-in messages-path concat new-messages)
(assoc-in [:chats current-chat-id :all-loaded?] all-loaded?)))))))
(defn safe-trim [s]
(when (string? s)
@ -44,33 +52,46 @@
(update-in [:chats current-chat-id :input-text] safe-trim))))
(defn invoke-suggestions-handler!
[{:keys [current-chat-id] :as db} _]
(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} %]))))
[{: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
(u/side-effect!
(fn [db _]
(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 invoke-suggestions-handler!)
(after cancel-command!)]
(fn [{:keys [current-chat-id] :as db} [_ content]]
(as-> db db
(commands/set-chat-command-content db content)
(assoc-in db [:chats current-chat-id :input-text] nil))))
(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
[{:keys [current-chat-id] :as db} text]
@ -80,10 +101,10 @@
[{: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}]
path [(if (= :command type) :commands :responses)
name
:preview]
params {:value content}]
(j/call current-chat-id
path
params
@ -93,12 +114,15 @@
(after invoke-command-preview!)
(fn [{:keys [current-chat-id] :as db} _]
(let [db (update-input-text db nil)
{:keys [command content]}
{:keys [command content to-msg-id]}
(get-in db [:chats current-chat-id :command-input])
command-info {:command command
:content content}]
content' (if (= :command (:type command))
(subs content 2)
content)
command-info {:command command
:content content'
:to-message to-msg-id}]
(-> db
;(assoc-in [:chats current-chat-id :command-input :command] nil)
(commands/stage-command command-info)
(assoc :staged-command command-info)))))
@ -115,14 +139,18 @@
(register-handler :set-response-chat-command
[(after invoke-suggestions-handler!)
(after #(dispatch [:command-edit-mode]))
;(after #(dispatch [:animate-show-response]))
]
(after #(dispatch [:set-chat-input-text ""]))]
(fn [db [_ to-msg-id command-key]]
(commands/set-response-chat-command db to-msg-id command-key)))
(-> db
(commands/set-response-chat-command to-msg-id command-key)
(assoc :canceled-command false))))
(defn update-text
[db [_ text]]
(update-input-text db text))
[{:keys [current-chat-id] :as db} [_ text]]
(let [suggestions (get-in db [:command-suggestions current-chat-id])]
(if-not (= 1 (count suggestions))
(update-input-text db text)
(assoc db :disable-input true))))
(defn update-command [db [_ text]]
(if-not (commands/get-chat-command db)
@ -132,8 +160,22 @@
db))
db))
(defn check-suggestions
[{:keys [current-chat-id] :as db} [_ text]]
(let [suggestions (suggestions/get-suggestions db text)]
(assoc-in db [:command-suggestions current-chat-id] suggestions)))
(defn select-suggestion!
[{:keys [current-chat-id] :as db} [_ text]]
(let [suggestions (get-in db [:command-suggestions current-chat-id])]
(when (= 1 (count suggestions))
(dispatch [:set-chat-command (ffirst suggestions)]))))
(register-handler :set-chat-input-text
((enrich update-command) update-text))
[(enrich update-command)
(after select-suggestion!)
(after #(dispatch [:animate-command-suggestions]))]
((enrich update-text) check-suggestions))
(defn console? [s]
(= "console" s))
@ -173,7 +215,7 @@
(defn prepare-message
[{: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])
[command] (suggestions/check-suggestion db (str text " "))
message (check-author-direction
db current-chat-id
@ -190,7 +232,7 @@
(assoc db :new-message (when-not (str/blank? text) message)))))
(defn prepare-command
[identity chat-id {:keys [preview preview-string content command]}]
[identity chat-id {:keys [preview preview-string content command to-message]}]
(let [content {:command (command :name)
:content content}]
{:msg-id (random/id)
@ -200,7 +242,8 @@
:content-type content-type-command
:outgoing true
:preview preview-string
:rendered-preview preview}))
:rendered-preview preview
:to-message to-message}))
(defn prepare-staged-commans
[{:keys [current-chat-id identity] :as db} _]
@ -253,8 +296,15 @@
(defn save-commands-to-realm!
[{:keys [new-commands current-chat-id]} _]
(doseq [new-command new-commands]
(messages/save-message current-chat-id
(dissoc new-command :rendered-preview))))
(messages/save-message
current-chat-id
(dissoc new-command :rendered-preview :to-message))))
(defn dispatch-responded-requests!
[{:keys [new-commands current-chat-id]} _]
(doseq [{:keys [to-message]} new-commands]
(when to-message
(dispatch [:request-answered! current-chat-id to-message]))))
(defn invoke-commands-handlers!
[{:keys [new-commands current-chat-id]}]
@ -287,6 +337,7 @@
((after send-message!))
((after save-message-to-realm!))
((after save-commands-to-realm!))
((after dispatch-responded-requests!))
;; todo maybe it is better to track if it was handled or not
((after invoke-commands-handlers!))
((after handle-commands))))
@ -296,11 +347,13 @@
(commands/unstage-command db staged-command)))
(register-handler :set-chat-command
[(after #(dispatch [:command-edit-mode]))
;(after #(dispatch [:animate-show-response]))
]
(fn [db [_ command-key]]
(commands/set-chat-command db command-key)))
[(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
(fn [db [_]]
@ -348,10 +401,10 @@
(dispatch [:load-commands! current-chat-id]))
(register-handler :init-chat
(after #(dispatch [:load-requests!]))
(-> load-messages!
((enrich init-chat))
((after load-commands!))
debug))
((after load-commands!))))
(defn initialize-chats
[{:keys [loaded-chats] :as db} _]
@ -376,6 +429,11 @@
[{:keys [new-message]} [_ {chat-id :from}]]
(messages/save-message chat-id new-message))
(defn dispatch-request!
[{:keys [new-message]} [_ {chat-id :from}]]
(when (= (:content-type new-message) content-type-command-request)
(dispatch [:add-request chat-id new-message])))
(defn receive-message
[db [_ {chat-id :from :as message}]]
(let [message' (check-author-direction db chat-id message)]
@ -384,8 +442,9 @@
(assoc :new-message message'))))
(register-handler :received-msg
(-> receive-message
((after store-message!))))
[(after store-message!)
(after dispatch-request!)]
receive-message)
(register-handler :group-received-msg
(u/side-effect!
@ -394,9 +453,10 @@
(defmethod nav/preload-data! :chat
[{:keys [current-chat-id] :as db} [_ _ id]]
(let [chat-id (or id current-chat-id)
(let [chat-id (or id current-chat-id)
messages (get-in db [:chats chat-id :messages])
db' (assoc db :current-chat-id chat-id)]
db' (assoc db :current-chat-id chat-id)]
(dispatch [:load-requests! chat-id])
(if (seq messages)
db'
(-> db'
@ -434,9 +494,11 @@
((after save-chat!))
((after open-chat!))))
(register-handler :switch-command-suggestions
(fn [db [_]]
(suggestions/switch-command-suggestions db)))
(register-handler :switch-command-suggestions!
(u/side-effect!
(fn [db]
(let [text (if (suggestions/typing-command? db) "" "!")]
(dispatch [:set-chat-input-text text])))))
(defn remove-chat
[{:keys [current-chat-id] :as db} _]
@ -488,4 +550,21 @@
(edit-mode-handler :command))
(register-handler :text-edit-mode
(after #(dispatch [:set-chat-input-text ""]))
(edit-mode-handler :text))
(register-handler :set-layout-height
[(after
(fn [{:keys [current-chat-id] :as db}]
(let [suggestions (get-in db [:suggestions current-chat-id])
mode (get-in db [:edit-mode current-chat-id])]
(when (and (= :command mode) (seq suggestions))
(dispatch [:fix-response-height])))))
(after
(fn [{:keys [current-chat-id] :as db}]
(let [suggestions (get-in db [:command-suggestions current-chat-id])
mode (get-in db [:edit-mode current-chat-id])]
(when (and (= :text mode)) (seq suggestions)
(dispatch [:fix-commands-suggestions-height])))))]
(fn [db [_ h]]
(assoc db :layout-height h)))

View File

@ -1,8 +1,9 @@
(ns status-im.chat.handlers.animation
(:require [re-frame.core :refer [register-handler after dispatch debug]]
[re-frame.middleware :refer [path]]
(:require [re-frame.core :refer [after dispatch debug path]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.chat.constants :refer [input-height request-info-height
minimum-command-suggestions-height
response-height-normal minimum-suggestion-height]]
[status-im.constants :refer [response-input-hiding-duration]]))
@ -17,60 +18,95 @@
(animation-handler :animate-cancel-command
(after #(dispatch [:text-edit-mode]))
(fn [db _]
(assoc db
:to-response-height input-height
:messages-offset 0)))
(assoc db :to-response-height input-height)))
(defn get-response-height
[{:keys [current-chat-id] :as db}]
(let [suggestions (get-in db [:suggestions current-chat-id])
suggestions-height (if suggestions middle-height 0)]
(+ input-height
(min response-height-normal (+ suggestions-height request-info-height)))))
(def response-height (+ input-height response-height-normal))
(defn update-response-height [db]
(assoc-in db [:animations :to-response-height] (get-response-height db)))
(assoc-in db [:animations :to-response-height] response-height))
(register-handler :animate-command-suggestions
(fn [{:keys [current-chat-id] :as db} _]
(let [suggestions? (seq (get-in db [:command-suggestions current-chat-id]))
current (get-in db [:animations :command-suggestions-height])
height (if suggestions? middle-height 30)
changed? (if (and suggestions?
(not (nil? current))
(not= 30 current))
identity inc)]
(-> db
(update :animations assoc :command-suggestions-height height)
(update-in [:animations :commands-height-changed] changed?)))))
(defn get-minimum-height
[{:keys [current-chat-id] :as db}]
(let [path [:chats current-chat-id :command-input :command :type]
type (get-in db path)]
(if (= :response type)
minimum-suggestion-height
30)))
(register-handler :animate-show-response
[(after #(dispatch [:command-edit-mode]))]
(fn [db _]
(-> db
(assoc-in [:animations :messages-offset] request-info-height)
(update-response-height))))
(fn [{:keys [current-chat-id] :as db}]
(let [suggestions? (seq (get-in db [:suggestions current-chat-id]))
height (if suggestions?
middle-height
(get-minimum-height db))]
(assoc-in db [:animations :to-response-height] height))))
(animation-handler :set-response-max-height
(fn [db [_ height]]
(let [prev-height (:response-height-max db)]
(if (not= height prev-height)
(let [db (assoc db :response-height-max height)]
(if (= prev-height (:to-response-height db))
(assoc db :to-response-height height)
db))
db))))
(defn fix-height
[height-key height-signal-key suggestions-key minimum]
(fn [{:keys [current-chat-id] :as db} [_ vy current]]
(let [max-height (get-in db [:layout-height])
moving-down? (pos? vy)
moving-up? (not moving-down?)
under-middle-position? (<= current middle-height)
over-middle-position? (not under-middle-position?)
suggestions (get-in db [suggestions-key current-chat-id])
old-fixed (get-in db [:animations height-key])
new-fixed (cond (not suggestions)
(minimum db)
(and (nil? vy) (nil? current)
(> old-fixed middle-height))
max-height
(and (nil? vy) (nil? current)
(< old-fixed middle-height))
(minimum db)
(and under-middle-position? moving-up?)
middle-height
(and over-middle-position? moving-down?)
middle-height
(and over-middle-position? moving-up?)
max-height
(and under-middle-position? moving-down?)
(minimum db))]
(-> db
(assoc-in [:animations height-key] new-fixed)
(update-in [:animations height-signal-key] inc)))))
(defn commands-min-height
[{:keys [current-chat-id] :as db}]
(let [suggestions (get-in db [:command-suggestions current-chat-id])]
(if (seq suggestions)
minimum-command-suggestions-height
0.1)))
(register-handler :fix-commands-suggestions-height
(fix-height :command-suggestions-height
:commands-height-changed
:command-suggestions
commands-min-height))
(register-handler :fix-response-height
(fn [{:keys [current-chat-id] :as db} [_ vy current]]
(let [max-height (get-in db [:animations :response-height-max])
moving-down? (pos? vy)
moving-up? (not moving-down?)
under-middle-position? (<= current middle-height)
over-middle-position? (not under-middle-position?)
suggestions (get-in db [:suggestions current-chat-id])
new-fixed (cond (not suggestions)
minimum-suggestion-height
(and under-middle-position? moving-up?)
middle-height
(and over-middle-position? moving-down?)
middle-height
(and over-middle-position? moving-up?)
max-height
(and under-middle-position?
moving-down?)
minimum-suggestion-height)]
(-> db
(assoc-in [:animations :to-response-height] new-fixed)
(update-in [:animations :response-height-changed] inc)))))
(fix-height :to-response-height
:response-height-changed
:suggestions
get-minimum-height))

View File

@ -0,0 +1,57 @@
(ns status-im.chat.handlers.requests
(:require [re-frame.core :refer [after dispatch enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.persistence.realm :as realm]
[status-im.utils.handlers :as u]))
(defn store-request!
[{:keys [new-request]}]
(realm/write
(fn []
(realm/create :requests new-request))))
(defn add-request
[db [_ chat-id {:keys [msg-id content]}]]
(let [request {:chat-id chat-id
:message-id msg-id
:type (:command content)
:added (js/Date.)}
request' (update request :type keyword)]
(-> db
(update-in [:chats chat-id :requests] conj request')
(assoc :new-request request))))
(defn load-requests!
[{:keys [current-chat-id] :as db} [_ chat-id]]
(let [chat-id' (or chat-id current-chat-id)
requests (-> :requests
;; todo maybe limit is needed
(realm/get-by-fields {:chat-id chat-id'
:status "open"})
(realm/sorted :added :desc)
(realm/collection->map))
requests' (map #(update % :type keyword) requests)]
(assoc-in db [:chats chat-id' :requests] requests')))
(defn mark-request-as-answered!
[_ [_ chat-id message-id]]
(realm/write
(fn []
(-> :requests
(realm/get-by-fields
{:chat-id chat-id
:message-id message-id})
(realm/single)
(.-status)
(set! "answered")))))
(register-handler :add-request
(after store-request!)
add-request)
(register-handler :load-requests! load-requests!)
(register-handler :request-answered!
(after (fn [_ [_ chat-id]]
(dispatch [:load-requests! chat-id])))
(u/side-effect! mark-request-as-answered!))

View File

@ -18,7 +18,7 @@
[status-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.chat.views.message :refer [chat-message]]
[status-im.chat.views.suggestions :refer [suggestions-view]]
[status-im.chat.views.suggestions :refer [suggestion-container]]
[status-im.chat.views.response :refer [response-view]]
[status-im.chat.views.new-message :refer [chat-message-new]]
[status-im.i18n :refer [label label-pluralize]]
@ -41,10 +41,10 @@
:background-color background-color))))
(defview chat-icon []
[chat-id [:chat :chat-id]
[chat-id [:chat :chat-id]
group-chat [:chat :group-chat]
name [:chat :name]
color [:chat :color]]
name [:chat :name]
color [:chat :color]]
;; TODO stub data ('online' property)
[chat-icon-view-action chat-id group-chat name color true])
@ -98,10 +98,10 @@
subtitle])]]])
(defview menu-item-icon-profile []
[chat-id [:chat :chat-id]
[chat-id [:chat :chat-id]
group-chat [:chat :group-chat]
name [:chat :name]
color [:chat :color]]
name [:chat :name]
color [:chat :color]]
;; TODO stub data ('online' property)
[chat-icon-view-menu-item chat-id group-chat name color true])
@ -140,12 +140,12 @@
:icon-style {:width 20
:height 13}
:handler #(dispatch [:show-group-settings])}]
[{:title (label :t/profile)
[{:title (label :t/profile)
:custom-icon [menu-item-icon-profile]
:icon :menu_group
:icon-style {:width 25
:height 19}
:handler #(dispatch [:show-profile @chat-id])}
:icon :menu_group
:icon-style {:width 25
:height 19}
:handler #(dispatch [:show-profile @chat-id])}
{:title (label :t/search-chat)
:subtitle (label :t/not-implemented)
:icon :search_gray_copy
@ -218,30 +218,26 @@
:custom-action [toolbar-action]}])))
(defview messages-view [group-chat]
[messages [:chat :messages]
contacts [:chat :contacts]]
(let [contacts' (contacts-by-identity contacts)]
[list-view {:renderRow (message-row contacts' group-chat (count messages))
:renderScrollComponent #(invertible-scroll-view (js->clj %))
:onEndReached #(dispatch [:load-more-messages])
:enableEmptySections true
:keyboardShouldPersistTaps true
:dataSource (to-datasource-inverted messages)}]))
[messages [:chat :messages]
contacts [:chat :contacts]]
(let [contacts' (contacts-by-identity contacts)]
[list-view {:renderRow (message-row contacts' group-chat (count messages))
:renderScrollComponent #(invertible-scroll-view (js->clj %))
:onEndReached #(dispatch [:load-more-messages])
:enableEmptySections true
:keyboardShouldPersistTaps true
:dataSource (to-datasource-inverted messages)}]))
(defn messages-container-animation-logic [{:keys [to-value val]}]
(defn messages-container-animation-logic
[{:keys [offset val]}]
(fn [_]
(let [to-value @to-value]
(anim/start (anim/spring val {:toValue to-value})
(fn [arg]
(when (.-finished arg)
(dispatch [:set-animation ::messages-offset-current to-value])))))))
(anim/start (anim/spring val {:toValue @offset}))))
(defn messages-container [messages]
(let [to-messages-offset (subscribe [:animations :messages-offset])
cur-messages-offset (subscribe [:animations ::messages-offset-current])
messages-offset (anim/create-value (or @cur-messages-offset 0))
context {:to-value to-messages-offset
:val messages-offset}
(let [offset (subscribe [:messages-offset])
messages-offset (anim/create-value 0)
context {:offset offset
:val messages-offset}
on-update (messages-container-animation-logic context)]
(r/create-class
{:component-did-mount
@ -250,7 +246,7 @@
on-update
:reagent-render
(fn [messages]
@to-messages-offset
@offset
[animated-view {:style (st/messages-container messages-offset)}
messages])})))
@ -259,16 +255,19 @@
show-actions-atom [:show-actions]
command [:get-chat-command]
command? [:command?]
to-msg-id [:get-chat-command-to-msg-id]]
[view {:style st/chat-view
suggestions [:get-suggestions]
to-msg-id [:get-chat-command-to-msg-id]
layout-height [:get :layout-height]]
[view {:style st/chat-view
:onLayout (fn [event]
(let [height (.. event -nativeEvent -layout -height)]
(dispatch [:set-response-max-height height])))}
(when (not= height layout-height)
(dispatch [:set-layout-height height]))))}
[chat-toolbar]
[messages-container
[messages-view group-chat]]
(when group-chat [typing-all])
[response-view]
(when-not command? [suggestions-view])
(when-not command? [suggestion-container])
[chat-message-new]
(when show-actions-atom [actions-view])])

View File

@ -45,12 +45,3 @@
(def container
{:backgroundColor color-white})
(def drag-down-touchable
{:height 22
:alignItems :center
:justifyContent :center})
(def drag-down-icon
{:width 16
:height 16})

View File

@ -0,0 +1,12 @@
(ns status-im.chat.styles.dragdown
(:require [status-im.components.styles :refer [color-white]]))
(def drag-down-touchable
{:height 22
:background-color color-white
:alignItems :center
:justifyContent :center})
(def drag-down-icon
{:width 16
:height 16})

View File

@ -16,13 +16,18 @@
:backgroundColor color-white
:elevation 4})
(def command-container
{:left 0
:backgroundColor :white
:position :absolute})
(defn command-text-container
[{:keys [color]}]
{:flexDirection :column
:marginTop 16
:marginBottom 16
:marginLeft 16
:marginRight 0
:marginRight 8
:backgroundColor color
:height 24
:borderRadius 50})

View File

@ -4,7 +4,7 @@
[status-im.chat.constants :refer [input-height]]))
(def message-input-container
{:flex 1
{:flex 1
:marginRight 0})
(def input-container

View File

@ -9,11 +9,24 @@
:justifyContent :center})
(defn message-input-button [scale]
{:transform [{:scale scale}]})
{:transform [{:scale scale}]
:width 24
:height 24
:alignItems :center
:justifyContent :center})
(def list-icon
{:width 13
:height 12})
{:width 16
:height 16})
(def requests-icon
{:background-color :#7099e6
:width 8
:height 8
:border-radius 8
:left 0
:top 0
:position :absolute})
(def close-icon
{:width 12

View File

@ -83,11 +83,12 @@
:width 12
:height 12})
(def command-input
(defn command-input [ml disbale?]
{:flex 1
:marginRight 16
:margin-left (- ml 5)
:marginTop -2
:padding 0
:fontSize 14
:fontFamily font
:color text1-color})
:color (if disbale? color-white text1-color)})

View File

@ -1,33 +1,44 @@
(ns status-im.chat.styles.suggestions
(:require [status-im.components.styles :refer [font
color-light-blue-transparent
color-white
color-black
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color
text3-color]]))
color-light-blue-transparent
color-white
color-black
color-gray
color-blue
color-blue-transparent
selected-message-color
online-color
separator-color
text1-color
text2-color
text3-color]]))
(def suggestion-height 88)
(def suggestion-height 60)
(def suggestion-highlight
{:margin-left 57})
(def suggestion-container
{:flexDirection :column
:paddingLeft 16
:backgroundColor color-white})
{:backgroundColor color-white})
(def suggestion-sub-container
{:height suggestion-height
:borderBottomWidth 1
:borderBottomColor separator-color})
:borderBottomColor separator-color
:flex-direction :row})
(def command-description-container
{:flex 0.6})
(def command-label-container
{:flex 0.4
:flex-direction :column
:align-items :flex-end
:margin-right 16})
(defn suggestion-background
[{:keys [color]}]
{:alignSelf :flex-start
:marginTop 10
{:marginTop 10
:height 24
:backgroundColor color
:borderRadius 50})
@ -39,6 +50,14 @@
:fontFamily font
:color color-white})
(def title-container
{:margin-left 57
:margin-bottom 16})
(def title-text
{:font-size 13
:color :#8f838c93})
(def value-text
{:marginTop 6
:fontSize 14
@ -51,22 +70,53 @@
:fontFamily font
:color text2-color})
(defn suggestions-container [suggestions-count]
{:flexDirection :row
:marginVertical 1
:marginHorizontal 0
:height (min 168 (* suggestion-height suggestions-count))
:backgroundColor color-white
:borderRadius 5})
(defn container [height]
{:flexDirection :column
:position :absolute
:left 0
:right 0
:bottom 0
:height height
:backgroundColor color-white
:elevation 2})
(def container
{:backgroundColor color-white})
(def request-container
{:height 56
:flex-direction :row})
(def drag-down-touchable
{:height 22
:alignItems :center
(def request-icon-container
{:height 56
:width 57
:align-items :center
:justifyContent :center})
(def drag-down-icon
{:width 16
:height 16})
(defn request-icon-background [color]
{:height 32
:width 32
:border-radius 32
:background-color color
:align-items :center
:justifyContent :center})
(def request-icon
{:width 12
:height 12})
(def request-info-container
{:height 56
:padding-top 10})
(def request-info-description
{:font-size 12
:color color-black})
(def request-message-info
{:font-size 12
:margin-top 2
:color color-gray})
(def header-icon
{:background-color :#838c93
:width 14
:border-radius 1
:height 3})

View File

@ -1,15 +1,12 @@
(ns status-im.chat.subs
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub dispatch subscribe path]]
[status-im.db :as db]
[status-im.chat.suggestions :refer
[get-suggestions typing-command?]]
[status-im.models.commands :as commands]
[status-im.constants :refer [response-suggesstion-resize-duration]]
[status-im.chat.constants :as c]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
[status-im.chat.views.plain-message :as plain-message]
[status-im.chat.views.command :as command]
[status-im.chat.constants :as c]))
[status-im.chat.views.command :as command]))
(register-sub :chat-properties
(fn [db [_ properties]]
@ -43,11 +40,8 @@
(register-sub :get-suggestions
(fn [db _]
(let [input-text (->> (:current-chat-id @db)
db/chat-input-text-path
(get-in @db)
(reaction))]
(reaction (get-suggestions @db @input-text)))))
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:command-suggestions @chat-id])))))
(register-sub :get-commands
(fn [db _]
@ -79,7 +73,7 @@
(register-sub :valid-plain-message?
(fn [_ _]
(let [input-message (subscribe [:get-chat-input-text])
(let [input-message (subscribe [:get-chat-input-text])
staged-commands (subscribe [:get-chat-staged-commands])]
(reaction
(plain-message/message-valid? @staged-commands @input-message)))))
@ -93,6 +87,15 @@
(fn [db _]
(reaction (commands/get-chat-command @db))))
(register-sub :get-command-parameter
(fn [db]
(let [command (subscribe [:get-chat-command])
chat-id (subscribe [:get-current-chat-id])]
(reaction
(let [path [:chats @chat-id :command-input :parameter-idx]
n (get-in @db path)]
(when n (nth (:params @command) n)))))))
(register-sub :get-chat-command-content
(fn [db _]
(reaction (commands/get-chat-command-content @db))))
@ -114,10 +117,6 @@
(fn [db [_ chat-id]]
(reaction (get-in @db [:chats chat-id]))))
(register-sub :typing-command?
(fn [db _]
(reaction (typing-command? @db))))
(register-sub :get-content-suggestions
(fn [db _]
(reaction (get-in @db [:suggestions (:current-chat-id @db)]))))
@ -127,3 +126,49 @@
(->> (get-in @db [:edit-mode (:current-chat-id @db)])
(= :command)
(reaction))))
(register-sub :command-type
(fn []
(let [command (subscribe [:get-chat-command])]
(reaction (:type @command)))))
(register-sub :messages-offset
(fn []
(let [command? (subscribe [:command?])
type (subscribe [:command-type])
command-suggestions (subscribe [:get-content-suggestions])
suggestions (subscribe [:get-suggestions])]
(reaction
(cond (and @command? (= @type :response))
c/request-info-height
(and @command? (= @type :command) (seq @command-suggestions))
c/suggestions-header-height
(and (not @command?) (seq @suggestions))
c/suggestions-header-height
:else 0)))))
(register-sub :command-icon-width
(fn []
(let [width (subscribe [:get :command-icon-width])
type (subscribe [:command-type])]
(reaction (if (= :command @type)
@width
0)))))
(register-sub :get-requests
(fn [db]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:chats @chat-id :requests])))))
(register-sub :get-response
(fn [db [_ n]]
(let [chat-id (subscribe [:get-current-chat-id])]
(reaction (get-in @db [:chats @chat-id :responses n])))))
(register-sub :is-request-answered?
(fn [_ [_ message-id]]
(let [requests (subscribe [:get-requests])]
(reaction (not (some #(= message-id (:message-id %)) @requests))))))

View File

@ -0,0 +1,39 @@
(ns status-im.chat.suggestions-responder
(:require [status-im.components.drag-drop :as drag]
[status-im.components.animation :as anim]
[status-im.components.react :as react]
[re-frame.core :refer [dispatch]]))
;; todo bad name. Ideas?
(defn enough-dy [gesture]
(> (Math/abs (.-dy gesture)) 10))
(defn on-move [response-height kb-height orientation]
(fn [_ gesture]
(when (enough-dy gesture)
(let [w (react/get-dimensions "window")
;; depending on orientation use height or width of screen
prop (if (= :portrait @orientation)
:height
:width)
;; subtract keyboard height to get "real height" of screen
;; then subtract gesture position to get suggestions height
;; todo maybe it is better to use margin-top instead height
;; it is not obvious
to-value (- (prop w) @kb-height (.-moveY gesture))]
(anim/start
(anim/spring response-height {:toValue to-value}))))))
(defn on-release [response-height handler-name]
(fn [_ gesture]
(when (enough-dy gesture)
(dispatch [handler-name
(.-vy gesture)
;; todo access to "private" property
;; better to find another way...
(.-_value response-height)]))))
(defn pan-responder [response-height kb-height orientation handler-name]
(drag/create-pan-responder
{:on-move (on-move response-height kb-height orientation)
:on-release (on-release response-height handler-name)}))

View File

@ -27,9 +27,15 @@
(when (valid? message validator)
(send-command)))
(defn command-icon [command]
[view (st/command-text-container command)
[text {:style st/command-text} (:text command)]])
(defview command-icon [command]
[icon-width [:get :command-icon-width]]
[view st/command-container
[view {:style (st/command-text-container command)
:onLayout (fn [event]
(let [width (.. event -nativeEvent -layout -width)]
(when (not= icon-width width)
(dispatch [:set :command-icon-width width]))))}
[text {:style st/command-text} (str "!" (:name command))]]])
(defn cancel-button []
[touchable-highlight {:on-press cancel-command-input}

View File

@ -80,25 +80,6 @@
(->> (when command (name command))
(str "request-")))
;; todo remove (merging leftover)
#_(defview message-content-command-request
[{:keys [msg-id content from incoming-group]}]
[commands [:get-responses]]
(let [{:keys [command content]} (parse-command-request commands content)]
[touchable-highlight {:onPress #(set-chat-command msg-id command)
:accessibility-label (label command)}
[view st/comand-request-view
[view st/command-request-message-view
(when incoming-group
[text {:style st/command-request-from-text} from])
[text {:style st/style-message-text} content]]
[view (st/command-request-image-view command)
[image {:source {:uri (:icon command)}
:style st/command-request-image}]]
(when-let [request-text (:request-text command)]
[view st/command-request-text-view
[text {:style st/style-sub-text} request-text]])]]))
(defn message-view
[message content]
[view (st/message-view message)

View File

@ -21,24 +21,27 @@
(defn message-input-container [input]
[view st/message-input-container input])
(def plain-input-options
(defn plain-input-options [disbale?]
{:style st-message/message-input
:onChangeText plain-message/set-input-message
:onChangeText (when-not disbale? plain-message/set-input-message)
:editable (not disbale?)
:onSubmitEditing plain-message/send})
(def command-input-options
{:style st-response/command-input
:onChangeText command/set-input-message
(defn command-input-options [icon-width disbale?]
{:style (st-response/command-input icon-width disbale?)
:onChangeText (when-not disbale? command/set-input-message)
:onSubmitEditing command/send-command})
(defview message-input [input-options]
[command? [:command?]
input-message [:get-chat-input-text]
input-command [:get-chat-command-content]]
input-command [:get-chat-command-content]
icon-width [:command-icon-width]
disbale? [:get :disable-input]]
[text-input (merge
(if command?
command-input-options
plain-input-options)
(command-input-options icon-width disbale?)
(plain-input-options disbale?))
{:autoFocus false
:blurOnSubmit false
:accessibility-label :input}
@ -47,6 +50,7 @@
(defview plain-message-input-view [{:keys [input-options validator]}]
[command? [:command?]
{:keys [type] :as command} [:get-chat-command]
input-command [:get-chat-command-content]
valid-plain-message? [:valid-plain-message?]
valid-command? [:valid-command? validator]]
@ -62,4 +66,6 @@
command/send-command
plain-message/send)]
[send-button {:on-press on-press
:accessibility-label :send-message}]))]])
:accessibility-label :send-message}]))
(when (and command? (= :command type))
[command/command-icon command])]])

View File

@ -16,24 +16,30 @@
(for [command staged-commands]
^{:key command} [staged-command-view command])])
(defn get-options [{:keys [type placeholder]} command-type]
(let [options (case (keyword type)
:phone {:input-options {:keyboardType :phone-pad}
:validator valid-mobile-number?}
:password {:input-options {:secureTextEntry true}}
:number {:input-options {:keyboardType :numeric}}
;; todo maybe nil is fine for now :)
nil #_(throw (js/Error. "Uknown command type")))]
(if (= :response command-type)
(if placeholder
(assoc-in options [:input-options :placeholder] placeholder)
options)
(assoc-in options [:input-options :placeholder] ""))))
(defview show-input []
[command [:get-chat-command]
command? [:command?]]
[parameter [:get-command-parameter]
command? [:command?]
type [:command-type]]
[plain-message-input-view
(when command?
(case (:command command)
:phone {:input-options {:keyboardType :phone-pad}
:validator valid-mobile-number?}
:keypair {:input-options {:secureTextEntry true}}
:confirmation-code {:input-options {:keyboardType :numeric}}
:money {:input-options {:keyboardType :numeric}}
:request {:input-options {:keyboardType :numeric}}
;; todo maybe nil is finr for now :)
nil #_(throw (js/Error. "Uknown command type"))))])
(when command? (get-options parameter type))])
(defview chat-message-new []
[staged-commands [:get-chat-staged-commands]]
[view st/new-message-container
(when (and staged-commands (pos? (count staged-commands)))
(when (seq staged-commands)
[staged-commands-view staged-commands])
[show-input]])

View File

@ -5,6 +5,7 @@
[status-im.components.react :refer [view
animated-view
icon
text
touchable-highlight]]
[status-im.components.animation :as anim]
[status-im.chat.styles.plain-message :as st]
@ -30,21 +31,24 @@
(defn list-container [min]
(fn [{:keys [command? width]}]
(let [n-width (if @command? min 56)
delay (if @command? 100 0)]
delay (if @command? 100 0)]
(anim/start (anim/timing width {:toValue n-width
:duration response-input-hiding-duration
:delay delay})))))
:delay delay})
#(dispatch [:set :disable-input false])))))
(defn commands-button []
(let [command? (subscribe [:command?])
buttons-scale (anim/create-value (if @command? 1 0))
(let [command? (subscribe [:command?])
requests (subscribe [:get-requests])
suggestions (subscribe [:get-suggestions])
buttons-scale (anim/create-value (if @command? 1 0))
container-width (anim/create-value (if @command? 20 56))
context {:command? command?
:val buttons-scale
:width container-width}
on-update (fn [_]
((button-animation-logic context))
((list-container 20) context))]
context {:command? command?
:val buttons-scale
:width container-width}
on-update (fn [_]
((button-animation-logic context))
((list-container 20) context))]
(r/create-class
{:component-did-mount
on-update
@ -52,12 +56,17 @@
on-update
:reagent-render
(fn []
[touchable-highlight {:on-press #(dispatch [:switch-command-suggestions])
[touchable-highlight {:on-press #(dispatch [:switch-command-suggestions!])
:disabled @command?}
[animated-view {:style (st/message-input-button-touchable
container-width)}
[animated-view {:style (st/message-input-button buttons-scale)}
[icon :list st/list-icon]]]])})))
(if (seq @suggestions)
[icon :close_gray st/close-icon]
[icon :input_list st/list-icon])
(when (and (seq @requests)
(not (seq @suggestions)))
[view st/requests-icon])]]])})))
(defn smile-animation-logic [{:keys [command? val width]}]
(fn [_]
@ -70,13 +79,13 @@
(anim/set-value width 0.1)))))))
(defn smile-button []
(let [command? (subscribe [:command?])
buttons-scale (anim/create-value (if @command? 1 0))
(let [command? (subscribe [:command?])
buttons-scale (anim/create-value (if @command? 1 0))
container-width (anim/create-value (if @command? 0.1 56))
context {:command? command?
:val buttons-scale
:width container-width}
on-update (smile-animation-logic context)]
context {:command? command?
:val buttons-scale
:width container-width}
on-update (smile-animation-logic context)]
(r/create-class
{:component-did-mount
on-update

View File

@ -19,49 +19,47 @@
(->> (name command)
(str "request-")))
(defn request-button-animation-logic [{:keys [to-value val loop?]}]
(fn [_]
(let [loop? @loop?
minimum 1
maximum 1.3
to-scale (if loop?
(or @to-value maximum)
minimum)]
(def min-scale 1)
(def max-scale 1.3)
(defn button-animation [val to-value loop? answered?]
(anim/anim-sequence
[(anim/anim-delay
(if (and @loop? (not @answered?))
request-message-icon-scale-delay
0))
(anim/spring val {:toValue to-value})]))
(defn request-button-animation-logic
[{:keys [to-value val loop? answered?] :as context}]
(anim/start
(button-animation val to-value loop? answered?)
#(if (and @loop? (not @answered?))
(let [new-value (if (= to-value min-scale) max-scale min-scale)
context' (assoc context :to-value new-value)]
(request-button-animation-logic context'))
(anim/start
(anim/anim-sequence
[(anim/anim-delay (if loop? request-message-icon-scale-delay 0))
(anim/spring val {:toValue to-scale})])
(fn [arg]
(when (.-finished arg)
(dispatch [:set-animation ::request-button-scale-current to-scale])
(when loop?
(dispatch [:set-animation ::request-button-scale (if (= to-scale minimum)
maximum
minimum)]))))))))
(button-animation val min-scale loop? answered?)))))
(defn request-button [msg-id command]
(let [to-scale (subscribe [:animations ::request-button-scale])
cur-scale (subscribe [:animations ::request-button-scale-current])
scale-anim-val (anim/create-value (or @cur-scale 1))
(let [scale-anim-val (anim/create-value min-scale)
answered? (subscribe [:is-request-answered? msg-id])
loop? (r/atom true)
context {:to-value to-scale
:val scale-anim-val
:loop? loop?}
on-update (request-button-animation-logic context)]
context {:to-value max-scale
:val scale-anim-val
:answered? answered?
:loop? loop?}]
(r/create-class
{:component-did-mount
on-update
:component-did-update
on-update
(when-not @answered? #(request-button-animation-logic context))
:component-will-unmount
#(reset! loop? false)
:reagent-render
(fn [msg-id command]
@to-scale
[touchable-highlight {:on-press (fn []
(reset! loop? false)
(set-chat-command msg-id command))
:style st/command-request-image-touchable}
;:accessibility-label (label command)
[touchable-highlight
{:on-press (when-not @answered?
#(set-chat-command msg-id command))
:style st/command-request-image-touchable}
[animated-view {:style (st/command-request-image-view command scale-anim-val)}
[image {:source {:uri (:icon command)}
:style st/command-request-image}]]])})))

View File

@ -12,8 +12,9 @@
touchable-highlight]]
[status-im.components.drag-drop :as drag]
[status-im.chat.styles.response :as st]
[status-im.chat.styles.dragdown :as ddst]
[status-im.components.animation :as anim]
[status-im.components.react :as react]))
[status-im.chat.suggestions-responder :as resp]))
(defn drag-icon []
[view st/drag-container
@ -32,71 +33,41 @@
;; TODO stub data: request message info
"By ???, MMM 1st at HH:mm"]])
;; todo bad name. Ideas?
(defn enough-dy [gesture]
(> (Math/abs (.-dy gesture)) 10))
(defn on-move [response-height kb-height orientation]
(fn [_ gesture]
(when (enough-dy gesture)
(let [w (react/get-dimensions "window")
;; depending on orientation use height or width of screen
prop (if (= :portrait @orientation)
:height
:width)
;; subtract keyboard height to get "real height" of screen
;; then subtract gesture position to get suggestions height
;; todo maybe it is better to use margin-top instead height
;; it is not obvious
to-value (- (prop w) @kb-height (.-moveY gesture))]
(anim/start
(anim/spring response-height {:toValue to-value}))))))
(defn on-release [response-height]
(fn [_ gesture]
(when (enough-dy gesture)
(dispatch [:fix-response-height
(.-vy gesture)
;; todo access to "private" property
;; better to find another way...
(.-_value response-height)]))))
(defn pan-responder [response-height kb-height orientation]
(drag/create-pan-responder
{:on-move (on-move response-height kb-height orientation)
:on-release (on-release response-height)}))
(defn request-info [response-height]
(let [orientation (subscribe [:get :orientation])
kb-height (subscribe [:get :keyboard-height])
pan-responder (pan-responder response-height kb-height orientation)
command (subscribe [:get-chat-command])]
(let [orientation (subscribe [:get :orientation])
kb-height (subscribe [:get :keyboard-height])
pan-responder (resp/pan-responder response-height
kb-height
orientation
:fix-response-height)
command (subscribe [:get-chat-command])]
(fn [response-height]
[view (merge (drag/pan-handlers pan-responder)
{:style (st/request-info (:color @command))})
[drag-icon]
[view st/inner-container
[command-icon nil]
[info-container @command]
[touchable-highlight {:on-press #(dispatch [:start-cancel-command])}
[view st/cancel-container
[icon :close-white st/cancel-icon]]]]])))
(if (= :response (:type @command))
[view (merge (drag/pan-handlers pan-responder)
{:style (st/request-info (:color @command))})
[drag-icon]
[view st/inner-container
[command-icon nil]
[info-container @command]
[touchable-highlight {:on-press #(dispatch [:start-cancel-command])}
[view st/cancel-container
[icon :close-white st/cancel-icon]]]]]
[view (merge (drag/pan-handlers pan-responder)
{:style ddst/drag-down-touchable})
[icon :drag_down ddst/drag-down-icon]]))))
(defn container-animation-logic [{:keys [to-value val]}]
(fn [_]
(let [to-value @to-value]
(anim/start (anim/spring val {:toValue to-value
:tension 50
:friction 10})))))
(let [to-value @to-value]
(anim/start (anim/spring val {:toValue to-value}))))
(defn container [response-height & children]
(let [;; todo to-response-height, cur-response-height must be specific
;; for each chat
to-response-height (subscribe [:animations :to-response-height])
changed (subscribe [:animations :response-height-changed])
context {:to-value to-response-height
:val response-height}
on-update (container-animation-logic context)]
changed (subscribe [:animations :response-height-changed])
context {:to-value to-response-height
:val response-height}
on-update #(container-animation-logic context)]
(r/create-class
{:component-did-mount
on-update

View File

@ -2,47 +2,127 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
scroll-view
text
icon
image
touchable-highlight
list-view
list-item]]
list-item
animated-view]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.chat.styles.suggestions :as st]))
[status-im.chat.styles.suggestions :as st]
[status-im.chat.styles.dragdown :as ddst]
[reagent.core :as r]
[status-im.components.animation :as anim]
[status-im.components.drag-drop :as drag]
[status-im.chat.suggestions-responder :as resp]
[status-im.chat.constants :as c]))
(defn set-command-input [command]
(dispatch [:set-chat-command command]))
(defview request-item [{:keys [type message-id]}]
[{:keys [color icon description] :as response} [:get-response type]]
[touchable-highlight
{:on-press #(dispatch [:set-response-chat-command message-id type])}
[view st/request-container
[view st/request-icon-container
[view (st/request-icon-background color)
[image {:source {:uri icon}
:style st/request-icon}]]]
[view st/request-info-container
[text {:style st/request-info-description} description]
;; todo stub
[text {:style st/request-message-info}
"By console, today at 14:50"]]]])
(defn render-request-row
[{:keys [chat-id message-id] :as row} _ _]
(list-item
^{:key [chat-id message-id]}
[request-item row]))
(defn suggestion-list-item
[[command {:keys [description]
name :name
:as suggestion}]]
(let [label (str "!" name)]
[touchable-highlight
{:onPress #(set-command-input command)}
{:onPress #(set-command-input command)
:style st/suggestion-highlight}
[view st/suggestion-container
[view st/suggestion-sub-container
[view (st/suggestion-background suggestion)
[text {:style st/suggestion-text} label]]
[text {:style st/value-text} label]
[text {:style st/description-text} description]]]]))
[view st/command-description-container
[text {:style st/value-text} label]
[text {:style st/description-text} description]]
[view st/command-label-container
[view (st/suggestion-background suggestion)
[text {:style st/suggestion-text} label]]]]]]))
(defn render-row [row _ _]
(list-item [suggestion-list-item row]))
(defn title [s]
[view st/title-container
[text {:style st/title-text} s]])
(defview suggestions-view []
[suggestions [:get-suggestions]]
(when (seq suggestions)
[view st/container
[touchable-highlight {:style st/drag-down-touchable
:onPress (fn []
;; TODO hide suggestions?
)}
[view
[icon :drag_down st/drag-down-icon]]]
[view (st/suggestions-container (count suggestions))
[list-view {:dataSource (to-datasource suggestions)
:enableEmptySections true
[suggestions [:get-suggestions]
requests [:get-requests]]
[scroll-view {:keyboardShouldPersistTaps true}
(when (seq requests) [title "Requests"])
(when (seq requests)
[view
[list-view {:dataSource (to-datasource requests)
:keyboardShouldPersistTaps true
:renderRow render-row}]]]))
:renderRow render-request-row}]])
[title "Commands"]
[view
[list-view {:dataSource (to-datasource suggestions)
:keyboardShouldPersistTaps true
:renderRow render-row}]]])
(defn header [h]
(let [orientation (subscribe [:get :orientation])
kb-height (subscribe [:get :keyboard-height])
pan-responder (resp/pan-responder h
kb-height
orientation
:fix-commands-suggestions-height)]
(fn [_]
[view
(merge (drag/pan-handlers pan-responder)
{:style ddst/drag-down-touchable})
[view st/header-icon]])))
(defn container-animation-logic [{:keys [to-value val]}]
(when-let [to-value @to-value]
(anim/start (anim/spring val {:toValue to-value}))))
(defn container [h & elements]
(let [;; todo to-response-height, cur-response-height must be specific
;; for each chat
to-response-height (subscribe [:animations :command-suggestions-height])
changed (subscribe [:animations :commands-height-changed])
context {:to-value to-response-height
:val h}
on-update #(container-animation-logic context)]
(r/create-class
{:component-did-mount
on-update
:component-did-update
on-update
:reagent-render
(fn [h & elements]
@changed
(into [animated-view {:style (st/container h)}] elements))})))
(defn suggestion-container []
(let [h (anim/create-value 0.1)
command? (subscribe [:command?])]
(when-not @command?
[container h
[header h]
[suggestions-view]
[view {:height c/input-height}]])))

View File

@ -1,6 +1,5 @@
(ns status-im.commands.handlers.jail
(:require [re-frame.core :refer [register-handler after dispatch subscribe
trim-v debug]]
(:require [re-frame.core :refer [after dispatch subscribe trim-v debug]]
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [http-get toast]]
[status-im.components.jail :as j]

View File

@ -1,7 +1,6 @@
(ns status-im.commands.handlers.loading
(:require-macros [status-im.utils.slurp :refer [slurp]])
(:require [re-frame.core :refer [register-handler after dispatch subscribe
trim-v debug]]
(:require [re-frame.core :refer [after dispatch subscribe trim-v debug]]
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [http-get toast]]
[clojure.string :as s]
@ -91,13 +90,13 @@
(reg-handler ::fetch-commands! (u/side-effect! fetch-commands!))
(reg-handler ::validate-hash
(after dispatch-loaded!)
validate-hash)
(after dispatch-loaded!)
validate-hash)
(reg-handler ::parse-commands! (u/side-effect! parse-commands!))
(reg-handler ::add-commands
(after save-commands-js!)
add-commands)
(after save-commands-js!)
add-commands)
(reg-handler ::loading-failed! (u/side-effect! loading-failed!))

View File

@ -3,7 +3,8 @@
[clojure.walk :as w]
[status-im.components.react :refer [text scroll-view view
image touchable-highlight]]
[re-frame.core :refer [register-handler dispatch trim-v debug]]))
[re-frame.core :refer [dispatch trim-v debug]]
[status-im.utils.handlers :refer [register-handler]]))
(defn json->clj [json]
(if (= json "undefined")
@ -44,4 +45,4 @@
(defn reg-handler
([name handler] (reg-handler name nil handler))
([name middleware handler]
(register-handler name [#_debug trim-v middleware] handler)))
(register-handler name [trim-v middleware] handler)))

View File

@ -16,4 +16,4 @@
(def response-input-hiding-duration 100)
(def response-suggesstion-resize-duration 100)
(def default-number-of-messages 10)
(def default-number-of-messages 5)

View File

@ -1,5 +1,6 @@
(ns status-im.contacts.handlers
(:require [re-frame.core :refer [register-handler after dispatch]]
(:require [re-frame.core :refer [after dispatch]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.models.contacts :as contacts]
[status-im.utils.crypt :refer [encrypt]]
[clojure.string :as s]

View File

@ -38,7 +38,6 @@
:phone-number ""}
:disable-group-creation false
:animations {:to-response-height 0.1
:messages-offset 0
;; todo clear this
:tabs-bar-value (anim/create-value 0)}})

View File

@ -1,5 +1,6 @@
(ns status-im.discovery.handlers
(:require [re-frame.core :refer [register-handler after dispatch enrich]]
(:require [re-frame.core :refer [after dispatch enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.protocol.api :as api]
[status-im.navigation.handlers :as nav]
[status-im.discovery.model :as discoveries]

View File

@ -1,6 +1,6 @@
(ns status-im.group-settings.handlers
(:require [re-frame.core :refer [register-handler debug dispatch after
enrich]]
(:require [re-frame.core :refer [debug dispatch after enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.persistence.realm :as r]
[status-im.chat.handlers :refer [delete-messages!]]
[status-im.protocol.api :as api]

View File

@ -1,13 +1,13 @@
(ns status-im.handlers
(:require
[re-frame.core :refer [register-handler after dispatch debug]]
[re-frame.core :refer [after dispatch debug]]
[schema.core :as s :include-macros true]
[status-im.db :refer [app-db schema]]
[status-im.persistence.simple-kv-store :as kv]
[status-im.protocol.state.storage :as storage]
[status-im.utils.logging :as log]
[status-im.utils.crypt :refer [gen-random-bytes]]
[status-im.utils.handlers :as u]
[status-im.utils.handlers :refer [register-handler] :as u]
status-im.chat.handlers
status-im.chat.handlers.animation
status-im.group-settings.handlers
@ -19,7 +19,8 @@
status-im.commands.handlers.loading
status-im.commands.handlers.jail
status-im.qr-scanner.handlers
status-im.protocol.handlers))
status-im.protocol.handlers
status-im.chat.handlers.requests))
;; -- Middleware ------------------------------------------------------------
;;
@ -40,16 +41,12 @@
(defn set-el [db [_ k v]]
(assoc db k v))
(register-handler :set
debug
set-el)
(register-handler :set set-el)
(defn set-in [db [_ path v]]
(assoc-in db path v))
(register-handler :set-in
debug
set-in)
(register-handler :set-in set-in)
(register-handler :set-animation
(fn [db [_ k v]]

View File

@ -34,9 +34,10 @@
(defn set-response-chat-command
[{:keys [current-chat-id] :as db} msg-id command-key]
(update-in db [:chats current-chat-id :command-input] merge
{:content nil
:command (get-command db command-key)
:to-msg-id msg-id}))
{:content nil
:command (get-command db command-key)
:parameter-idx 0
:to-msg-id msg-id}))
(defn set-chat-command [db command-key]
(set-response-chat-command db nil command-key))

View File

@ -47,24 +47,6 @@
#{c/content-type-command c/content-type-command-request}
type))
<<<<<<< HEAD
(defn get-messages [chat-id]
(->> (-> (r/get-by-field :msgs :chat-id chat-id)
(r/sorted :timestamp :desc)
(r/collection->map))
(into '())
;; todo why reverse?
reverse
(map (fn [{:keys [content-type preview] :as message}]
(if (command-type? content-type)
(-> message
(update :content str-to-map)
(assoc :rendered-preview (when preview
(generate-hiccup
(read-string preview))))
(dissoc :preview))
message)))))
=======
(defn get-messages
([chat-id] (get-messages chat-id 0))
([chat-id from]
@ -74,11 +56,10 @@
(r/collection->map))
(into '())
reverse
(map (fn [{:keys [content-type] :as message}]
(keep (fn [{:keys [content-type] :as message}]
(if (command-type? content-type)
(update message :content str-to-map)
message))))))
>>>>>>> develop
(defn update-message! [{:keys [msg-id] :as msg}]
(log/debug "update-message!" msg)

View File

@ -1,5 +1,6 @@
(ns status-im.navigation.handlers
(:require [re-frame.core :refer [register-handler dispatch debug enrich after]]))
(:require [re-frame.core :refer [dispatch debug enrich after]]
[status-im.utils.handlers :refer [register-handler]]))
(defn push-view [db view-id]
(-> db

View File

@ -1,6 +1,7 @@
(ns status-im.new-group.handlers
(:require [status-im.protocol.api :as api]
[re-frame.core :refer [register-handler after dispatch debug enrich]]
[re-frame.core :refer [after dispatch debug enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.components.styles :refer [default-chat-color]]
[status-im.models.chats :as chats]
[clojure.string :as s]))

View File

@ -1,6 +1,7 @@
(ns status-im.participants.handlers
(:require [status-im.navigation.handlers :as nav]
[re-frame.core :refer [register-handler debug]]))
[re-frame.core :refer [debug]]
[status-im.utils.handlers :refer [register-handler]]))
(defmethod nav/preload-data! :add-participants
[db _]

View File

@ -2,7 +2,8 @@
(:require [cljs.reader :refer [read-string]]
[status-im.components.styles :refer [default-chat-color]]
[status-im.utils.types :refer [to-string]]
[status-im.utils.utils :as u])
[status-im.utils.utils :as u]
[clojure.string :as str])
(:refer-clojure :exclude [exists?]))
(def opts {:schema [{:name :contacts
@ -14,6 +15,13 @@
:optional true}
:photo-path {:type "string"
:optinal true}}}
{:name :requests
:properties {:message-id :string
:chat-id :string
:type :string
:status {:type :string
:default "open"}
:added :date}}
{:name :kv-store
:primaryKey :key
:properties {:key "string"
@ -107,12 +115,16 @@
[schema-name obj]
(write (fn [] (create schema-name obj true))))
(defn and-q [queries]
(str/join " and " queries))
(defmulti to-query (fn [schema-name operator field value]
operator))
(defmethod to-query :eq [schema-name operator field value]
(let [value (to-string value)
query (str (name field) "=" (if (= "string" (field-type schema-name field))
query (str (name field) "=" (if (= "string" (name (field-type
schema-name field)))
(str "\"" value "\"")
value))]
query))
@ -125,6 +137,12 @@
(let [q (to-query schema-name :eq field value)]
(.filtered (.objects realm (name schema-name)) q)))
(defn get-by-fields [schema-name fields]
(let [queries (map (fn [[k v]]
(to-query schema-name :eq k v))
fields)]
(.filtered (.objects realm (name schema-name)) (and-q queries))))
(defn get-all [schema-name]
(.objects realm (to-string schema-name)))

View File

@ -4,7 +4,8 @@
(:require [status-im.utils.handlers :as u]
[status-im.utils.logging :as log]
[status-im.protocol.api :as api]
[re-frame.core :refer [register-handler dispatch debug]]
[re-frame.core :refer [dispatch debug]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.models.contacts :as contacts]
[status-im.protocol.api :refer [init-protocol]]
[status-im.protocol.protocol-handler :refer [make-handler]]

View File

@ -1,5 +1,6 @@
(ns status-im.qr-scanner.handlers
(:require [re-frame.core :refer [register-handler after dispatch debug enrich]]
(:require [re-frame.core :refer [after dispatch debug enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.navigation.handlers :as nav]
[status-im.utils.handlers :as u]))

View File

@ -1,4 +1,5 @@
(ns status-im.utils.handlers)
(ns status-im.utils.handlers
(:require [re-frame.core :refer [after dispatch debug] :as re-core]))
(defn side-effect!
"Middleware for handlers that will not affect db."
@ -6,3 +7,8 @@
(fn [db params]
(handler db params)
db))
(defn register-handler
([name handler] (register-handler name nil handler))
([name middleware handler]
(re-core/register-handler name [#_debug middleware] handler)))