From 991d909b972fdc4f4080e4983be24d7eb52349eb Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Mon, 20 Jun 2016 01:20:48 +0300 Subject: [PATCH] another attempt Former-commit-id: 5e7df10c76afdd4d0a83121c119a0d6b1432c06b --- src/status_im/chat/handlers.cljs | 8 +- src/status_im/chat/handlers/animation.cljs | 65 +++++------ src/status_im/chat/styles/message_input.cljs | 5 +- src/status_im/chat/styles/plain_message.cljs | 4 +- src/status_im/chat/styles/response.cljs | 1 - src/status_im/chat/views/command.cljs | 6 +- src/status_im/chat/views/message_input.cljs | 108 +++++++------------ src/status_im/chat/views/plain_message.cljs | 100 +++++++++-------- src/status_im/chat/views/response.cljs | 80 +++++++------- src/status_im/components/animation.cljs | 3 + src/status_im/constants.cljs | 2 +- src/status_im/db.cljs | 7 +- 12 files changed, 171 insertions(+), 218 deletions(-) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 9ec8b78858..05f1bef3a7 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -48,9 +48,7 @@ (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]))))) + (dispatch [:animate-cancel-command])))) (defn animate-set-chat-command-content [db _] (when (commands/get-chat-command-to-msg-id db) @@ -78,7 +76,9 @@ command-info {:command command :content content :handler (:handler command)}] - (commands/stage-command db command-info)))) + (-> db + (assoc-in [:chats current-chat-id :command-input :command] nil) + (commands/stage-command command-info))))) (register-handler :set-message-input [] (fn [db [_ input]] diff --git a/src/status_im/chat/handlers/animation.cljs b/src/status_im/chat/handlers/animation.cljs index 2859261ab3..f296ea73d8 100644 --- a/src/status_im/chat/handlers/animation.cljs +++ b/src/status_im/chat/handlers/animation.cljs @@ -15,20 +15,12 @@ ([name middleware handler] (register-handler name [(path :animations) middleware] handler))) -(animation-handler :finish-animate-cancel-command - (fn [db _] - (assoc db :commands-input-is-switching? false))) - (animation-handler :animate-cancel-command (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))) + (assoc db + :command? false + :to-response-height zero-height + :messages-offset 0))) (animation-handler :finish-animate-response-resize (fn [db _] @@ -58,18 +50,12 @@ (defn update-response-height [db] (assoc-in db [:animations :to-response-height] (get-response-height db))) -(animation-handler :finish-show-response - (fn [db _] - (assoc db :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 :command?] true) (assoc-in [:animations :messages-offset] request-info-height) (update-response-height)))) @@ -91,21 +77,26 @@ :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))) + (fn [db [_ dy vy current]] + (let [max-height (get-in db [:animations :response-height-max]) + ;; todo magic value + middle 270 + moving-down? (pos? vy) + moving-up? (not moving-down?) + under-middle-position? (<= current middle) + over-middle-position? (not under-middle-position?) + min-height (+ zero-height request-info-height) + new-fixed (cond (and under-middle-position? moving-down?) + min-height + + (and under-middle-position? moving-up?) + middle + + (and over-middle-position? moving-down?) + middle + + (and over-middle-position? moving-up?) + max-height)] + (-> db + (assoc-in [:animations :to-response-height] new-fixed) + (update-in [:animations :response-height-changed] inc))))) diff --git a/src/status_im/chat/styles/message_input.cljs b/src/status_im/chat/styles/message_input.cljs index 9cbcc4e27f..ccde0a7994 100644 --- a/src/status_im/chat/styles/message_input.cljs +++ b/src/status_im/chat/styles/message_input.cljs @@ -4,10 +4,9 @@ (def input-height 56) -(defn message-input-container [offset] +(def message-input-container {:flex 1 - :transform [{:translateX offset}] - :marginRight offset}) + :marginRight 0}) (def input-container {:flexDirection :column}) diff --git a/src/status_im/chat/styles/plain_message.cljs b/src/status_im/chat/styles/plain_message.cljs index d52ae4d257..b85dea9a97 100644 --- a/src/status_im/chat/styles/plain_message.cljs +++ b/src/status_im/chat/styles/plain_message.cljs @@ -2,8 +2,8 @@ (:require [status-im.components.styles :refer [font text2-color]])) -(def message-input-button-touchable - {:width 56 +(defn message-input-button-touchable [w] + {:width w :height 56 :alignItems :center :justifyContent :center}) diff --git a/src/status_im/chat/styles/response.cljs b/src/status_im/chat/styles/response.cljs index 029ca2ed86..918bd28eec 100644 --- a/src/status_im/chat/styles/response.cljs +++ b/src/status_im/chat/styles/response.cljs @@ -87,7 +87,6 @@ (def command-input {:flex 1 - :marginLeft 56 :marginRight 16 :marginTop -2 :padding 0 diff --git a/src/status_im/chat/views/command.cljs b/src/status_im/chat/views/command.cljs index 582dacfa49..51b9bd8fd7 100644 --- a/src/status_im/chat/views/command.cljs +++ b/src/status_im/chat/views/command.cljs @@ -31,9 +31,7 @@ [view (st/command-text-container command) [text {:style st/command-text} (:text command)]]) -(defview cancel-button [] - [commands-input-is-switching? [:animations :commands-input-is-switching?]] - [touchable-highlight {:disabled commands-input-is-switching? - :on-press cancel-command-input} +(defn cancel-button [] + [touchable-highlight {:on-press cancel-command-input} [view st/cancel-container [icon :close-gray st/cancel-icon]]]) diff --git a/src/status_im/chat/views/message_input.cljs b/src/status_im/chat/views/message_input.cljs index 4c26e15eb8..d3bf3eccc8 100644 --- a/src/status_im/chat/views/message_input.cljs +++ b/src/status_im/chat/views/message_input.cljs @@ -18,10 +18,8 @@ [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? [:animations :commands-input-is-switching?]] - [touchable-highlight {:disabled commands-input-is-switching? - :on-press on-press +(defn send-button [{:keys [on-press accessibility-label]}] + [touchable-highlight {:on-press on-press :accessibility-label accessibility-label} [view st/send-container [icon :send st/send-icon]]]) @@ -36,61 +34,42 @@ (dispatch [:set-animation ::message-input-offset-current to-value]))))))) (defn message-input-container [input] - (let [to-message-input-offset (subscribe [:animations :message-input-offset]) - cur-message-input-offset (subscribe [: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 (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])}))) + [view st/message-input-container 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? [: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)])) + [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?]] + (let [dismiss-keyboard (not (or command typing-command?)) + response? (and command to-msg-id) + message-input? (not command)] + [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] + ((if message-input? + plain-message/set-input-message + command/set-input-message) + text)) + :onSubmitEditing #(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] @@ -98,22 +77,17 @@ 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? [:animations :commands-input-is-switching?]] + typing-command? [:typing-command?]] (let [dismiss-keyboard (not (or command typing-command?)) - response? (and command to-msg-id) - message-input? (or (not command) commands-input-is-switching?)] + response? (and command to-msg-id) + message-input? (not command)] [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?])) + [plain-message/commands-button] [message-input-container [message-input input-options validator]] ;; TODO emoticons: not implemented - (when message-input? - [plain-message/smile-button]) + [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 diff --git a/src/status_im/chat/views/plain_message.cljs b/src/status_im/chat/views/plain_message.cljs index 7c637ebbd0..b7ecef4e2c 100644 --- a/src/status_im/chat/views/plain_message.cljs +++ b/src/status_im/chat/views/plain_message.cljs @@ -33,39 +33,29 @@ (.clear message-input) (.focus message-input))) -(defn commands-button-animation-callback [message-input] - (fn [arg to-value] - (when (.-finished arg) - (dispatch [:set-animation ::message-input-buttons-scale-current to-value]) - (when (<= to-value 0.1) - (dispatch [:finish-show-response]) - (prepare-message-input @message-input))))) - -(defn button-animation-logic [{:keys [to-value val callback]}] +(defn button-animation-logic [{:keys [command? 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}) - (when callback - (fn [arg] - (callback arg to-scale))))))) + (let [to-scale (if @command? 0 1)] + (anim/start (anim/spring val {:toValue to-scale}))))) + +(defn list-container [min] + (fn [{:keys [command? width]}] + (let [n-width (if @command? min 56) + delay (if @command? 100 0)] + (anim/start (anim/timing width {:toValue n-width + :duration response-input-hiding-duration + :delay delay}))))) (defn commands-button [] - (let [typing-command? (subscribe [:typing-command?]) - message-input (subscribe [:get :message-input]) - animation? (subscribe [:animations :commands-input-is-switching?]) - to-scale (subscribe [:animations :message-input-buttons-scale]) - cur-scale (subscribe [:animations ::message-input-buttons-scale-current]) - buttons-scale (anim/create-value (or @cur-scale 1)) - anim-callback (commands-button-animation-callback message-input) - context {:to-value to-scale - :val buttons-scale - :callback anim-callback} - on-update (button-animation-logic context)] + (let [command? (subscribe [:animations :command?]) + 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))] (r/create-class {:component-did-mount on-update @@ -73,24 +63,30 @@ 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])]]))}))) + [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]]]])}))) + +(defn smile-animation-logic [{:keys [command? val width]}] + (fn [_] + (let [to-scale (if @command? 0 1)] + (when-not @command? (anim/set-value width 56)) + (anim/start (anim/spring val {:toValue to-scale}) + (fn [] + (when @command? + (anim/set-value width 0.1))))))) (defn smile-button [] - (let [animation? (subscribe [:animations :commands-input-is-switching?]) - to-scale (subscribe [:animations :message-input-buttons-scale]) - cur-scale (subscribe [: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 (button-animation-logic context)] + (let [command? (subscribe [:animations :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)] (r/create-class {:component-did-mount on-update @@ -98,11 +94,11 @@ on-update :reagent-render (fn [] - @to-scale - [touchable-highlight {:disabled @animation? - :on-press (fn [] + [touchable-highlight {: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]]])}))) + :disabled @command?} + [animated-view {:style (st/message-input-button-touchable + container-width)} + [animated-view {:style (st/message-input-button buttons-scale)} + [icon :smile st/smile-icon]]]])}))) diff --git a/src/status_im/chat/views/response.cljs b/src/status_im/chat/views/response.cljs index 6f745b5844..7ff986e7a8 100644 --- a/src/status_im/chat/views/response.cljs +++ b/src/status_im/chat/views/response.cljs @@ -14,7 +14,8 @@ [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])) + [status-im.components.animation :as anim] + [status-im.components.react :as react])) (defn drag-icon [] [view st/drag-container @@ -33,17 +34,25 @@ ;; TODO stub data: request message info "By ???, MMM 1st at HH:mm"]]) -(defn create-response-pan-responder [] +(defn create-response-pan-responder [response-height] (drag/create-pan-responder - {:on-move (fn [e gesture] - (dispatch [:on-drag-response (.-dy gesture)])) - :on-release (fn [e gesture] - (dispatch [:fix-response-height]))})) + {:on-move (fn [_ gesture] + (when (> (Math/abs (.-dy gesture)) 10) + (let [to-value (- (:height (react/get-dimensions "window")) + (.-moveY gesture))] + (anim/start + (anim/spring response-height {:toValue to-value}))))) + :on-release (fn [_ gesture] + (when (> (Math/abs (.-dy gesture)) 10) + (dispatch [:fix-response-height + (.-dy gesture) + (.-vy gesture) + (.-_value response-height)])))})) -(defn request-info [] - (let [pan-responder (create-response-pan-responder) - command (subscribe [:get-chat-command])] - (fn [] +(defn request-info [response-height] + (let [pan-responder (create-response-pan-responder 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] @@ -54,46 +63,33 @@ [view st/cancel-container [icon :close-white st/cancel-icon]]]]]))) -(defn container-animation-logic [{:keys [animation? to-value current-value val]}] +(defn container-animation-logic [{:keys [to-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-animation :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)))) + (let [to-value @to-value] + (anim/start (anim/spring val {:toValue to-value}))))) -(defn container [& children] - (let [commands-input-is-switching? (subscribe [:animations :commands-input-is-switching?]) - response-resize? (subscribe [:animations :response-resize?]) - to-response-height (subscribe [:animations :to-response-height]) - cur-response-height (subscribe [: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)] +(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)] (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)))}] + (fn [response-height & children] + @to-response-height @changed + (into [animated-view {:style (st/response-view response-height)}] children))}))) (defn response-view [] - [container - [request-info] - [response-suggestions-view] - [view st/input-placeholder]]) + (let [response-height (anim/create-value 0)] + [container response-height + [request-info response-height] + [response-suggestions-view] + [view st/input-placeholder]])) diff --git a/src/status_im/components/animation.cljs b/src/status_im/components/animation.cljs index a945d44f4c..74d3cb3f78 100644 --- a/src/status_im/components/animation.cljs +++ b/src/status_im/components/animation.cljs @@ -11,6 +11,9 @@ (defn spring [anim-value config] (.spring animated anim-value (clj->js config))) +(defn decay [anim-value config] + (.decay animated anim-value (clj->js config))) + (defn anim-sequence [animations] (.sequence animated (clj->js animations))) diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 556f9b7898..7faee32d1b 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -13,5 +13,5 @@ (def max-chat-name-length 20) -(def response-input-hiding-duration 300) +(def response-input-hiding-duration 100) (def response-suggesstion-resize-duration 100) diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 2b3ad6f88f..e118920433 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -37,13 +37,10 @@ :whisper-identity "" :phone-number ""} :disable-group-creation false - :animations {;; mutable data - :to-response-height nil + :animations {:to-response-height nil :response-height-current nil - :message-input-offset 0 - :message-input-buttons-scale 1 + :command? false :messages-offset 0 - :commands-input-is-switching? false :response-resize? false}}) (def protocol-initialized-path [:protocol-initialized])