diff --git a/src/status_im/chat/constants.cljs b/src/status_im/chat/constants.cljs index e9d95a4ed9..f37aff957e 100644 --- a/src/status_im/chat/constants.cljs +++ b/src/status_im/chat/constants.cljs @@ -4,3 +4,4 @@ (def request-info-height 61) (def response-height-normal 211) (def minimum-suggestion-height (+ input-height request-info-height)) +(def minimum-command-suggestions-height (+ input-height 22)) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index c1627a957e..3d1d213cab 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -19,6 +19,7 @@ [status-im.utils.phone-number :refer [format-phone-number]] [status-im.utils.datetime :as time] [status-im.components.jail :as j] + [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [generate-hiccup]])) (register-handler :set-show-actions @@ -93,7 +94,7 @@ (register-handler :stage-command (after invoke-command-preview!) (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 @@ -115,9 +116,7 @@ (register-handler :set-response-chat-command [(after invoke-suggestions-handler!) - (after #(dispatch [:command-edit-mode])) - ;(after #(dispatch [:animate-show-response])) - ] + (after #(dispatch [:command-edit-mode]))] (fn [db [_ to-msg-id command-key]] (commands/set-response-chat-command db to-msg-id command-key))) @@ -133,8 +132,17 @@ db)) db)) +(defn check-suggestions + [{:keys [current-chat-id] :as db} [_ text]] + (assoc-in db + [:command-suggestions current-chat-id] + (suggestions/get-suggestions db text))) + (register-handler :set-chat-input-text - ((enrich update-command) update-text)) + [(enrich update-command) + (enrich check-suggestions) + (after #(dispatch [:animate-command-suggestions]))] + update-text) (defn console? [s] (= "console" s)) @@ -437,9 +445,11 @@ ((after save-chat!)) ((after open-chat!)))) -(register-handler :switch-command-suggestions - (fn [db [_]] - (suggestions/switch-command-suggestions db))) +(register-handler :switch-command-suggestions! + (u/side-effect! + (fn [db] + (let [text (if (suggestions/typing-command? db) "" "!")] + (dispatch [:set-chat-input-text text]))))) (defn remove-chat [{:keys [current-chat-id] :as db} _] diff --git a/src/status_im/chat/handlers/animation.cljs b/src/status_im/chat/handlers/animation.cljs index a1ea5c98a5..80ca0ac379 100644 --- a/src/status_im/chat/handlers/animation.cljs +++ b/src/status_im/chat/handlers/animation.cljs @@ -3,6 +3,7 @@ [re-frame.middleware :refer [path]] [status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.chat.constants :refer [input-height request-info-height + minimum-command-suggestions-height response-height-normal minimum-suggestion-height]] [status-im.constants :refer [response-input-hiding-duration]])) @@ -19,45 +20,45 @@ (fn [db _] (assoc db :to-response-height input-height - :messages-offset 0))) + :messages-offset? false))) -(defn get-response-height - [{:keys [current-chat-id] :as db}] - (let [suggestions (get-in db [:suggestions current-chat-id]) - suggestions-height (if suggestions middle-height 0)] - (+ input-height - (min response-height-normal (+ suggestions-height request-info-height))))) +(def response-height (+ input-height response-height-normal)) (defn update-response-height [db] - (assoc-in db [:animations :to-response-height] (get-response-height db))) + (assoc-in db [:animations :to-response-height] response-height)) -(register-handler :animate-show-response +(register-handler :animate-command-suggestions + (fn [{:keys [current-chat-id] :as db} _] + (let [suggestions? (seq (get-in db [:command-suggestions current-chat-id])) + current (get-in db [:animations :command-suggestions-height]) + height (if suggestions? middle-height 0.1)] + (-> db + (update :animations assoc + :messages-offset? suggestions? + :messages-offset-max 22 + :command-suggestions-height height) + (update-in [:animations :commands-height-changed] + (if (and suggestions? (not= 0.1 current)) + identity inc)))))) + +(animation-handler :animate-show-response [(after #(dispatch [:command-edit-mode]))] - (fn [db _] - (-> db - (assoc-in [:animations :messages-offset] request-info-height) - (update-response-height)))) + (fn [db] + (assoc db :messages-offset? true + :messages-offset-max request-info-height + :to-response-height response-height))) -(animation-handler :set-response-max-height - (fn [db [_ height]] - (let [prev-height (:response-height-max db)] - (if (not= height prev-height) - (let [db (assoc db :response-height-max height)] - (if (= prev-height (:to-response-height db)) - (assoc db :to-response-height height) - db)) - db)))) - -(register-handler :fix-response-height +(defn fix-height + [height-key height-signal-key suggestions-key minimum] (fn [{:keys [current-chat-id] :as db} [_ vy current]] - (let [max-height (get-in db [:animations :response-height-max]) + (let [max-height (get-in db [:layout-height]) moving-down? (pos? vy) moving-up? (not moving-down?) under-middle-position? (<= current middle-height) over-middle-position? (not under-middle-position?) - suggestions (get-in db [:suggestions current-chat-id]) + suggestions (get-in db [suggestions-key current-chat-id]) new-fixed (cond (not suggestions) - minimum-suggestion-height + minimum (and under-middle-position? moving-up?) middle-height @@ -70,7 +71,20 @@ (and under-middle-position? moving-down?) - minimum-suggestion-height)] + minimum)] + (println height-key new-fixed) (-> db - (assoc-in [:animations :to-response-height] new-fixed) - (update-in [:animations :response-height-changed] inc))))) + (assoc-in [:animations height-key] new-fixed) + (update-in [:animations height-signal-key] inc))))) + +(register-handler :fix-commands-suggestions-height + (fix-height :command-suggestions-height + :commands-height-changed + :command-suggestions + minimum-command-suggestions-height)) + +(register-handler :fix-response-height + (fix-height :to-response-height + :response-height-changed + :suggestions + minimum-suggestion-height)) diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index f9394aeb5a..71718746cf 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -18,7 +18,7 @@ [status-im.components.invertible-scroll-view :refer [invertible-scroll-view]] [status-im.components.toolbar :refer [toolbar]] [status-im.chat.views.message :refer [chat-message]] - [status-im.chat.views.suggestions :refer [suggestions-view]] + [status-im.chat.views.suggestions :refer [suggestion-container]] [status-im.chat.views.response :refer [response-view]] [status-im.chat.views.new-message :refer [chat-message-new]] [status-im.i18n :refer [label label-pluralize]] @@ -228,20 +228,19 @@ :keyboardShouldPersistTaps true :dataSource (to-datasource-inverted messages)}])) -(defn messages-container-animation-logic [{:keys [to-value val]}] +(defn messages-container-animation-logic + [{:keys [offset? val max]}] (fn [_] - (let [to-value @to-value] - (anim/start (anim/spring val {:toValue to-value}) - (fn [arg] - (when (.-finished arg) - (dispatch [:set-animation ::messages-offset-current to-value]))))))) + (let [to-value (if @offset? @max 0)] + (anim/start (anim/spring val {:toValue to-value}))))) (defn messages-container [messages] - (let [to-messages-offset (subscribe [:animations :messages-offset]) - cur-messages-offset (subscribe [:animations ::messages-offset-current]) - messages-offset (anim/create-value (or @cur-messages-offset 0)) - context {:to-value to-messages-offset - :val messages-offset} + (let [messages-offset? (subscribe [:animations :messages-offset?]) + maximum-offset (subscribe [:animations :messages-offset-max]) + messages-offset (anim/create-value 0) + context {:offset? messages-offset? + :val messages-offset + :max maximum-offset} on-update (messages-container-animation-logic context)] (r/create-class {:component-did-mount @@ -250,7 +249,7 @@ on-update :reagent-render (fn [messages] - @to-messages-offset + @messages-offset? [animated-view {:style (st/messages-container messages-offset)} messages])}))) @@ -259,16 +258,19 @@ show-actions-atom [:show-actions] command [:get-chat-command] command? [:command?] - to-msg-id [:get-chat-command-to-msg-id]] - [view {:style st/chat-view + suggestions [:get-suggestions] + to-msg-id [:get-chat-command-to-msg-id] + layout-height [:get :layout-height]] + [view {:style st/chat-view :onLayout (fn [event] (let [height (.. event -nativeEvent -layout -height)] - (dispatch [:set-response-max-height height])))} + (when (not= height layout-height) + (dispatch [:set :layout-height height]))))} [chat-toolbar] [messages-container [messages-view group-chat]] (when group-chat [typing-all]) [response-view] - (when-not command? [suggestions-view]) + (when-not command? [suggestion-container]) [chat-message-new] (when show-actions-atom [actions-view])]) diff --git a/src/status_im/chat/styles/suggestions.cljs b/src/status_im/chat/styles/suggestions.cljs index 0c35347f79..2d1d89525f 100644 --- a/src/status_im/chat/styles/suggestions.cljs +++ b/src/status_im/chat/styles/suggestions.cljs @@ -1,16 +1,16 @@ (ns status-im.chat.styles.suggestions (:require [status-im.components.styles :refer [font - color-light-blue-transparent - color-white - color-black - color-blue - color-blue-transparent - selected-message-color - online-color - separator-color - text1-color - text2-color - text3-color]])) + color-light-blue-transparent + color-white + color-black + color-blue + color-blue-transparent + selected-message-color + online-color + separator-color + text1-color + text2-color + text3-color]])) (def suggestion-height 88) @@ -59,11 +59,19 @@ :backgroundColor color-white :borderRadius 5}) -(def container - {:backgroundColor color-white}) +(defn container [height] + {:flexDirection :column + :position :absolute + :left 0 + :right 0 + :bottom 0 + :height height + :backgroundColor color-white + :elevation 2}) (def drag-down-touchable {:height 22 + :background-color color-white :alignItems :center :justifyContent :center}) diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index 20bcf239ce..4d197b1aad 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -43,11 +43,8 @@ (register-sub :get-suggestions (fn [db _] - (let [input-text (->> (:current-chat-id @db) - db/chat-input-text-path - (get-in @db) - (reaction))] - (reaction (get-suggestions @db @input-text))))) + (let [chat-id (subscribe [:get-current-chat-id])] + (reaction (get-in @db [:command-suggestions @chat-id]))))) (register-sub :get-commands (fn [db _] diff --git a/src/status_im/chat/views/new_message.cljs b/src/status_im/chat/views/new_message.cljs index 67280885c4..1434651b1f 100644 --- a/src/status_im/chat/views/new_message.cljs +++ b/src/status_im/chat/views/new_message.cljs @@ -21,19 +21,19 @@ command? [:command?]] [plain-message-input-view (when command? - (case (:command command) + (case (keyword (:name command)) :phone {:input-options {:keyboardType :phone-pad} :validator valid-mobile-number?} :keypair {:input-options {:secureTextEntry true}} :confirmation-code {:input-options {:keyboardType :numeric}} :money {:input-options {:keyboardType :numeric}} :request {:input-options {:keyboardType :numeric}} - ;; todo maybe nil is finr for now :) + ;; todo maybe nil is fine for now :) nil #_(throw (js/Error. "Uknown command type"))))]) (defview chat-message-new [] [staged-commands [:get-chat-staged-commands]] [view st/new-message-container - (when (and staged-commands (pos? (count staged-commands))) + (when (seq staged-commands) [staged-commands-view staged-commands]) [show-input]]) diff --git a/src/status_im/chat/views/plain_message.cljs b/src/status_im/chat/views/plain_message.cljs index f9abe83f25..12ccadd664 100644 --- a/src/status_im/chat/views/plain_message.cljs +++ b/src/status_im/chat/views/plain_message.cljs @@ -52,7 +52,7 @@ on-update :reagent-render (fn [] - [touchable-highlight {:on-press #(dispatch [:switch-command-suggestions]) + [touchable-highlight {:on-press #(dispatch [:switch-command-suggestions!]) :disabled @command?} [animated-view {:style (st/message-input-button-touchable container-width)} diff --git a/src/status_im/chat/views/suggestions.cljs b/src/status_im/chat/views/suggestions.cljs index 202150423f..3eba75a4ea 100644 --- a/src/status_im/chat/views/suggestions.cljs +++ b/src/status_im/chat/views/suggestions.cljs @@ -6,9 +6,14 @@ icon touchable-highlight list-view - list-item]] + list-item + animated-view]] [status-im.utils.listview :refer [to-datasource]] - [status-im.chat.styles.suggestions :as st])) + [status-im.chat.styles.suggestions :as st] + [reagent.core :as r] + [status-im.components.animation :as anim] + [status-im.components.drag-drop :as drag] + [status-im.components.react :as react])) (defn set-command-input [command] (dispatch [:set-chat-command command])) @@ -31,18 +36,89 @@ (list-item [suggestion-list-item row])) -(defview suggestions-view [] - [suggestions [:get-suggestions]] - (when (seq suggestions) - [view st/container - [touchable-highlight {:style st/drag-down-touchable - :onPress (fn [] - ;; TODO hide suggestions? - )} +(defn suggestions-view [] + (let + [suggestions (subscribe [:get-suggestions])] + (r/create-class + {:reagent-render + (fn [] + [view (st/suggestions-container (count @suggestions)) + [list-view {:dataSource (to-datasource @suggestions) + :enableEmptySections true + :keyboardShouldPersistTaps true + :renderRow render-row}]])}))) + +;; todo bad name. Ideas? +(defn enough-dy [gesture] + (> (Math/abs (.-dy gesture)) 10)) + +(defn on-move [response-height kb-height orientation] + (fn [_ gesture] + (when (enough-dy gesture) + (let [w (react/get-dimensions "window") + ;; depending on orientation use height or width of screen + prop (if (= :portrait @orientation) + :height + :width) + ;; subtract keyboard height to get "real height" of screen + ;; then subtract gesture position to get suggestions height + ;; todo maybe it is better to use margin-top instead height + ;; it is not obvious + to-value (- (prop w) @kb-height (.-moveY gesture))] + (anim/start + (anim/spring response-height {:toValue to-value})))))) + +(defn on-release [response-height] + (fn [_ gesture] + (when (enough-dy gesture) + (dispatch [:fix-commands-suggestions-height + (.-vy gesture) + ;; todo access to "private" property + ;; better to find another way... + (.-_value response-height)])))) + +(defn pan-responder [response-height kb-height orientation] + (drag/create-pan-responder + {:on-move (on-move response-height kb-height orientation) + :on-release (on-release response-height)})) + +(defn header [h] + (let [orientation (subscribe [:get :orientation]) + kb-height (subscribe [:get :keyboard-height]) + pan-responder (pan-responder h kb-height orientation)] + (fn [_] [view - [icon :drag_down st/drag-down-icon]]] - [view (st/suggestions-container (count suggestions)) - [list-view {:dataSource (to-datasource suggestions) - :enableEmptySections true - :keyboardShouldPersistTaps true - :renderRow render-row}]]])) + (merge (drag/pan-handlers pan-responder) + {:style st/drag-down-touchable}) + [icon :drag_down st/drag-down-icon]]))) + +(defn container-animation-logic [{:keys [to-value val]}] + (fn [_] + (let [to-value @to-value] + (anim/start (anim/spring val {:toValue to-value + :tension 50 + :friction 10}))))) + +(defn container [h & elements] + (let [;; todo to-response-height, cur-response-height must be specific + ;; for each chat + to-response-height (subscribe [:animations :command-suggestions-height]) + changed (subscribe [:animations :commands-height-changed]) + context {:to-value to-response-height + :val h} + on-update (container-animation-logic context)] + (r/create-class + {:component-did-mount + on-update + :component-did-update + on-update + :reagent-render + (fn [h & elements] + @changed + (into [animated-view {:style (st/container h)}] elements))}))) + +(defn suggestion-container [] + (let [h (anim/create-value 0)] + [container h + [header h] + [suggestions-view] ])) diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 7c07c77636..08f3e8abf0 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -38,7 +38,6 @@ :phone-number ""} :disable-group-creation false :animations {:to-response-height 0.1 - :messages-offset 0 ;; todo clear this :tabs-bar-value (anim/create-value 0)}})