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
(fn [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])]))
db))

View File

@ -1,6 +1,5 @@
(ns status-im.chat.handlers.animation
(:require [re-frame.core :refer [register-handler after dispatch]]
[status-im.components.animation :as anim]
[status-im.components.drag-drop :as drag]
[status-im.models.commands :as commands]
[status-im.handlers.content-suggestions :refer [get-content-suggestions]]
@ -15,56 +14,30 @@
(fn [db _]
(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
(after animate-cancel-command!)
(fn [db _]
(let [hiding? (get-in db [:animations :commands-input-is-switching?])]
(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))))
(register-handler :finish-animate-response-resize
(fn [db _]
(let [fixed (get-in db [:animations :response-height-fixed])]
(let [fixed (get-in db [:animations :to-response-height])]
(-> db
(assoc-in [:animations :response-height] fixed)
(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] 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]))))
(assoc-in db [:animations :response-height-current] value)))
(register-handler :animate-response-resize
(after animate-response-resize!)
(fn [db _]
(assoc-in db [:animations :response-resize?] true)))
@ -80,30 +53,21 @@
(min response-height-normal (+ suggestions-height request-info-height)))))
(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 _]
(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
(after animate-show-response!)
(fn [db _]
(dispatch [:animate-response-resize])
(-> db
(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))))
(register-handler :set-response-max-height
@ -112,12 +76,12 @@
(register-handler :on-drag-response
(fn [db [_ dy]]
(let [fixed (get-in db [:animations :response-height-fixed])]
(assoc-in db [:animations :response-height] (- fixed dy)))))
(let [fixed (get-in db [:animations :to-response-height])]
(assoc-in db [:animations :response-height-current] (- fixed dy)))))
(register-handler :fix-response-height
(fn [db _]
(let [current (get-in db [:animations :response-height])
(let [current (get-in db [:animations :response-height-current])
normal-height response-height-normal
max-height (get-in db [:animations :response-height-max])
delta (/ normal-height 2)
@ -126,7 +90,7 @@
(<= current (+ zero-height normal-height delta)) (get-response-height db)
:else max-height)]
(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 []
(drag/create-pan-responder

View File

@ -22,7 +22,9 @@
[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]
@ -217,17 +219,41 @@
:custom-action [toolbar-action]}])))
(defview messages-view [group-chat]
[messages [:chat :messages]
contacts [:chat :contacts]
messages-offset [:get-in [:animations :messages-offset-anim-value]]]
(let [contacts' (contacts-by-identity contacts)]
[animated-view {:style (st/messages-container messages-offset)}
[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)}]]))
[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]
@ -236,7 +262,8 @@
to-msg-id [:get-chat-command-to-msg-id]]
[view st/chat-view
[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]

View File

@ -1,17 +1,20 @@
(ns status-im.chat.views.plain-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.command :as command]
[status-im.chat.views.response :as response]
[status-im.chat.styles.plain-input :as st]
[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]
(dispatch [:set-chat-input-text message]))
@ -30,29 +33,95 @@
(when (message-valid? staged-commands message)
(send dismiss-keyboard)))
(defview commands-button [animation?]
[typing-command? [:typing-command?]
buttons-scale [:get-in [:animations :message-input-buttons-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 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]))))))))
(defview smile-button [animation?]
[buttons-scale [:get-in [:animations :message-input-buttons-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)}
[icon :smile st/smile-icon]]])
(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?
: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])]]))})))
(defview message-input-container [input]
[message-input-offset [:get-in [:animations :message-input-offset]]]
[animated-view {:style (st/message-input-container message-input-offset)}
input])
(defn smile-button [animation?]
(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?
: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]]])})))
(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 plain-message-input-view [{:keys [input-options validator]}]
[input-message [:get-chat-input-text]

View File

@ -1,6 +1,8 @@
(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]]
[reagent.core :as r]
[status-im.components.react :refer [view
animated-view
icon
@ -10,7 +12,9 @@
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.response :as st]
[status-im.chat.styles.plain-input :refer [input-height]]
[status-im.components.animation :as anim]))
(defn drag-icon []
[view st/drag-container
@ -40,20 +44,54 @@
[view st/cancel-container
[icon :close-white st/cancel-icon]]]]])
(defview response-view []
[pan-responder [:get-in [:animations :response-pan-responder]]
response-height [:get-in [:animations :response-height]]
anim-height [:get-in [:animations :response-height-anim-value]]
commands-input-is-switching? [:get-in [:animations :commands-input-is-switching?]]
response-resize? [:get-in [:animations :response-resize?]]]
(defn inner-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 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
:onLayout (fn [event]
(let [height (.. event -nativeEvent -layout -height)]
(dispatch [:set-response-max-height height])))}
[animated-view (merge (drag/pan-handlers pan-responder)
{:style (st/response-view (if (or commands-input-is-switching? response-resize?)
anim-height
response-height))})
[request-info]
[response-suggestions-view]
[view st/input-placeholder]]])
[inner-container
[view
[request-info]
[response-suggestions-view]
[view st/input-placeholder]]]])

View File

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