diff --git a/.re-natal b/.re-natal index a547f09695..75b59a0481 100644 --- a/.re-natal +++ b/.re-natal @@ -1,7 +1,7 @@ { "name": "StatusIm", "interface": "reagent", - "androidHost": "10.0.3.2", + "androidHost": "localhost", "modules": [ "react-native-contacts", "react-native-invertible-scroll-view", @@ -19,6 +19,7 @@ "react-native-android-sms-listener", "react-native-camera", "react-native-qrcode", + "react-native-orientation", "identicon.js" ], "imageDirs": [ @@ -29,4 +30,4 @@ "dev": "env/dev", "prod": "env/prod" } -} \ No newline at end of file +} diff --git a/android/app/build.gradle b/android/app/build.gradle index 21e197ea42..7202b12494 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -131,6 +131,7 @@ dependencies { compile project(':react-native-linear-gradient') compile project(':ReactNativeAndroidSmsListener') compile project(':react-native-camera') + compile project(':react-native-orientation') // compile(name:'geth', ext:'aar') compile(group: 'status-im', name: 'android-geth', version: '1.4.0-201604110816-a97a114', ext: 'aar') diff --git a/android/app/src/main/java/com/statusim/MainActivity.java b/android/app/src/main/java/com/statusim/MainActivity.java index 341732d5d7..ee5ff65fd1 100644 --- a/android/app/src/main/java/com/statusim/MainActivity.java +++ b/android/app/src/main/java/com/statusim/MainActivity.java @@ -23,6 +23,7 @@ import android.content.Context; import com.bitgo.randombytes.RandomBytesPackage; import com.BV.LinearGradient.LinearGradientPackage; import com.centaurwarchief.smslistener.SmsListener; +import com.github.yamill.orientation.OrientationPackage; import android.util.Log; @@ -35,7 +36,8 @@ import java.io.File; import com.lwansbrough.RCTCamera.*; import com.i18n.reactnativei18n.ReactNativeI18n; import io.realm.react.RealmReactPackage; - +import android.content.Intent; +import android.content.res.Configuration; public class MainActivity extends ReactActivity { @@ -181,7 +183,16 @@ public class MainActivity extends ReactActivity { new RandomBytesPackage(), new LinearGradientPackage(), new RCTCameraPackage(), - new SmsListener(this) + new SmsListener(this), + new OrientationPackage(this) ); } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Intent intent = new Intent("onConfigurationChanged"); + intent.putExtra("newConfig", newConfig); + this.sendBroadcast(intent); + } } diff --git a/android/settings.gradle b/android/settings.gradle index 906ece37bc..ee6b7c66b3 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -20,3 +20,5 @@ include ':ReactNativeAndroidSmsListener' project(':ReactNativeAndroidSmsListener').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-sms-listener/android') include ':react-native-camera' project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android') +include ':react-native-orientation', ':app' +project(':react-native-orientation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation/android') diff --git a/package.json b/package.json index b8c7a1a2a8..d3c2cf30db 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "react-native-qrcode": "^0.2.2", "react-native-randombytes": "^2.1.0", "react-native-vector-icons": "^1.3.4", + "react-native-orientation": "^1.17.0", "realm": "^0.11.1" } } diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 52c7cee85e..0e1e22c930 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -5,7 +5,8 @@ [re-frame.core :refer [subscribe dispatch dispatch-sync]] [status-im.handlers] [status-im.subs] - [status-im.components.react :refer [navigator app-registry]] + [status-im.components.react :refer [navigator app-registry device-event-emitter + orientation]] [status-im.components.main-tabs :refer [main-tabs]] [status-im.contacts.views.contact-list :refer [contact-list] ] [status-im.contacts.views.new-contact :refer [new-contact]] @@ -33,25 +34,45 @@ true)))] (add-event-listener "hardwareBackPress" new-listener))) +(defn orientation->keyword [o] + (keyword (.toLowerCase o))) + (defn app-root [] (let [signed-up (subscribe [:get :signed-up]) view-id (subscribe [:get :view-id])] - (fn [] - (case (if @signed-up @view-id :chat) - :discovery [main-tabs] - :discovery-tag [discovery-tag] - :add-participants [new-participants] - :remove-participants [remove-participants] - :chat-list [main-tabs] - :new-group [new-group] - :group-settings [group-settings] - :contact-list [main-tabs] - :group-contacts [contact-list] - :new-contact [new-contact] - :qr-scanner [qr-scanner] - :chat [chat] - :profile [profile] - :my-profile [my-profile])))) + (r/create-class + {:component-will-mount + (fn [] + (let [o (orientation->keyword (.getInitialOrientation orientation))] + (dispatch [:set :orientation o])) + (.addOrientationListener + orientation + #(dispatch [:set :orientation (orientation->keyword %)])) + (.addListener device-event-emitter + "keyboardDidShow" + (fn [e] + (let [h (.. e -endCoordinates -height)] + (dispatch [:set :keyboard-height h])))) + (.addListener device-event-emitter + "keyboardDidHide" + #(dispatch [:set :keyboard-height 0]))) + :render + (fn [] + (case (if @signed-up @view-id :chat) + :discovery [main-tabs] + :discovery-tag [discovery-tag] + :add-participants [new-participants] + :remove-participants [remove-participants] + :chat-list [main-tabs] + :new-group [new-group] + :group-settings [group-settings] + :contact-list [main-tabs] + :group-contacts [contact-list] + :new-contact [new-contact] + :qr-scanner [qr-scanner] + :chat [chat] + :profile [profile] + :my-profile [my-profile]))}))) (defn init [] (dispatch-sync [:initialize-db]) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 9ec8b78858..ae8cdd5dc0 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -48,16 +48,9 @@ (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]))))) - -(defn animate-set-chat-command-content [db _] - (when (commands/get-chat-command-to-msg-id db) - (dispatch [:animate-response-resize]))) + (dispatch [:animate-cancel-command])))) (register-handler :set-chat-command-content - (after animate-set-chat-command-content) (fn [{:keys [current-chat-id] :as db} [_ content]] (as-> db db (commands/set-chat-command-content db content) @@ -78,7 +71,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]] @@ -91,7 +86,8 @@ (.blur message-input))))) (register-handler :set-response-chat-command - (after #(dispatch [:animate-show-response])) + [(after #(dispatch [:command-edit-mode])) + (after #(dispatch [:animate-show-response]))] (fn [db [_ to-msg-id command-key]] (commands/set-response-chat-command db to-msg-id command-key))) @@ -253,8 +249,9 @@ (commands/unstage-command db staged-command))) (register-handler :set-chat-command + [(after #(dispatch [:command-edit-mode])) + (after #(dispatch [:animate-show-response]))] (fn [db [_ command-key]] - ;; todo what is going on there?! (commands/set-chat-command db command-key))) (register-handler :init-console-chat @@ -431,3 +428,13 @@ ;((after leaving-message!)) ((after delete-messages!)) ((after delete-chat!)))) + +(defn edit-mode-handler [mode] + (fn [{:keys [current-chat-id] :as db} _] + (assoc-in db [:edit-mode current-chat-id] mode))) + +(register-handler :command-edit-mode + (edit-mode-handler :command)) + +(register-handler :text-edit-mode + (edit-mode-handler :text)) diff --git a/src/status_im/chat/handlers/animation.cljs b/src/status_im/chat/handlers/animation.cljs index 2859261ab3..994a32e85f 100644 --- a/src/status_im/chat/handlers/animation.cljs +++ b/src/status_im/chat/handlers/animation.cljs @@ -15,34 +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 + (after #(dispatch [:text-edit-mode])) (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))) - -(animation-handler :finish-animate-response-resize - (fn [db _] - (let [fixed (:to-response-height db)] - (assoc db :response-height-current fixed - :response-resize? false)))) - -(animation-handler :set-response-height - (fn [db [_ value]] - (assoc db :response-height-current value))) - -(animation-handler :animate-response-resize - (fn [db _] - (assoc db :response-resize? true))) + (assoc db + :to-response-height zero-height + :messages-offset 0))) (defn get-response-height [db] (let [command (commands/get-chat-command db) @@ -58,18 +36,10 @@ (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])) + (after #(dispatch [:command-edit-mode])) (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)))) @@ -79,33 +49,31 @@ (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 - :response-height-current height) + (assoc db :to-response-height height) db)) db)))) -(animation-handler :on-drag-response - (fn [db [_ dy]] - (let [fixed (:to-response-height db)] - (assoc db :response-height-current (- fixed dy) - :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 [_ 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/screen.cljs b/src/status_im/chat/screen.cljs index feb88de74e..4927858f1e 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -259,6 +259,7 @@ [group-chat [:chat :group-chat] 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 :onLayout (fn [event] @@ -268,9 +269,7 @@ [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]) + [response-view] + (when-not command? [suggestions-view]) [chat-message-new] (when show-actions-atom [actions-view])]) 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/subs.cljs b/src/status_im/chat/subs.cljs index 9b11d29fd0..804085ad4b 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -1,13 +1,15 @@ (ns status-im.chat.subs (:require-macros [reagent.ratom :refer [reaction]]) - (:require [re-frame.core :refer [register-sub dispatch]] + (:require [re-frame.core :refer [register-sub dispatch subscribe]] [status-im.db :as db] ;todo handlers in subs?... [status-im.chat.suggestions :refer [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]])) + [status-im.handlers.content-suggestions :refer [get-content-suggestions]] + [status-im.chat.views.plain-message :as plain-message] + [status-im.chat.views.command :as command])) (register-sub :chat-properties (fn [db [_ properties]] @@ -63,6 +65,18 @@ (get-in @db) (reaction)))) +(register-sub :valid-plain-message? + (fn [_ _] + (let [input-message (subscribe [:get-chat-input-text]) + staged-commands (subscribe [:get-chat-staged-commands])] + (reaction + (plain-message/message-valid? @staged-commands @input-message))))) + +(register-sub :valid-command? + (fn [_ [_ validator]] + (let [input (subscribe [:get-chat-command-content])] + (reaction (command/valid? @input validator))))) + (register-sub :get-chat-command (fn [db _] (reaction (commands/get-chat-command @db)))) @@ -97,3 +111,9 @@ (let [command (reaction (commands/get-chat-command @db)) text (reaction (commands/get-chat-command-content @db))] (reaction (get-content-suggestions @command @text))))) + +(register-sub :command? + (fn [db ] + (->> (get-in @db [:edit-mode (:current-chat-id @db)]) + (= :command) + (reaction)))) 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 e40cfa4f8f..9c5562efce 100644 --- a/src/status_im/chat/views/message_input.cljs +++ b/src/status_im/chat/views/message_input.cljs @@ -1,7 +1,6 @@ (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] + (:require [re-frame.core :refer [subscribe]] [status-im.components.react :refer [view animated-view icon @@ -10,113 +9,58 @@ [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]])) + [status-im.chat.styles.response :as st-response])) -(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]]]) -(defn 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-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 [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 false - :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) - (command/try-send input-command validator)))} - (when command - {:accessibility-label :command-input}) - input-options) - (if message-input? - input-message - input-command)])) +(def plain-input-options + {:style st-message/message-input + :onChangeText plain-message/set-input-message + :onSubmitEditing plain-message/send}) + +(def command-input-options + {:style st-response/command-input + :onChangeText command/set-input-message + :onSubmitEditing command/send-command}) + +(defview message-input [input-options] + [command? [:command?] + input-message [:get-chat-input-text] + input-command [:get-chat-command-content]] + [text-input (merge + (if command? + command-input-options + plain-input-options) + {:autoFocus false + :blurOnSubmit false + :accessibility-label :input} + input-options) + (if command? input-command input-message)]) (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] + [command? [:command?] 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 [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) - :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])))]])) + valid-plain-message? [:valid-plain-message?] + valid-command? [:valid-command? validator]] + [view st/input-container + [view st/input-view + [plain-message/commands-button] + [message-input-container + [message-input input-options validator]] + ;; TODO emoticons: not implemented + [plain-message/smile-button] + (when (if command? valid-command? valid-plain-message?) + (let [on-press (if command? + command/send-command + plain-message/send)] + [send-button {:on-press on-press + :accessibility-label :send-message}]))]]) diff --git a/src/status_im/chat/views/new_message.cljs b/src/status_im/chat/views/new_message.cljs index 3a330d0a0b..cb5865a5d0 100644 --- a/src/status_im/chat/views/new_message.cljs +++ b/src/status_im/chat/views/new_message.cljs @@ -16,9 +16,11 @@ (for [command staged-commands] ^{:key command} [staged-command-view command])]) -(defn show-input [command] +(defview show-input [] + [command [:get-chat-command] + command? [:command?]] [plain-message-input-view - (when command + (when command? (case (:command command) :phone {:input-options {:keyboardType :phone-pad} :validator valid-mobile-number?} @@ -29,9 +31,8 @@ (throw (js/Error. "Uknown command type"))))]) (defview chat-message-new [] - [command [:get-chat-command] - staged-commands [:get-chat-staged-commands]] + [staged-commands [:get-chat-staged-commands]] [view st/new-message-container (when (and staged-commands (pos? (count staged-commands))) [staged-commands-view staged-commands]) - [show-input command]]) + [show-input]]) diff --git a/src/status_im/chat/views/plain_message.cljs b/src/status_im/chat/views/plain_message.cljs index 0284e0e25f..69829dae14 100644 --- a/src/status_im/chat/views/plain_message.cljs +++ b/src/status_im/chat/views/plain_message.cljs @@ -13,53 +13,37 @@ (defn set-input-message [message] (dispatch [:set-chat-input-text message])) +(defn send [] + (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] - (when (message-valid? staged-commands message) - (dispatch [:send-chat-msg]))) - -(defn prepare-message-input [message-input] - (when message-input - (.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 [: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 @@ -67,24 +51,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 [e] + (when (and @command? (.-finished e)) + (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 [: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 @@ -92,11 +82,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..56382052c8 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,47 @@ ;; 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]))})) +;; todo bad name. Ideas? +(defn enough-dy [gesture] + (> (Math/abs (.-dy gesture)) 10)) -(defn request-info [] - (let [pan-responder (create-response-pan-responder) - command (subscribe [:get-chat-command])] - (fn [] +(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))] + (println to-value ) + (anim/start + (anim/spring response-height {:toValue to-value})))))) + +(defn on-release [response-height] + (fn [_ gesture] + (when (enough-dy gesture) + (dispatch [:fix-response-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 request-info [response-height] + (let [orientation (subscribe [:get :orientation]) + kb-height (subscribe [:get :keyboard-height]) + pan-responder (pan-responder response-height kb-height orientation) + 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 +85,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?]) +(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]) - 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)] + 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/components/react.cljs b/src/status_im/components/react.cljs index 1347f22ea2..f931ce4e00 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -76,3 +76,5 @@ (r/as-element component)) (def dismiss-keyboard! (u/require "dismissKeyboard")) +(def device-event-emitter (.-DeviceEventEmitter react)) +(def orientation (u/require "react-native-orientation")) 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 25772a58fa..7c07c77636 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -37,14 +37,9 @@ :whisper-identity "" :phone-number ""} :disable-group-creation false - :animations {;; mutable data - :to-response-height nil - :response-height-current nil - :message-input-offset 0 - :message-input-buttons-scale 1 + :animations {:to-response-height 0.1 :messages-offset 0 - :commands-input-is-switching? false - :response-resize? false + ;; todo clear this :tabs-bar-value (anim/create-value 0)}}) (def protocol-initialized-path [:protocol-initialized])