Move animation to views

This commit is contained in:
virvar 2016-06-03 22:34:24 +03:00
parent 217f0f93d8
commit c229902a77
6 changed files with 209 additions and 112 deletions

View File

@ -51,7 +51,7 @@
(register-handler :start-cancel-command (register-handler :start-cancel-command
(fn [db _] (fn [db _]
(if (commands/get-chat-command-to-msg-id db) (if (commands/get-chat-command-to-msg-id db)
(dispatch [:animate-cancel-command #(dispatch [:cancel-command])]) (dispatch [:animate-cancel-command])
(dispatch [:cancel-command #(dispatch [:cancel-command])])) (dispatch [:cancel-command #(dispatch [:cancel-command])]))
db)) db))

View File

@ -1,6 +1,5 @@
(ns status-im.chat.handlers.animation (ns status-im.chat.handlers.animation
(:require [re-frame.core :refer [register-handler after dispatch]] (:require [re-frame.core :refer [register-handler after dispatch]]
[status-im.components.animation :as anim]
[status-im.components.drag-drop :as drag] [status-im.components.drag-drop :as drag]
[status-im.models.commands :as commands] [status-im.models.commands :as commands]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]]
@ -15,56 +14,30 @@
(fn [db _] (fn [db _]
(assoc-in db [:animations :commands-input-is-switching?] false))) (assoc-in db [:animations :commands-input-is-switching?] false)))
(defn animate-cancel-command! [{{:keys [response-height-anim-value
message-input-buttons-scale
message-input-offset
messages-offset-anim-value]} :animations}
[_ on-animation-stop]]
(let [height-to-value zero-height]
(anim/start (anim/spring response-height-anim-value {:toValue height-to-value})
(fn []
(dispatch [:finish-animate-cancel-command])
(on-animation-stop)))
(anim/start (anim/timing message-input-buttons-scale {:toValue 1
:duration response-input-hiding-duration}))
(anim/start (anim/timing message-input-offset {:toValue 0
:duration response-input-hiding-duration}))
(anim/start (anim/spring messages-offset-anim-value {:toValue 0}))))
(register-handler :animate-cancel-command (register-handler :animate-cancel-command
(after animate-cancel-command!)
(fn [db _] (fn [db _]
(let [hiding? (get-in db [:animations :commands-input-is-switching?])] (let [hiding? (get-in db [:animations :commands-input-is-switching?])]
(if-not hiding? (if-not hiding?
(assoc-in db [:animations :commands-input-is-switching?] true) (-> db
(assoc-in [:animations :commands-input-is-switching?] true)
(assoc-in [:animations :message-input-buttons-scale] 1)
(assoc-in [:animations :message-input-offset] 0)
(assoc-in [:animations :to-response-height] zero-height)
(assoc-in [:animations :messages-offset] 0))
db)))) db))))
(register-handler :finish-animate-response-resize (register-handler :finish-animate-response-resize
(fn [db _] (fn [db _]
(let [fixed (get-in db [:animations :response-height-fixed])] (let [fixed (get-in db [:animations :to-response-height])]
(-> db (-> db
(assoc-in [:animations :response-height] fixed) (assoc-in [:animations :response-height-current] fixed)
(assoc-in [:animations :response-resize?] false))))) (assoc-in [:animations :response-resize?] false)))))
(register-handler :set-response-height (register-handler :set-response-height
(fn [db [_ value]] (fn [db [_ value]]
(assoc-in db [:animations :response-height] value))) (assoc-in db [:animations :response-height-current] value)))
(defn animate-response-resize! [{{height-anim-value :response-height-anim-value
from :response-height
to :response-height-fixed} :animations}]
(anim/remove-all-listeners height-anim-value)
(anim/set-value height-anim-value from)
(anim/add-listener height-anim-value
(fn [val]
(dispatch [:set-response-height (anim/value val)])))
(anim/start (anim/spring height-anim-value {:toValue to})
(fn []
(anim/remove-all-listeners height-anim-value)
(dispatch [:finish-animate-response-resize]))))
(register-handler :animate-response-resize (register-handler :animate-response-resize
(after animate-response-resize!)
(fn [db _] (fn [db _]
(assoc-in db [:animations :response-resize?] true))) (assoc-in db [:animations :response-resize?] true)))
@ -80,30 +53,21 @@
(min response-height-normal (+ suggestions-height request-info-height))))) (min response-height-normal (+ suggestions-height request-info-height)))))
(defn update-response-height [db] (defn update-response-height [db]
(assoc-in db [:animations :response-height-fixed] (get-response-height db))) (assoc-in db [:animations :to-response-height] (get-response-height db)))
(register-handler :finish-show-response! (register-handler :finish-show-response
(fn [db _] (fn [db _]
(assoc-in db [:animations :commands-input-is-switching?] false))) (assoc-in db [:animations :commands-input-is-switching?] false)))
(defn animate-show-response! [{{scale-anim-value :message-input-buttons-scale
input-offset-anim-value :message-input-offset
messages-offset-anim-value :messages-offset-anim-value} :animations}]
(let [to-value 0.1]
(anim/start (anim/timing scale-anim-value {:toValue to-value
:duration response-input-hiding-duration})
#(dispatch [:finish-show-response!]))
(anim/start (anim/timing input-offset-anim-value {:toValue -40
:duration response-input-hiding-duration}))
(anim/start (anim/spring messages-offset-anim-value {:toValue request-info-height}))))
(register-handler :animate-show-response (register-handler :animate-show-response
(after animate-show-response!)
(fn [db _] (fn [db _]
(dispatch [:animate-response-resize]) (dispatch [:animate-response-resize])
(-> db (-> db
(assoc-in [:animations :commands-input-is-switching?] true) (assoc-in [:animations :commands-input-is-switching?] true)
(assoc-in [:animations :response-height] zero-height) (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)))) (update-response-height))))
(register-handler :set-response-max-height (register-handler :set-response-max-height
@ -112,12 +76,12 @@
(register-handler :on-drag-response (register-handler :on-drag-response
(fn [db [_ dy]] (fn [db [_ dy]]
(let [fixed (get-in db [:animations :response-height-fixed])] (let [fixed (get-in db [:animations :to-response-height])]
(assoc-in db [:animations :response-height] (- fixed dy))))) (assoc-in db [:animations :response-height-current] (- fixed dy)))))
(register-handler :fix-response-height (register-handler :fix-response-height
(fn [db _] (fn [db _]
(let [current (get-in db [:animations :response-height]) (let [current (get-in db [:animations :response-height-current])
normal-height response-height-normal normal-height response-height-normal
max-height (get-in db [:animations :response-height-max]) max-height (get-in db [:animations :response-height-max])
delta (/ normal-height 2) delta (/ normal-height 2)
@ -126,7 +90,7 @@
(<= current (+ zero-height normal-height delta)) (get-response-height db) (<= current (+ zero-height normal-height delta)) (get-response-height db)
:else max-height)] :else max-height)]
(dispatch [:animate-response-resize]) (dispatch [:animate-response-resize])
(assoc-in db [:animations :response-height-fixed] new-fixed)))) (assoc-in db [:animations :to-response-height] new-fixed))))
(defn create-response-pan-responder [] (defn create-response-pan-responder []
(drag/create-pan-responder (drag/create-pan-responder

View File

@ -22,7 +22,9 @@
[status-im.chat.views.suggestions :refer [suggestions-view]] [status-im.chat.views.suggestions :refer [suggestions-view]]
[status-im.chat.views.response :refer [response-view]] [status-im.chat.views.response :refer [response-view]]
[status-im.chat.views.new-message :refer [chat-message-new]] [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] (defn contacts-by-identity [contacts]
@ -218,16 +220,40 @@
(defview messages-view [group-chat] (defview messages-view [group-chat]
[messages [:chat :messages] [messages [:chat :messages]
contacts [:chat :contacts] contacts [:chat :contacts]]
messages-offset [:get-in [:animations :messages-offset-anim-value]]]
(let [contacts' (contacts-by-identity contacts)] (let [contacts' (contacts-by-identity contacts)]
[animated-view {:style (st/messages-container messages-offset)}
[list-view {:renderRow (message-row contacts' group-chat) [list-view {:renderRow (message-row contacts' group-chat)
:renderScrollComponent #(invertible-scroll-view (js->clj %)) :renderScrollComponent #(invertible-scroll-view (js->clj %))
:onEndReached #(dispatch [:load-more-messages]) :onEndReached #(dispatch [:load-more-messages])
:enableEmptySections true :enableEmptySections true
:keyboardShouldPersistTaps true :keyboardShouldPersistTaps true
:dataSource (to-datasource messages)}]])) :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 [] (defview chat []
[group-chat [:chat :group-chat] [group-chat [:chat :group-chat]
@ -236,7 +262,8 @@
to-msg-id [:get-chat-command-to-msg-id]] to-msg-id [:get-chat-command-to-msg-id]]
[view st/chat-view [view st/chat-view
[chat-toolbar] [chat-toolbar]
[messages-view group-chat] [messages-container
[messages-view group-chat]]
(when group-chat [typing-all]) (when group-chat [typing-all])
(cond (cond
(and command to-msg-id) [response-view] (and command to-msg-id) [response-view]

View File

@ -1,17 +1,20 @@
(ns status-im.chat.views.plain-input (ns status-im.chat.views.plain-input
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r]
[status-im.components.react :refer [view [status-im.components.react :refer [view
animated-view animated-view
icon icon
touchable-highlight touchable-highlight
text-input text-input
dismiss-keyboard!]] dismiss-keyboard!]]
[status-im.components.animation :as anim]
[status-im.chat.views.command :as command] [status-im.chat.views.command :as command]
[status-im.chat.views.response :as response] [status-im.chat.views.response :as response]
[status-im.chat.styles.plain-input :as st] [status-im.chat.styles.plain-input :as st]
[status-im.chat.styles.input :as st-command] [status-im.chat.styles.input :as st-command]
[status-im.chat.styles.response :as st-response])) [status-im.chat.styles.response :as st-response]
[status-im.constants :refer [response-input-hiding-duration]]))
(defn set-input-message [message] (defn set-input-message [message]
(dispatch [:set-chat-input-text message])) (dispatch [:set-chat-input-text message]))
@ -30,29 +33,95 @@
(when (message-valid? staged-commands message) (when (message-valid? staged-commands message)
(send dismiss-keyboard))) (send dismiss-keyboard)))
(defview commands-button [animation?] (defn commands-button-animation-logic [{:keys [to-value val]}]
[typing-command? [:typing-command?] (fn [_]
buttons-scale [:get-in [:animations :message-input-buttons-scale]]] (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 [animation?]
(let [typing-command? (subscribe [:typing-command?])
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 [animation?]
(let [typing-command? @typing-command?]
@to-scale
[touchable-highlight {:disabled animation? [touchable-highlight {:disabled animation?
:on-press #(dispatch [:switch-command-suggestions]) :on-press #(dispatch [:switch-command-suggestions])
:style st/message-input-button-touchable} :style st/message-input-button-touchable}
[animated-view {:style (st/message-input-button buttons-scale)} [animated-view {:style (st/message-input-button buttons-scale)}
(if typing-command? (if typing-command?
[icon :close-gray st/close-icon] [icon :close-gray st/close-icon]
[icon :list st/list-icon])]]) [icon :list st/list-icon])]]))})))
(defview smile-button [animation?] (defn smile-button [animation?]
[buttons-scale [:get-in [:animations :message-input-buttons-scale]]] (let [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 [animation?]
@to-scale
[touchable-highlight {:disabled animation? [touchable-highlight {:disabled animation?
:on-press #(dispatch [:switch-command-suggestions]) :on-press (fn []
;; TODO emoticons: not implemented
)
:style st/message-input-button-touchable} :style st/message-input-button-touchable}
[animated-view {:style (st/message-input-button buttons-scale)} [animated-view {:style (st/message-input-button buttons-scale)}
[icon :smile st/smile-icon]]]) [icon :smile st/smile-icon]]])})))
(defview message-input-container [input] (defn message-input-container-animation-logic [{:keys [to-value val]}]
[message-input-offset [:get-in [:animations :message-input-offset]]] (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)} [animated-view {:style (st/message-input-container message-input-offset)}
input]) input])})))
(defview plain-message-input-view [{:keys [input-options validator]}] (defview plain-message-input-view [{:keys [input-options validator]}]
[input-message [:get-chat-input-text] [input-message [:get-chat-input-text]

View File

@ -1,6 +1,8 @@
(ns status-im.chat.views.response (ns status-im.chat.views.response
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [reagent.ratom :refer [reaction]]
[status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r]
[status-im.components.react :refer [view [status-im.components.react :refer [view
animated-view animated-view
icon icon
@ -10,7 +12,9 @@
touchable-highlight]] touchable-highlight]]
[status-im.components.drag-drop :as drag] [status-im.components.drag-drop :as drag]
[status-im.chat.views.response-suggestions :refer [response-suggestions-view]] [status-im.chat.views.response-suggestions :refer [response-suggestions-view]]
[status-im.chat.styles.response :as st])) [status-im.chat.styles.response :as st]
[status-im.chat.styles.plain-input :refer [input-height]]
[status-im.components.animation :as anim]))
(defn drag-icon [] (defn drag-icon []
[view st/drag-container [view st/drag-container
@ -40,20 +44,54 @@
[view st/cancel-container [view st/cancel-container
[icon :close-white st/cancel-icon]]]]]) [icon :close-white st/cancel-icon]]]]])
(defview response-view [] (defn inner-container-animation-logic [{:keys [animation? to-value current-value val]}]
[pan-responder [:get-in [:animations :response-pan-responder]] (fn [_]
response-height [:get-in [:animations :response-height]] (if @animation?
anim-height [:get-in [:animations :response-height-anim-value]] (let [to-value @to-value]
commands-input-is-switching? [:get-in [:animations :commands-input-is-switching?]] (anim/start (anim/spring val {:toValue to-value})
response-resize? [:get-in [:animations :response-resize?]]] (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 inner-container [content]
(let [pan-responder (subscribe [:get-in [:animations :response-pan-responder]])
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 (inner-container-animation-logic context)]
(r/create-class
{:component-did-mount
on-update
:component-did-update
on-update
:reagent-render
(fn [content]
@to-response-height
[animated-view (merge (drag/pan-handlers @pan-responder)
{:style (st/response-view (if (or @commands-input-is-switching? @response-resize?)
response-height
(or @cur-response-height 0)))})
content])})))
(defn response-view []
[view {:style st/container [view {:style st/container
:onLayout (fn [event] :onLayout (fn [event]
(let [height (.. event -nativeEvent -layout -height)] (let [height (.. event -nativeEvent -layout -height)]
(dispatch [:set-response-max-height height])))} (dispatch [:set-response-max-height height])))}
[animated-view (merge (drag/pan-handlers pan-responder) [inner-container
{:style (st/response-view (if (or commands-input-is-switching? response-resize?) [view
anim-height
response-height))})
[request-info] [request-info]
[response-suggestions-view] [response-suggestions-view]
[view st/input-placeholder]]]) [view st/input-placeholder]]]])

View File

@ -33,14 +33,13 @@
:current-tag nil :current-tag nil
:disable-group-creation false :disable-group-creation false
:animations {;; mutable data :animations {;; mutable data
:response-height nil :to-response-height nil
:response-height-fixed nil :response-height-current nil
:response-pan-responder nil :response-pan-responder nil
:message-input-offset (anim/create-value 0) :message-input-offset 0
:message-input-buttons-scale (anim/create-value 1) :message-input-buttons-scale 1
:commands-input-is-switching? false :commands-input-is-switching? false
:response-height-anim-value (anim/create-value 0) :messages-offset 0
:messages-offset-anim-value (anim/create-value 0)
:response-resize? false}}) :response-resize? false}})
(def protocol-initialized-path [:protocol-initialized]) (def protocol-initialized-path [:protocol-initialized])