After Width: | Height: | Size: 253 B |
After Width: | Height: | Size: 776 B |
After Width: | Height: | Size: 151 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 481 B |
After Width: | Height: | Size: 120 B |
After Width: | Height: | Size: 329 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 145 B |
After Width: | Height: | Size: 401 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 187 B |
After Width: | Height: | Size: 546 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 223 B |
|
@ -3,6 +3,7 @@
|
|||
[status-im.models.commands :as commands]
|
||||
[clojure.string :as str]
|
||||
[status-im.components.styles :refer [default-chat-color]]
|
||||
[status-im.chat.styles.response :refer [request-info-height response-height-normal]]
|
||||
[status-im.chat.suggestions :as suggestions]
|
||||
[status-im.protocol.api :as api]
|
||||
[status-im.models.messages :as messages]
|
||||
|
@ -15,8 +16,13 @@
|
|||
[status-im.utils.handlers :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.utils.datetime :as time]
|
||||
[status-im.chat.handlers.animation :refer [update-response-height
|
||||
get-response-height]]))
|
||||
|
||||
(def delta 1)
|
||||
|
||||
(register-handler :set-show-actions
|
||||
(fn [db [_ show-actions]]
|
||||
|
@ -41,9 +47,22 @@
|
|||
(assoc-in [:chats current-chat-id :command-input] {})
|
||||
(update-in [:chats current-chat-id :input-text] safe-trim))))
|
||||
|
||||
(register-handler :start-cancel-command
|
||||
(u/side-effect!
|
||||
(fn [db _]
|
||||
(if (commands/get-chat-command-to-msg-id db)
|
||||
(dispatch [:animate-cancel-command])
|
||||
(dispatch [:cancel-command])))))
|
||||
|
||||
(register-handler :set-chat-command-content
|
||||
(fn [db [_ content]]
|
||||
(commands/set-chat-command-content db content)))
|
||||
(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)
|
||||
(if (commands/get-chat-command-to-msg-id db)
|
||||
(do (dispatch [:animate-response-resize])
|
||||
(update-response-height db))
|
||||
db))))
|
||||
|
||||
(defn update-input-text
|
||||
[{:keys [current-chat-id] :as db} text]
|
||||
|
@ -51,7 +70,7 @@
|
|||
|
||||
(register-handler :stage-command
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(let [db (update-input-text db nil)
|
||||
(let [db (update-input-text db nil)
|
||||
{:keys [command content]}
|
||||
(get-in db [:chats current-chat-id :command-input])
|
||||
command-info {:command command
|
||||
|
@ -59,7 +78,25 @@
|
|||
:handler (:handler command)}]
|
||||
(commands/stage-command db command-info))))
|
||||
|
||||
(register-handler :set-message-input []
|
||||
(fn [db [_ input]]
|
||||
(assoc db :message-input input)))
|
||||
|
||||
(register-handler :prepare-message-input
|
||||
(u/side-effect!
|
||||
(fn [db _]
|
||||
(when-let [message-input (:message-input db)]
|
||||
(.clear message-input)
|
||||
(.focus message-input)))))
|
||||
|
||||
(register-handler :blur-message-input
|
||||
(u/side-effect!
|
||||
(fn [db _]
|
||||
(when-let [message-input (:message-input db)]
|
||||
(.blur message-input)))))
|
||||
|
||||
(register-handler :set-response-chat-command
|
||||
(after #(dispatch [:animate-show-response]))
|
||||
(fn [db [_ to-msg-id command-key]]
|
||||
(commands/set-response-chat-command db to-msg-id command-key)))
|
||||
|
||||
|
@ -68,8 +105,12 @@
|
|||
(update-input-text db text))
|
||||
|
||||
(defn update-command [db [_ text]]
|
||||
(let [{:keys [command]} (suggestions/check-suggestion db text)]
|
||||
(commands/set-chat-command db command)))
|
||||
(if-not (commands/get-chat-command db)
|
||||
(let [{:keys [command]} (suggestions/check-suggestion db text)]
|
||||
(if command
|
||||
(commands/set-chat-command db command)
|
||||
db))
|
||||
db))
|
||||
|
||||
(register-handler :set-chat-input-text
|
||||
((enrich update-command) update-text))
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
(ns status-im.chat.handlers.animation
|
||||
(:require [re-frame.core :refer [register-handler after dispatch]]
|
||||
[re-frame.middleware :refer [path]]
|
||||
[status-im.models.commands :as commands]
|
||||
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
|
||||
[status-im.chat.styles.message-input :refer [input-height]]
|
||||
[status-im.chat.styles.response :refer [request-info-height response-height-normal]]
|
||||
[status-im.chat.styles.response-suggestions :as response-suggestions-styles]
|
||||
[status-im.constants :refer [response-input-hiding-duration]]))
|
||||
|
||||
(def zero-height input-height)
|
||||
|
||||
(register-handler :finish-animate-cancel-command
|
||||
(fn [db _]
|
||||
(assoc-in db [:animations :commands-input-is-switching?] false)))
|
||||
|
||||
(register-handler :animate-cancel-command
|
||||
(path :animations)
|
||||
(fn [db _]
|
||||
(if-not (:commands-input-is-switching? db)
|
||||
(assoc db
|
||||
:commands-input-is-switching? true
|
||||
:message-input-buttons-scale 1
|
||||
:message-input-offset 0
|
||||
:to-response-height zero-height
|
||||
:messages-offset 0)
|
||||
db)))
|
||||
|
||||
(register-handler :finish-animate-response-resize
|
||||
(fn [db _]
|
||||
(let [fixed (get-in db [:animations :to-response-height])]
|
||||
(-> db
|
||||
(assoc-in [:animations :response-height-current] fixed)
|
||||
(assoc-in [:animations :response-resize?] false)))))
|
||||
|
||||
(register-handler :set-response-height
|
||||
(fn [db [_ value]]
|
||||
(assoc-in db [:animations :response-height-current] value)))
|
||||
|
||||
(register-handler :animate-response-resize
|
||||
(fn [db _]
|
||||
(assoc-in db [:animations :response-resize?] true)))
|
||||
|
||||
(defn get-response-height [db]
|
||||
(let [command (commands/get-chat-command db)
|
||||
text (commands/get-chat-command-content db)
|
||||
suggestions (get-content-suggestions command text)
|
||||
suggestions-height (reduce + 0 (map #(if (:header %)
|
||||
response-suggestions-styles/header-height
|
||||
response-suggestions-styles/suggestion-height)
|
||||
suggestions))]
|
||||
(+ zero-height
|
||||
(min response-height-normal (+ suggestions-height request-info-height)))))
|
||||
|
||||
(defn update-response-height [db]
|
||||
(assoc-in db [:animations :to-response-height] (get-response-height db)))
|
||||
|
||||
(register-handler :finish-show-response
|
||||
(after #(dispatch [:prepare-message-input]))
|
||||
(fn [db _]
|
||||
(assoc-in db [:animations :commands-input-is-switching?] false)))
|
||||
|
||||
(register-handler :animate-show-response
|
||||
(after #(dispatch [:animate-response-resize]))
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(assoc-in [:animations :commands-input-is-switching?] true)
|
||||
(assoc-in [:animations :response-height-current] zero-height)
|
||||
(assoc-in [:animations :message-input-buttons-scale] 0.1)
|
||||
(assoc-in [:animations :message-input-offset] -40)
|
||||
(assoc-in [:animations :messages-offset] request-info-height)
|
||||
(update-response-height))))
|
||||
|
||||
(register-handler :set-response-max-height
|
||||
(fn [db [_ height]]
|
||||
(let [prev-height (get-in db [:animations :response-height-max])]
|
||||
(if (not= height prev-height)
|
||||
(let [db (assoc-in db [:animations :response-height-max] height)]
|
||||
(if (= prev-height (get-in db [:animations :to-response-height]))
|
||||
(-> db
|
||||
(assoc-in [:animations :to-response-height] height)
|
||||
(assoc-in [:animations :response-height-current] height))
|
||||
db))
|
||||
db))))
|
||||
|
||||
(register-handler :on-drag-response
|
||||
(fn [db [_ dy]]
|
||||
(let [fixed (get-in db [:animations :to-response-height])]
|
||||
(-> db
|
||||
(assoc-in [:animations :response-height-current] (- fixed dy))
|
||||
(assoc-in [:animations :response-resize?] false)))))
|
||||
|
||||
(register-handler :fix-response-height
|
||||
(fn [db _]
|
||||
(if (and (commands/get-chat-command-to-msg-id db)
|
||||
(not (get-in db [:animations :commands-input-is-switching?])))
|
||||
(let [current (get-in db [:animations :response-height-current])
|
||||
normal-height response-height-normal
|
||||
command (commands/get-chat-command db)
|
||||
text (commands/get-chat-command-content db)
|
||||
suggestions (get-content-suggestions command text)
|
||||
max-height (get-in db [:animations :response-height-max])
|
||||
delta (/ normal-height 2)
|
||||
new-fixed (cond
|
||||
(or (<= current (+ zero-height delta))
|
||||
(empty? suggestions)) (+ zero-height request-info-height)
|
||||
(<= current (+ zero-height normal-height delta)) (get-response-height db)
|
||||
:else max-height)]
|
||||
(dispatch [:animate-response-resize])
|
||||
(assoc-in db [:animations :to-response-height] new-fixed))
|
||||
db)))
|
|
@ -3,6 +3,7 @@
|
|||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[clojure.string :as s]
|
||||
[status-im.components.react :refer [view
|
||||
animated-view
|
||||
text
|
||||
image
|
||||
icon
|
||||
|
@ -17,8 +18,13 @@
|
|||
[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.content-suggestions :refer [content-suggestions-view]]
|
||||
[status-im.chat.views.suggestions :refer [suggestions-view]]
|
||||
[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]]))
|
||||
[status-im.i18n :refer [label label-pluralize]]
|
||||
[status-im.components.animation :as anim]
|
||||
[reagent.core :as r]))
|
||||
|
||||
|
||||
(defn contacts-by-identity [contacts]
|
||||
|
@ -213,21 +219,58 @@
|
|||
: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)
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:enableEmptySections true
|
||||
:dataSource (to-datasource messages)}]))
|
||||
[messages [:chat :messages]
|
||||
contacts [:chat :contacts]]
|
||||
(let [contacts' (contacts-by-identity contacts)]
|
||||
[list-view {:renderRow (message-row contacts' group-chat)
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:enableEmptySections true
|
||||
:keyboardShouldPersistTaps true
|
||||
:dataSource (to-datasource messages)}]))
|
||||
|
||||
(defn messages-container-animation-logic [{:keys [to-value val]}]
|
||||
(fn [_]
|
||||
(let [to-value @to-value]
|
||||
(anim/start (anim/spring val {:toValue to-value})
|
||||
(fn [arg]
|
||||
(when (.-finished arg)
|
||||
(dispatch [:set-in [:animations ::messages-offset-current] to-value])))))))
|
||||
|
||||
(defn messages-container [messages]
|
||||
(let [to-messages-offset (subscribe [:get-in [:animations :messages-offset]])
|
||||
cur-messages-offset (subscribe [:get-in [:animations ::messages-offset-current]])
|
||||
messages-offset (anim/create-value (or @cur-messages-offset 0))
|
||||
context {:to-value to-messages-offset
|
||||
:val messages-offset}
|
||||
on-update (messages-container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn [messages]
|
||||
@to-messages-offset
|
||||
[animated-view {:style (st/messages-container messages-offset)}
|
||||
messages])})))
|
||||
|
||||
(defview chat []
|
||||
[group-chat [:chat :group-chat]
|
||||
show-actions-atom [:show-actions]]
|
||||
[view st/chat-view
|
||||
show-actions-atom [:show-actions]
|
||||
command [:get-chat-command]
|
||||
to-msg-id [:get-chat-command-to-msg-id]]
|
||||
[view {:style st/chat-view
|
||||
:onLayout (fn [event]
|
||||
(let [height (.. event -nativeEvent -layout -height)]
|
||||
(dispatch [:set-response-max-height height])))}
|
||||
[chat-toolbar]
|
||||
[messages-view group-chat]
|
||||
[messages-container
|
||||
[messages-view group-chat]]
|
||||
(when group-chat [typing-all])
|
||||
(cond
|
||||
(and command to-msg-id) [response-view]
|
||||
command [content-suggestions-view]
|
||||
:else [suggestions-view])
|
||||
[chat-message-new]
|
||||
(when show-actions-atom [actions-view])])
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
:backgroundColor color-white
|
||||
:borderRadius 5})
|
||||
|
||||
(def container
|
||||
{:backgroundColor color-white})
|
||||
|
||||
(def drag-down-touchable
|
||||
{:height 22
|
||||
:alignItems :center
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
(def command-input
|
||||
{:flex 1
|
||||
:marginLeft 8
|
||||
:marginTop 7
|
||||
:marginTop -2
|
||||
:padding 0
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text1-color})
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
(ns status-im.chat.styles.message-input
|
||||
(:require [status-im.components.styles :refer [color-white
|
||||
color-blue]]))
|
||||
|
||||
(def input-height 56)
|
||||
|
||||
(defn message-input-container [offset]
|
||||
{:flex 1
|
||||
:transform [{:translateX offset}]
|
||||
:marginRight offset})
|
||||
|
||||
(def input-container
|
||||
{:flexDirection :column})
|
||||
|
||||
(def input-view
|
||||
{:flexDirection :row
|
||||
:height input-height
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def send-icon
|
||||
{:marginTop 10.5
|
||||
:marginLeft 12
|
||||
:width 15
|
||||
:height 15})
|
||||
|
||||
(def send-container
|
||||
{:marginTop 10
|
||||
:marginRight 10
|
||||
:width 36
|
||||
:height 36
|
||||
:borderRadius 50
|
||||
:backgroundColor color-blue})
|
|
@ -1,55 +0,0 @@
|
|||
(ns status-im.chat.styles.plain-input
|
||||
(:require [status-im.components.styles :refer [font
|
||||
text2-color
|
||||
color-white
|
||||
color-blue]]))
|
||||
|
||||
(def input-container
|
||||
{:flexDirection :column})
|
||||
|
||||
(def input-view
|
||||
{:flexDirection :row
|
||||
:height 56
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def switch-commands-touchable
|
||||
{:width 56
|
||||
:height 56
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def list-icon
|
||||
{:width 13
|
||||
:height 12})
|
||||
|
||||
(def close-icon
|
||||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def message-input
|
||||
{:flex 1
|
||||
:marginTop -2
|
||||
:padding 0
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text2-color})
|
||||
|
||||
(def smile-icon
|
||||
{:marginTop 18
|
||||
:marginRight 18
|
||||
:width 20
|
||||
:height 20})
|
||||
|
||||
(def send-icon
|
||||
{:marginTop 10.5
|
||||
:marginLeft 12
|
||||
:width 15
|
||||
:height 15})
|
||||
|
||||
(def send-container
|
||||
{:marginTop 10
|
||||
:marginRight 10
|
||||
:width 36
|
||||
:height 36
|
||||
:borderRadius 50
|
||||
:backgroundColor color-blue})
|
|
@ -0,0 +1,32 @@
|
|||
(ns status-im.chat.styles.plain-message
|
||||
(:require [status-im.components.styles :refer [font
|
||||
text2-color]]))
|
||||
|
||||
(def message-input-button-touchable
|
||||
{:width 56
|
||||
:height 56
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(defn message-input-button [scale]
|
||||
{:transform [{:scale scale}]})
|
||||
|
||||
(def list-icon
|
||||
{:width 13
|
||||
:height 12})
|
||||
|
||||
(def close-icon
|
||||
{:width 12
|
||||
:height 12})
|
||||
|
||||
(def message-input
|
||||
{:flex 1
|
||||
:marginTop -2
|
||||
:padding 0
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text2-color})
|
||||
|
||||
(def smile-icon
|
||||
{:width 20
|
||||
:height 20})
|
|
@ -0,0 +1,96 @@
|
|||
(ns status-im.chat.styles.response
|
||||
(:require [status-im.components.styles :refer [font
|
||||
color-white
|
||||
color-blue
|
||||
text1-color
|
||||
text2-color
|
||||
chat-background
|
||||
color-black]]
|
||||
[status-im.chat.styles.message-input :refer [input-height]]))
|
||||
|
||||
(def response-height-normal 211)
|
||||
(def request-info-height 61)
|
||||
|
||||
(def drag-container
|
||||
{:height 16
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def drag-icon
|
||||
{:width 14
|
||||
:height 3})
|
||||
|
||||
(def command-icon-container
|
||||
{:marginTop 1
|
||||
:marginLeft 12
|
||||
:width 32
|
||||
:height 32
|
||||
:alignItems :center
|
||||
:justifyContent :center
|
||||
:borderRadius 50
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def command-icon
|
||||
{:width 9
|
||||
:height 15})
|
||||
|
||||
(def info-container
|
||||
{:flex 1
|
||||
:marginLeft 12})
|
||||
|
||||
(def command-name
|
||||
{:marginTop 0
|
||||
:fontSize 12
|
||||
:fontFamily font
|
||||
:color color-white})
|
||||
|
||||
(def message-info
|
||||
{:marginTop 1
|
||||
:fontSize 12
|
||||
:fontFamily font
|
||||
:opacity 0.69
|
||||
:color color-white})
|
||||
|
||||
(defn response-view [height]
|
||||
{:flexDirection :column
|
||||
:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:height height
|
||||
:backgroundColor color-white
|
||||
:elevation 2})
|
||||
|
||||
(def input-placeholder
|
||||
{:height input-height})
|
||||
|
||||
(defn request-info [color]
|
||||
{:flexDirection :column
|
||||
:height request-info-height
|
||||
:backgroundColor color})
|
||||
|
||||
(def inner-container
|
||||
{:flexDirection :row
|
||||
:height 45})
|
||||
|
||||
(def cancel-container
|
||||
{:marginTop 2.5
|
||||
:marginRight 16
|
||||
:width 24
|
||||
:height 24})
|
||||
|
||||
(def cancel-icon
|
||||
{:marginTop 6
|
||||
:marginLeft 6
|
||||
:width 12
|
||||
:height 12})
|
||||
|
||||
(def command-input
|
||||
{:flex 1
|
||||
:marginLeft 56
|
||||
:marginRight 16
|
||||
:marginTop -2
|
||||
:padding 0
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text1-color})
|
|
@ -0,0 +1,59 @@
|
|||
(ns status-im.chat.styles.response-suggestions
|
||||
(:require [status-im.components.styles :refer [font
|
||||
font-medium
|
||||
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]]))
|
||||
|
||||
(def header-height 50)
|
||||
(def suggestion-height 56)
|
||||
|
||||
(def header-container
|
||||
{:paddingLeft 16
|
||||
:height header-height
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def header-text
|
||||
{:marginTop 18
|
||||
:fontSize 13
|
||||
:fontFamily font-medium
|
||||
:color text2-color})
|
||||
|
||||
(def suggestion-container
|
||||
{:flexDirection :column
|
||||
:paddingLeft 16
|
||||
:height suggestion-height
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def suggestion-sub-container
|
||||
{:height suggestion-height
|
||||
:borderBottomWidth 1
|
||||
:borderBottomColor separator-color})
|
||||
|
||||
(def value-text
|
||||
{:marginTop 10
|
||||
:fontSize 12
|
||||
:fontFamily font
|
||||
:color text1-color})
|
||||
|
||||
(def description-text
|
||||
{:marginTop 2
|
||||
:fontSize 12
|
||||
:fontFamily font
|
||||
:color text2-color})
|
||||
|
||||
(def suggestions-container
|
||||
{:flexDirection :row
|
||||
:flex 1
|
||||
:marginVertical 1
|
||||
:marginHorizontal 0
|
||||
:backgroundColor color-white
|
||||
:borderRadius 5})
|
|
@ -14,6 +14,10 @@
|
|||
{:flex 1
|
||||
:backgroundColor chat-background})
|
||||
|
||||
(defn messages-container [bottom]
|
||||
{:flex 1
|
||||
:bottom bottom})
|
||||
|
||||
(def toolbar-view
|
||||
{:flexDirection :row
|
||||
:height 56
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
:backgroundColor color-white
|
||||
:borderRadius 5})
|
||||
|
||||
(def container
|
||||
{:backgroundColor color-white})
|
||||
|
||||
(def drag-down-touchable
|
||||
{:height 22
|
||||
:alignItems :center
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
(ns status-im.chat.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]
|
||||
(:require [re-frame.core :refer [register-sub dispatch]]
|
||||
[status-im.db :as db]
|
||||
;todo handlers in subs?...
|
||||
[status-im.chat.suggestions :refer
|
||||
[get-suggestions typing-command? get-content-suggestions]]
|
||||
[get-suggestions typing-command?]]
|
||||
[status-im.models.commands :as commands]
|
||||
[status-im.constants :refer [response-suggesstion-resize-duration]]
|
||||
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]))
|
||||
|
||||
(register-sub :chat-properties
|
||||
|
@ -70,6 +71,10 @@
|
|||
(fn [db _]
|
||||
(reaction (commands/get-chat-command-content @db))))
|
||||
|
||||
(register-sub :get-chat-command-to-msg-id
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command-to-msg-id @db))))
|
||||
|
||||
(register-sub :chat-command-request
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command-request @db))))
|
||||
|
@ -90,5 +95,5 @@
|
|||
(register-sub :get-content-suggestions
|
||||
(fn [db _]
|
||||
(let [command (reaction (commands/get-chat-command @db))
|
||||
text (reaction (commands/get-chat-command-content @db))]
|
||||
(reaction (get-content-suggestions @db @command @text)))))
|
||||
text (reaction (commands/get-chat-command-content @db))]
|
||||
(reaction (get-content-suggestions @command @text)))))
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
(ns status-im.chat.views.command
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
icon
|
||||
text
|
||||
text-input
|
||||
touchable-highlight]]
|
||||
[status-im.chat.views.content-suggestions :refer
|
||||
[content-suggestions-view]]
|
||||
icon
|
||||
text
|
||||
text-input
|
||||
touchable-highlight]]
|
||||
[status-im.chat.styles.input :as st]))
|
||||
|
||||
(defn cancel-command-input []
|
||||
(dispatch [:cancel-command]))
|
||||
(dispatch [:start-cancel-command]))
|
||||
|
||||
(defn set-input-message [message]
|
||||
(dispatch [:set-chat-command-content message]))
|
||||
|
@ -24,28 +23,17 @@
|
|||
(validator message)
|
||||
(pos? (count message))))
|
||||
|
||||
(defn simple-command-input-view [command input-options & {:keys [validator]}]
|
||||
(let [message-atom (subscribe [:get-chat-command-content])]
|
||||
(fn [command input-options & {:keys [validator]}]
|
||||
(let [message @message-atom]
|
||||
[view st/command-input-and-suggestions-container
|
||||
[content-suggestions-view]
|
||||
[view st/command-input-container
|
||||
[view (st/command-text-container command)
|
||||
[text {:style st/command-text} (:text command)]]
|
||||
[text-input (merge {:style st/command-input
|
||||
:autoFocus true
|
||||
:onChangeText set-input-message
|
||||
:onSubmitEditing (fn []
|
||||
(when (valid? message validator)
|
||||
(send-command)))
|
||||
:accessibility-label :command-input}
|
||||
input-options)
|
||||
message]
|
||||
(if (valid? message validator)
|
||||
[touchable-highlight {:on-press send-command
|
||||
:accessibility-label :stage-command}
|
||||
[view st/send-container [icon :send st/send-icon]]]
|
||||
[touchable-highlight {:on-press cancel-command-input}
|
||||
[view st/cancel-container
|
||||
[icon :close-gray st/cancel-icon]]])]]))))
|
||||
(defn try-send [message validator]
|
||||
(when (valid? message validator)
|
||||
(send-command)))
|
||||
|
||||
(defn command-icon [command]
|
||||
[view (st/command-text-container command)
|
||||
[text {:style st/command-text} (:text command)]])
|
||||
|
||||
(defview cancel-button []
|
||||
[commands-input-is-switching? [:get-in [:animations :commands-input-is-switching?]]]
|
||||
[touchable-highlight {:disabled commands-input-is-switching?
|
||||
:on-press cancel-command-input}
|
||||
[view st/cancel-container
|
||||
[icon :close-gray st/cancel-icon]]])
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
(ns status-im.chat.views.confirmation-code
|
||||
(:require
|
||||
[status-im.chat.views.command :refer [simple-command-input-view]]))
|
||||
|
||||
(defn confirmation-code-input-view [command]
|
||||
[simple-command-input-view command {:keyboardType :numeric}])
|
|
@ -2,11 +2,11 @@
|
|||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
icon
|
||||
text
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
icon
|
||||
text
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.chat.styles.content-suggestions :as st]
|
||||
[status-im.utils.listview :refer [to-datasource]]))
|
||||
|
||||
|
@ -25,12 +25,13 @@
|
|||
|
||||
(defview content-suggestions-view []
|
||||
[suggestions [:get-content-suggestions]]
|
||||
(when (seq suggestions)
|
||||
[view
|
||||
(when-let [values (not-empty (filter :value suggestions))]
|
||||
[view st/container
|
||||
[touchable-highlight {:style st/drag-down-touchable
|
||||
;; TODO hide suggestions?
|
||||
:onPress (fn [])}
|
||||
[view [icon :drag_down st/drag-down-icon]]]
|
||||
[view (st/suggestions-container (count suggestions))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:renderRow render-row}]]]))
|
||||
[view (st/suggestions-container (count values))
|
||||
[list-view {:dataSource (to-datasource values)
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-row}]]]))
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
(ns status-im.chat.views.message-input
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.components.react :refer [view
|
||||
animated-view
|
||||
icon
|
||||
touchable-highlight
|
||||
text-input
|
||||
dismiss-keyboard!]]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.chat.views.plain-message :as plain-message]
|
||||
[status-im.chat.views.command :as command]
|
||||
[status-im.chat.views.response :as response]
|
||||
[status-im.chat.styles.message-input :as st]
|
||||
[status-im.chat.styles.plain-message :as st-message]
|
||||
[status-im.chat.styles.input :as st-command]
|
||||
[status-im.chat.styles.response :as st-response]
|
||||
[status-im.constants :refer [response-input-hiding-duration]]))
|
||||
|
||||
(defview send-button [{:keys [on-press accessibility-label]}]
|
||||
[commands-input-is-switching? [:get-in [:animations :commands-input-is-switching?]]]
|
||||
[touchable-highlight {:disabled commands-input-is-switching?
|
||||
:on-press on-press
|
||||
:accessibility-label accessibility-label}
|
||||
[view st/send-container
|
||||
[icon :send st/send-icon]]])
|
||||
|
||||
(defn message-input-container-animation-logic [{:keys [to-value val]}]
|
||||
(fn [_]
|
||||
(let [to-value @to-value]
|
||||
(anim/start (anim/timing val {:toValue to-value
|
||||
:duration response-input-hiding-duration})
|
||||
(fn [arg]
|
||||
(when (.-finished arg)
|
||||
(dispatch [:set-in [:animations ::message-input-offset-current] to-value])))))))
|
||||
|
||||
(defn message-input-container [input]
|
||||
(let [to-message-input-offset (subscribe [:get-in [:animations :message-input-offset]])
|
||||
cur-message-input-offset (subscribe [:get-in [:animations ::message-input-offset-current]])
|
||||
message-input-offset (anim/create-value (or @cur-message-input-offset 0))
|
||||
context {:to-value to-message-input-offset
|
||||
:val message-input-offset}
|
||||
on-update (message-input-container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn [input]
|
||||
@to-message-input-offset
|
||||
[animated-view {:style (st/message-input-container message-input-offset)}
|
||||
input])})))
|
||||
|
||||
(defview message-input [input-options validator]
|
||||
[input-message [:get-chat-input-text]
|
||||
command [:get-chat-command]
|
||||
to-msg-id [:get-chat-command-to-msg-id]
|
||||
input-command [:get-chat-command-content]
|
||||
staged-commands [:get-chat-staged-commands]
|
||||
typing-command? [:typing-command?]
|
||||
commands-input-is-switching? [:get-in [:animations :commands-input-is-switching?]]]
|
||||
(let [dismiss-keyboard (not (or command typing-command?))
|
||||
response? (and command to-msg-id)
|
||||
message-input? (or (not command) commands-input-is-switching?)
|
||||
animation? commands-input-is-switching?]
|
||||
[text-input (merge {:style (cond
|
||||
message-input? st-message/message-input
|
||||
response? st-response/command-input
|
||||
command st-command/command-input)
|
||||
:ref (fn [input]
|
||||
(dispatch [:set-message-input input]))
|
||||
:autoFocus false
|
||||
:blurOnSubmit dismiss-keyboard
|
||||
:onChangeText (fn [text]
|
||||
(when-not animation?
|
||||
((if message-input?
|
||||
plain-message/set-input-message
|
||||
command/set-input-message)
|
||||
text)))
|
||||
:onSubmitEditing #(when-not animation?
|
||||
(if message-input?
|
||||
(plain-message/try-send staged-commands
|
||||
input-message
|
||||
dismiss-keyboard)
|
||||
(command/try-send input-command validator)))}
|
||||
(when command
|
||||
{:accessibility-label :command-input})
|
||||
input-options)
|
||||
(if message-input?
|
||||
input-message
|
||||
input-command)]))
|
||||
|
||||
(defview plain-message-input-view [{:keys [input-options validator]}]
|
||||
[input-message [:get-chat-input-text]
|
||||
command [:get-chat-command]
|
||||
to-msg-id [:get-chat-command-to-msg-id]
|
||||
input-command [:get-chat-command-content]
|
||||
staged-commands [:get-chat-staged-commands]
|
||||
typing-command? [:typing-command?]
|
||||
commands-input-is-switching? [:get-in [:animations :commands-input-is-switching?]]]
|
||||
(let [dismiss-keyboard (not (or command typing-command?))
|
||||
response? (and command to-msg-id)
|
||||
message-input? (or (not command) commands-input-is-switching?)]
|
||||
[view st/input-container
|
||||
[view st/input-view
|
||||
(if message-input?
|
||||
[plain-message/commands-button]
|
||||
(when (and command (not response?))
|
||||
[command/command-icon command response?]))
|
||||
[message-input-container
|
||||
[message-input input-options validator]]
|
||||
;; TODO emoticons: not implemented
|
||||
(when message-input?
|
||||
[plain-message/smile-button])
|
||||
(if message-input?
|
||||
(when (plain-message/message-valid? staged-commands input-message)
|
||||
[send-button {:on-press #(plain-message/try-send staged-commands
|
||||
input-message
|
||||
dismiss-keyboard)
|
||||
:accessibility-label :send-message}])
|
||||
(if (command/valid? input-command validator)
|
||||
[send-button {:on-press command/send-command
|
||||
:accessibility-label :stage-command}]
|
||||
(when-not response?
|
||||
[command/cancel-button])))]]))
|
|
@ -1,7 +0,0 @@
|
|||
(ns status-im.chat.views.money
|
||||
(:require
|
||||
[status-im.chat.views.command :refer [simple-command-input-view]]))
|
||||
|
||||
(defn money-input-view [command]
|
||||
[simple-command-input-view command
|
||||
{:keyboardType :numeric}])
|
|
@ -1,14 +1,11 @@
|
|||
(ns status-im.chat.views.new-message
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[status-im.components.react :refer [view]]
|
||||
[status-im.chat.views.plain-input :refer [plain-message-input-view]]
|
||||
[status-im.chat.views.command :refer [simple-command-input-view]]
|
||||
[status-im.chat.views.phone :refer [phone-input-view]]
|
||||
[status-im.chat.views.password :refer [password-input-view]]
|
||||
[status-im.chat.views.confirmation-code :refer [confirmation-code-input-view]]
|
||||
[status-im.chat.views.money :refer [money-input-view]]
|
||||
[status-im.chat.views.message-input :refer [plain-message-input-view]]
|
||||
[status-im.chat.views.staged-command :refer [simple-command-staged-view]]
|
||||
[status-im.utils.phone-number :refer [valid-mobile-number?]]
|
||||
[status-im.chat.styles.message :as st]))
|
||||
|
||||
(defn staged-command-view [stage-command]
|
||||
|
@ -19,27 +16,24 @@
|
|||
(for [command staged-commands]
|
||||
^{:key command} [staged-command-view command])])
|
||||
|
||||
(defn default-command-input-view [command]
|
||||
[simple-command-input-view command {}])
|
||||
|
||||
(defn special-input-view [command]
|
||||
(case (:command command)
|
||||
:phone [phone-input-view command]
|
||||
:keypair-password [password-input-view command]
|
||||
:confirmation-code [confirmation-code-input-view command]
|
||||
:money [money-input-view command]
|
||||
:request [money-input-view command]
|
||||
[default-command-input-view command]))
|
||||
(defn show-input [command]
|
||||
[plain-message-input-view
|
||||
(when command
|
||||
(case (:command command)
|
||||
:phone {:input-options {:keyboardType :phone-pad}
|
||||
:validator valid-mobile-number?}
|
||||
:keypair-password {:input-options {:secureTextEntry true}}
|
||||
:confirmation-code {:input-options {:keyboardType :numeric}}
|
||||
:money {:input-options {:keyboardType :numeric}}
|
||||
:request {:input-options {:keyboardType :numeric}}
|
||||
(throw (js/Error. "Uknown command type"))))])
|
||||
|
||||
(defn chat-message-new []
|
||||
(let [command-atom (subscribe [:get-chat-command])
|
||||
(let [command-atom (subscribe [:get-chat-command])
|
||||
staged-commands-atom (subscribe [:get-chat-staged-commands])]
|
||||
(fn []
|
||||
(let [command @command-atom
|
||||
staged-commands @staged-commands-atom]
|
||||
(let [staged-commands @staged-commands-atom]
|
||||
[view st/new-message-container
|
||||
(when (and staged-commands (pos? (count staged-commands)))
|
||||
[staged-commands-view staged-commands])
|
||||
(if command
|
||||
[special-input-view command]
|
||||
[plain-message-input-view])]))))
|
||||
[show-input @command-atom]]))))
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
(ns status-im.chat.views.password
|
||||
(:require
|
||||
[status-im.chat.views.command
|
||||
:refer [simple-command-input-view]]))
|
||||
|
||||
(defn password-input-view [command]
|
||||
[simple-command-input-view command {:secureTextEntry true}])
|
|
@ -1,9 +0,0 @@
|
|||
(ns status-im.chat.views.phone
|
||||
(:require
|
||||
[status-im.chat.views.command
|
||||
:refer [simple-command-input-view]]
|
||||
[status-im.utils.phone-number :refer [valid-mobile-number?]]))
|
||||
|
||||
(defn phone-input-view [command]
|
||||
[simple-command-input-view command {:keyboardType :phone-pad}
|
||||
:validator valid-mobile-number?])
|
|
@ -1,54 +0,0 @@
|
|||
(ns status-im.chat.views.plain-input
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
icon
|
||||
touchable-highlight
|
||||
text-input]]
|
||||
[status-im.chat.views.suggestions :refer [suggestions-view]]
|
||||
[status-im.chat.styles.plain-input :as st]))
|
||||
|
||||
(defn set-input-message [message]
|
||||
(dispatch [:set-chat-input-text message]))
|
||||
|
||||
(defn send [chat input-message]
|
||||
(let [{:keys [group-chat chat-id]} chat]
|
||||
(dispatch [:send-chat-msg])))
|
||||
|
||||
(defn message-valid? [staged-commands message]
|
||||
(or (and (pos? (count message))
|
||||
(not= "!" message))
|
||||
(pos? (count staged-commands))))
|
||||
|
||||
(defn try-send [chat staged-commands message]
|
||||
(when (message-valid? staged-commands message)
|
||||
(send chat message)))
|
||||
|
||||
(defn plain-message-input-view []
|
||||
(let [chat (subscribe [:get-current-chat])
|
||||
input-message-atom (subscribe [:get-chat-input-text])
|
||||
staged-commands-atom (subscribe [:get-chat-staged-commands])
|
||||
typing-command? (subscribe [:typing-command?])]
|
||||
(fn []
|
||||
(let [input-message @input-message-atom]
|
||||
[view st/input-container
|
||||
[suggestions-view]
|
||||
[view st/input-view
|
||||
[touchable-highlight {:on-press #(dispatch [:switch-command-suggestions])
|
||||
:style st/switch-commands-touchable}
|
||||
[view nil
|
||||
(if @typing-command?
|
||||
[icon :close-gray st/close-icon]
|
||||
[icon :list st/list-icon])]]
|
||||
[text-input {:style st/message-input
|
||||
:autoFocus (pos? (count @staged-commands-atom))
|
||||
:onChangeText set-input-message
|
||||
:onSubmitEditing #(try-send @chat @staged-commands-atom
|
||||
input-message)}
|
||||
input-message]
|
||||
;; TODO emoticons: not implemented
|
||||
[icon :smile st/smile-icon]
|
||||
(when (message-valid? @staged-commands-atom input-message)
|
||||
[touchable-highlight {:on-press #(send @chat input-message)
|
||||
:accessibility-label :send-message}
|
||||
[view st/send-container
|
||||
[icon :send st/send-icon]]])]]))))
|
|
@ -0,0 +1,94 @@
|
|||
(ns status-im.chat.views.plain-message
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.components.react :refer [view
|
||||
animated-view
|
||||
icon
|
||||
touchable-highlight
|
||||
dismiss-keyboard!]]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.chat.styles.plain-message :as st]
|
||||
[status-im.constants :refer [response-input-hiding-duration]]))
|
||||
|
||||
(defn set-input-message [message]
|
||||
(dispatch [:set-chat-input-text message]))
|
||||
|
||||
(defn send [dismiss-keyboard]
|
||||
(when dismiss-keyboard
|
||||
(dismiss-keyboard!))
|
||||
(dispatch [:send-chat-msg]))
|
||||
|
||||
(defn message-valid? [staged-commands message]
|
||||
(or (and (pos? (count message))
|
||||
(not= "!" message))
|
||||
(pos? (count staged-commands))))
|
||||
|
||||
(defn try-send [staged-commands message dismiss-keyboard]
|
||||
(when (message-valid? staged-commands message)
|
||||
(send dismiss-keyboard)))
|
||||
|
||||
(defn commands-button-animation-logic [{:keys [to-value val]}]
|
||||
(fn [_]
|
||||
(let [to-scale @to-value
|
||||
minimum 0.1
|
||||
scale (cond (< 1 to-scale) 1
|
||||
(< to-scale minimum) minimum
|
||||
:else to-scale)]
|
||||
(anim/start (anim/timing val {:toValue scale
|
||||
:duration response-input-hiding-duration})
|
||||
(fn [arg]
|
||||
(when (.-finished arg)
|
||||
(dispatch [:set-in [:animations ::message-input-buttons-scale-current] scale])
|
||||
(when (= to-scale minimum)
|
||||
(dispatch [:finish-show-response]))))))))
|
||||
|
||||
(defn commands-button []
|
||||
(let [typing-command? (subscribe [:typing-command?])
|
||||
animation? (subscribe [:get-in [:animations :commands-input-is-switching?]])
|
||||
to-scale (subscribe [:get-in [:animations :message-input-buttons-scale]])
|
||||
cur-scale (subscribe [:get-in [:animations ::message-input-buttons-scale-current]])
|
||||
buttons-scale (anim/create-value (or @cur-scale 1))
|
||||
context {:to-value to-scale
|
||||
:val buttons-scale}
|
||||
on-update (commands-button-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn []
|
||||
(let [typing-command? @typing-command?]
|
||||
@to-scale
|
||||
[touchable-highlight {:disabled @animation?
|
||||
:on-press #(dispatch [:switch-command-suggestions])
|
||||
:style st/message-input-button-touchable}
|
||||
[animated-view {:style (st/message-input-button buttons-scale)}
|
||||
(if typing-command?
|
||||
[icon :close-gray st/close-icon]
|
||||
[icon :list st/list-icon])]]))})))
|
||||
|
||||
(defn smile-button []
|
||||
(let [animation? (subscribe [:get-in [:animations :commands-input-is-switching?]])
|
||||
to-scale (subscribe [:get-in [:animations :message-input-buttons-scale]])
|
||||
cur-scale (subscribe [:get-in [:animations ::message-input-buttons-scale-current]])
|
||||
buttons-scale (anim/create-value (or @cur-scale 1))
|
||||
context {:to-value to-scale
|
||||
:val buttons-scale}
|
||||
on-update (commands-button-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn []
|
||||
@to-scale
|
||||
[touchable-highlight {:disabled @animation?
|
||||
:on-press (fn []
|
||||
;; TODO emoticons: not implemented
|
||||
)
|
||||
:style st/message-input-button-touchable}
|
||||
[animated-view {:style (st/message-input-button buttons-scale)}
|
||||
[icon :smile st/smile-icon]]])})))
|
|
@ -0,0 +1,99 @@
|
|||
(ns status-im.chat.views.response
|
||||
(:require-macros [reagent.ratom :refer [reaction]]
|
||||
[status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[reagent.core :as r]
|
||||
[status-im.components.react :refer [view
|
||||
animated-view
|
||||
icon
|
||||
image
|
||||
text
|
||||
text-input
|
||||
touchable-highlight]]
|
||||
[status-im.components.drag-drop :as drag]
|
||||
[status-im.chat.views.response-suggestions :refer [response-suggestions-view]]
|
||||
[status-im.chat.styles.response :as st]
|
||||
[status-im.chat.styles.message-input :refer [input-height]]
|
||||
[status-im.components.animation :as anim]))
|
||||
|
||||
(defn drag-icon []
|
||||
[view st/drag-container
|
||||
[icon :drag-white st/drag-icon]])
|
||||
|
||||
(defn command-icon []
|
||||
[view st/command-icon-container
|
||||
;; TODO stub data: command icon
|
||||
[icon :dollar-green st/command-icon]])
|
||||
|
||||
(defn info-container [command]
|
||||
[view st/info-container
|
||||
[text {:style st/command-name}
|
||||
(:description command)]
|
||||
[text {:style st/message-info}
|
||||
;; TODO stub data: request message info
|
||||
"By ???, MMM 1st at HH:mm"]])
|
||||
|
||||
(defn create-response-pan-responder []
|
||||
(drag/create-pan-responder
|
||||
{:on-move (fn [e gesture]
|
||||
(dispatch [:on-drag-response (.-dy gesture)]))
|
||||
:on-release (fn [e gesture]
|
||||
(dispatch [:fix-response-height]))}))
|
||||
|
||||
(defn request-info []
|
||||
(let [pan-responder (create-response-pan-responder)
|
||||
command (subscribe [:get-chat-command])]
|
||||
(fn []
|
||||
[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]]]]])))
|
||||
|
||||
(defn container-animation-logic [{:keys [animation? to-value current-value val]}]
|
||||
(fn [_]
|
||||
(if @animation?
|
||||
(let [to-value @to-value]
|
||||
(anim/start (anim/spring val {:toValue to-value})
|
||||
(fn [arg]
|
||||
(when (.-finished arg)
|
||||
(dispatch [:set-in [:animations :response-height-current] to-value])
|
||||
(dispatch [:finish-animate-response-resize])
|
||||
(when (= to-value input-height)
|
||||
(dispatch [:finish-animate-cancel-command])
|
||||
(dispatch [:cancel-command]))))))
|
||||
(anim/set-value val @current-value))))
|
||||
|
||||
(defn container [& children]
|
||||
(let [commands-input-is-switching? (subscribe [:get-in [:animations :commands-input-is-switching?]])
|
||||
response-resize? (subscribe [:get-in [:animations :response-resize?]])
|
||||
to-response-height (subscribe [:get-in [:animations :to-response-height]])
|
||||
cur-response-height (subscribe [:get-in [:animations :response-height-current]])
|
||||
response-height (anim/create-value (or @cur-response-height 0))
|
||||
context {:animation? (reaction (or @commands-input-is-switching? @response-resize?))
|
||||
:to-value to-response-height
|
||||
:current-value cur-response-height
|
||||
:val response-height}
|
||||
on-update (container-animation-logic context)]
|
||||
(r/create-class
|
||||
{:component-did-mount
|
||||
on-update
|
||||
:component-did-update
|
||||
on-update
|
||||
:reagent-render
|
||||
(fn [& children]
|
||||
@to-response-height
|
||||
(into [animated-view {:style (st/response-view (if (or @commands-input-is-switching? @response-resize?)
|
||||
response-height
|
||||
(or @cur-response-height 0)))}]
|
||||
children))})))
|
||||
|
||||
(defn response-view []
|
||||
[container
|
||||
[request-info]
|
||||
[response-suggestions-view]
|
||||
[view st/input-placeholder]])
|
|
@ -0,0 +1,38 @@
|
|||
(ns status-im.chat.views.response-suggestions
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
icon
|
||||
text
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.chat.styles.response-suggestions :as st]
|
||||
[status-im.utils.listview :refer [to-datasource]]))
|
||||
|
||||
(defn set-command-content [content]
|
||||
(dispatch [:set-chat-command-content content]))
|
||||
|
||||
(defn header-list-item [{:keys [header]}]
|
||||
[view st/header-container
|
||||
[text {:style st/header-text} header]])
|
||||
|
||||
(defn suggestion-list-item [{:keys [value description]}]
|
||||
[touchable-highlight {:onPress #(set-command-content value)}
|
||||
[view st/suggestion-container
|
||||
[view st/suggestion-sub-container
|
||||
[text {:style st/value-text} value]
|
||||
[text {:style st/description-text} description]]]])
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item (if (:header row)
|
||||
[header-list-item row]
|
||||
[suggestion-list-item row])))
|
||||
|
||||
(defview response-suggestions-view []
|
||||
[suggestions [:get-content-suggestions]]
|
||||
(when (seq suggestions)
|
||||
[view st/suggestions-container
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-row}]]))
|
|
@ -1,11 +1,11 @@
|
|||
(ns status-im.chat.views.suggestions
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.components.react :refer [view
|
||||
text
|
||||
icon
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
text
|
||||
icon
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
[status-im.chat.styles.suggestions :as st]))
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
|||
(fn []
|
||||
(let [suggestions @suggestions-atom]
|
||||
(when (seq suggestions)
|
||||
[view
|
||||
[view st/container
|
||||
[touchable-highlight {:style st/drag-down-touchable
|
||||
:onPress (fn []
|
||||
;; TODO hide suggestions?
|
||||
|
@ -41,6 +41,7 @@
|
|||
[view
|
||||
[icon :drag_down st/drag-down-icon]]]
|
||||
[view (st/suggestions-container (count suggestions))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:enableEmptySections true
|
||||
:renderRow render-row}]]])))))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:enableEmptySections true
|
||||
:keyboardShouldPersistTaps true
|
||||
:renderRow render-row}]]])))))
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[status-im.utils.datetime :as time]))
|
||||
|
||||
(defn chat-list-item-inner-view
|
||||
[{:keys [chat-id name color photo-path new-messages-count
|
||||
[{:keys [chat-id name color new-messages-count
|
||||
online group-chat contacts] :as chat}]
|
||||
(let [last-message (first (:messages chat))]
|
||||
[view st/chat-container
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
(ns status-im.components.animation
|
||||
(:require [status-im.components.react :refer [animated]]))
|
||||
|
||||
(defn start
|
||||
([anim] (.start anim))
|
||||
([anim callback] (.start anim callback)))
|
||||
|
||||
(defn timing [anim-value config]
|
||||
(.timing animated anim-value (clj->js config)))
|
||||
|
||||
(defn spring [anim-value config]
|
||||
(.spring animated anim-value (clj->js config)))
|
||||
|
||||
(defn event [config]
|
||||
(.event animated (clj->js [nil, config])))
|
||||
|
||||
(defn add-listener [anim-value listener]
|
||||
(.addListener anim-value listener))
|
||||
|
||||
(defn remove-all-listeners [anim-value]
|
||||
(.removeAllListeners anim-value))
|
||||
|
||||
(defn stop-animation [anim-value]
|
||||
(.stopAnimation anim-value))
|
||||
|
||||
(defn value [anim-value]
|
||||
(.-value anim-value))
|
||||
|
||||
(defn set-value [anim-value value]
|
||||
(.setValue anim-value value))
|
||||
|
||||
(defn create-value [value]
|
||||
(js/React.Animated.Value. value))
|
||||
|
||||
(defn x [value-xy]
|
||||
(.-x value-xy))
|
||||
|
||||
(defn y [value-xy]
|
||||
(.-y value-xy))
|
||||
|
||||
(defn get-layout [value-xy]
|
||||
(js->clj (.getLayout value-xy)))
|
||||
|
||||
(defn create-value-xy [x y]
|
||||
(js/React.Animated.ValueXY. (clj->js {:x x, :y y})))
|
|
@ -0,0 +1,12 @@
|
|||
(ns status-im.components.drag-drop
|
||||
(:require [status-im.components.react :refer [animated pan-responder]]
|
||||
[status-im.components.animation :as anim]))
|
||||
|
||||
(defn pan-handlers [pan-responder]
|
||||
(js->clj (.-panHandlers pan-responder)))
|
||||
|
||||
(defn create-pan-responder [{:keys [on-move on-release]}]
|
||||
(.create pan-responder
|
||||
(clj->js {:onStartShouldSetPanResponder (fn [] true)
|
||||
:onPanResponderMove on-move
|
||||
:onPanResponderRelease on-release})))
|
|
@ -46,6 +46,14 @@
|
|||
(when-let [picker (get-react-property "Picker")]
|
||||
(adapt-class (.-Item picker))))
|
||||
|
||||
(def pan-responder (.-PanResponder js/React))
|
||||
(def animated (.-Animated js/React))
|
||||
(def animated-view (r/adapt-react-class (.-View animated)))
|
||||
(def animated-text (r/adapt-react-class (.-Text animated)))
|
||||
|
||||
(def dimensions (.-Dimensions js/React))
|
||||
(defn get-dimensions [name]
|
||||
(js->clj (.get dimensions name) :keywordize-keys true))
|
||||
|
||||
(defn icon
|
||||
([n] (icon n {}))
|
||||
|
|
|
@ -10,3 +10,8 @@
|
|||
(def content-type-command "command")
|
||||
(def content-type-command-request "command-request")
|
||||
(def content-type-status "status")
|
||||
|
||||
(def max-chat-name-length 20)
|
||||
|
||||
(def response-input-hiding-duration 300)
|
||||
(def response-suggesstion-resize-duration 100)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
(ns status-im.db
|
||||
(:require [schema.core :as s :include-macros true]))
|
||||
(:require [schema.core :as s :include-macros true]
|
||||
[status-im.components.react :refer [animated]]
|
||||
[status-im.components.animation :as anim]))
|
||||
|
||||
;; schema of app-db
|
||||
(def schema {:greeting s/Str})
|
||||
|
@ -34,7 +36,15 @@
|
|||
:address ""
|
||||
:whisper-identity ""
|
||||
:phone-number ""}
|
||||
:disable-group-creation false})
|
||||
:disable-group-creation false
|
||||
:animations {;; mutable data
|
||||
:to-response-height nil
|
||||
:response-height-current nil
|
||||
:message-input-offset 0
|
||||
:message-input-buttons-scale 1
|
||||
:messages-offset 0
|
||||
:commands-input-is-switching? false
|
||||
:response-resize? false}})
|
||||
|
||||
(def protocol-initialized-path [:protocol-initialized])
|
||||
(defn chat-input-text-path [chat-id]
|
||||
|
|
|
@ -146,7 +146,9 @@
|
|||
(defview chat-name []
|
||||
[name [:chat :name]
|
||||
new-name [:get :new-chat-name]
|
||||
focused? [:get ::name-input-focused]]
|
||||
validation-messages [:new-chat-name-validation-messages]
|
||||
focused? [:get ::name-input-focused]
|
||||
valid? [:new-chat-name-valid?]]
|
||||
[view
|
||||
[text {:style st/chat-name-text} (label :t/chat-name)]
|
||||
[view (st/chat-name-value-container focused?)
|
||||
|
@ -157,12 +159,14 @@
|
|||
:on-blur blur}
|
||||
name]
|
||||
(if (or focused? (not= name new-name))
|
||||
[touchable-highlight {:style st/chat-name-btn-edit-container
|
||||
[touchable-highlight {:style (st/chat-name-btn-edit-container valid?)
|
||||
:on-press save}
|
||||
[view [icon :ok-purple st/add-members-icon]]]
|
||||
[touchable-highlight {:style st/chat-name-btn-edit-container
|
||||
[touchable-highlight {:style (st/chat-name-btn-edit-container true)
|
||||
:on-press focus}
|
||||
[text {:style st/chat-name-btn-edit-text} (label :t/edit)]])]])
|
||||
[text {:style st/chat-name-btn-edit-text} (label :t/edit)]])]
|
||||
(when (pos? (count validation-messages))
|
||||
[text {:style st/chat-name-validation-message} (first validation-messages)])])
|
||||
|
||||
(defview group-settings []
|
||||
[show-color-picker [:group-settings :show-color-picker]]
|
||||
|
|
|
@ -91,9 +91,15 @@
|
|||
:fontFamily font
|
||||
:color text1-color})
|
||||
|
||||
(def chat-name-btn-edit-container
|
||||
(def chat-name-validation-message
|
||||
{:marginTop 8
|
||||
:marginLeft 16
|
||||
:color :red})
|
||||
|
||||
(defn chat-name-btn-edit-container [enabled?]
|
||||
{:padding 16
|
||||
:justifyContent :center})
|
||||
:justifyContent :center
|
||||
:opacity (if enabled? 1 0.3)})
|
||||
|
||||
(def chat-name-btn-edit-text
|
||||
{:marginTop -1
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.group-settings.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]))
|
||||
(:require [re-frame.core :refer [register-sub]]
|
||||
[status-im.constants :refer [max-chat-name-length]]))
|
||||
|
||||
(register-sub :selected-participant
|
||||
(fn [db _]
|
||||
|
@ -11,3 +12,20 @@
|
|||
(register-sub :group-settings
|
||||
(fn [db [_ k]]
|
||||
(reaction (get-in @db [:group-settings k]))))
|
||||
|
||||
(defn get-chat-name-validation-messages [chat-name]
|
||||
(filter some?
|
||||
(list (when (zero? (count chat-name))
|
||||
"Chat name can't be empty")
|
||||
(when (< max-chat-name-length (count chat-name))
|
||||
"Chat name is too long"))))
|
||||
|
||||
(register-sub :new-chat-name-validation-messages
|
||||
(fn [db [_]]
|
||||
(let [chat-name (reaction (:new-chat-name @db))]
|
||||
(reaction (get-chat-name-validation-messages @chat-name)))))
|
||||
|
||||
(register-sub :new-chat-name-valid?
|
||||
(fn [db [_]]
|
||||
(let [chat-name (reaction (:new-chat-name @db))]
|
||||
(reaction (zero? (count (get-chat-name-validation-messages @chat-name)))))))
|
||||
|
|
|
@ -4,19 +4,22 @@
|
|||
[status-im.utils.logging :as log]
|
||||
[clojure.string :as s]))
|
||||
|
||||
;; TODO stub data?
|
||||
(def suggestions
|
||||
{:phone [{:value "89171111111"
|
||||
{:phone [{:header "Phone number formats"}
|
||||
{:value "89171111111"
|
||||
:description "Number format 1"}
|
||||
{:value "+79171111111"
|
||||
{:value "+79171111111"
|
||||
:description "Number format 2"}
|
||||
{:value "9171111111"
|
||||
{:value "9171111111"
|
||||
:description "Number format 3"}]})
|
||||
|
||||
(defn get-content-suggestions [db command text]
|
||||
(defn get-content-suggestions [command text]
|
||||
(or (when command
|
||||
(when-let [command-suggestions ((:command command) suggestions)]
|
||||
(filterv (fn [s]
|
||||
(and (.startsWith (:value s) (or text ""))
|
||||
(not= (:value s) text)))
|
||||
(or (:header s)
|
||||
(and (.startsWith (:value s) (or text ""))
|
||||
(not= (:value s) text))))
|
||||
command-suggestions)))
|
||||
[]))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
[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]]))
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@
|
|||
(fn [db _]
|
||||
(-> db
|
||||
(push-view :new-group)
|
||||
(assoc :new-group #{})))))
|
||||
(assoc :new-group #{})
|
||||
(assoc :new-chat-name nil)))))
|
||||
|
||||
(register-handler :show-contacts
|
||||
(fn [db _]
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[status-im.resources :as res]
|
||||
[status-im.components.react :refer [view
|
||||
text-input
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
text-input
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[status-im.components.styles :refer [color-purple]]
|
||||
[status-im.components.toolbar :refer [toolbar]]
|
||||
[status-im.utils.listview :refer [to-datasource]]
|
||||
|
@ -19,24 +19,30 @@
|
|||
|
||||
|
||||
(defview new-group-toolbar []
|
||||
[group-name [:get ::group-name]
|
||||
creation-disabled? [:get :disable-group-creation]]
|
||||
[toolbar
|
||||
{:title (label :t/new-group-chat)
|
||||
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style st/toolbar-icon}
|
||||
:handler (when-not creation-disabled?
|
||||
#(dispatch [:init-group-creation group-name]))}}])
|
||||
[group-name [:get :new-chat-name]
|
||||
creation-disabled? [:get :disable-group-creation]
|
||||
valid? [:new-chat-name-valid?]]
|
||||
(let [create-btn-enabled? (and valid? (not creation-disabled?))]
|
||||
[toolbar
|
||||
{:title (label :t/new-group-chat)
|
||||
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style (st/toolbar-icon create-btn-enabled?)}
|
||||
:handler (when create-btn-enabled?
|
||||
#(dispatch [:init-group-creation group-name]))}}]))
|
||||
|
||||
(defview group-name-input []
|
||||
[group-name [:get ::group-name]]
|
||||
[text-input
|
||||
{:underlineColorAndroid color-purple
|
||||
:style st/group-name-input
|
||||
:autoFocus true
|
||||
:placeholder (label :t/group-name)
|
||||
:onChangeText #(dispatch [:set ::group-name %])}
|
||||
group-name])
|
||||
[group-name [:get :new-chat-name]
|
||||
validation-messages [:new-chat-name-validation-messages]]
|
||||
[view
|
||||
[text-input
|
||||
{:underlineColorAndroid color-purple
|
||||
:style st/group-name-input
|
||||
:autoFocus true
|
||||
:placeholder (label :t/group-name)
|
||||
:onChangeText #(dispatch [:set :new-chat-name %])}
|
||||
group-name]
|
||||
(when (pos? (count validation-messages))
|
||||
[text {:style st/group-name-validation-message} (first validation-messages)])])
|
||||
|
||||
(defview new-group []
|
||||
[contacts [:all-contacts]]
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
text2-color
|
||||
toolbar-background1]]))
|
||||
|
||||
(def toolbar-icon
|
||||
{:width 20
|
||||
:height 18})
|
||||
(defn toolbar-icon [enabled?]
|
||||
{:width 20
|
||||
:height 18
|
||||
:opacity (if enabled? 1 0.3)})
|
||||
|
||||
(def new-group-container
|
||||
{:flex 1
|
||||
|
@ -33,6 +34,9 @@
|
|||
:fontFamily font
|
||||
:color text1-color})
|
||||
|
||||
(def group-name-validation-message
|
||||
{:color :red})
|
||||
|
||||
(def members-text
|
||||
{:marginTop 24
|
||||
:marginBottom 16
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
:location-command-description "Send location"
|
||||
:phone-command-description "Send phone number"
|
||||
:phone-request-text "Phone number request"
|
||||
:confirmation-code-coomand-description "Send confirmation code"
|
||||
:confirmation-code-command-description "Send confirmation code"
|
||||
:confirmation-code-request-text "Confirmation code request"
|
||||
:send-command-description "Send location"
|
||||
:request-command-description "Send request"
|
||||
|
|