diff --git a/.re-natal b/.re-natal index 1e46c72dab..d64f30c702 100644 --- a/.re-natal +++ b/.re-natal @@ -34,7 +34,8 @@ "eccjs", "chance", "react-native-swiper", - "react-native-share" + "react-native-share", + "react-native-emoji-picker" ], "imageDirs": [ "images" diff --git a/package.json b/package.json index 47bcb0dde1..9c84b98aac 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react-native-crypto": "^2.0.1", "react-native-dialogs": "0.0.16", "react-native-drawer-layout": "^1.1.0", + "react-native-emoji-picker": "^0.2.2", "react-native-fs": "^1.5.1", "react-native-http": "github:tradle/react-native-http#834492d", "react-native-i18n": "0.0.8", diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 385fe4026f..81b5086b07 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -77,7 +77,8 @@ (fn [e] (let [h (.. e -endCoordinates -height)] (when-not (= h @keyboard-height) - (dispatch [:set :keyboard-height h]))))) + (dispatch [:set :keyboard-height h]) + (dispatch [:set :keyboard-max-height h]))))) (.addListener keyboard "keyboardDidHide" #(when-not (= 0 @keyboard-height) diff --git a/src/status_im/chat/constants.cljs b/src/status_im/chat/constants.cljs index 8a7499dd48..e34f89c8b0 100644 --- a/src/status_im/chat/constants.cljs +++ b/src/status_im/chat/constants.cljs @@ -12,3 +12,5 @@ (def suggestions-header-height 22) (def minimum-command-suggestions-height (+ input-height suggestions-header-height)) + +(def emoji-container-height 250) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index a2a1072ede..34b820387c 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -2,7 +2,7 @@ (:require-macros [cljs.core.async.macros :as am]) (:require [re-frame.core :refer [enrich after debug dispatch]] [status-im.models.commands :as commands] - [clojure.string :as str] + [clojure.string :as string] [status-im.components.styles :refer [default-chat-color]] [status-im.chat.suggestions :as suggestions] [status-im.protocol.core :as protocol] @@ -46,6 +46,10 @@ (fn [db [_ ui-element value]] (assoc-in db [:chat-ui-props ui-element] value))) +(register-handler :toggle-chat-ui-props + (fn [{:keys [chat-ui-props] :as db} [_ ui-element]] + (assoc-in db [:chat-ui-props ui-element] (not (ui-element chat-ui-props))))) + (register-handler :set-show-info (fn [db [_ show-info]] (assoc db :show-info show-info))) @@ -54,6 +58,7 @@ (u/side-effect! (fn [_ [_ details]] (dispatch [:set-chat-ui-props :show-bottom-info? true]) + (dispatch [:set-chat-ui-props :show-emoji? false]) (dispatch [:set-chat-ui-props :bottom-info details])))) (register-handler :load-more-messages @@ -78,7 +83,7 @@ (defn safe-trim [s] (when (string? s) - (str/trim s))) + (string/trim s))) (register-handler :cancel-command (fn [{:keys [current-chat-id] :as db} _] @@ -165,11 +170,16 @@ (u/side-effect! (fn [{:keys [current-chat-id] :as db} [_ text]] (let [{:keys [dapp?] :as contact} (get-in db [:contacts current-chat-id])] - (log/debug "SET CHAT INPUT TEXT: " current-chat-id text contact dapp?) (if (console? current-chat-id) (dispatch [::check-input-for-commands text]) (dispatch [::check-suggestions current-chat-id text])))))) +(register-handler :add-to-chat-input-text + (u/side-effect! + (fn [{:keys [chats current-chat-id] :as db} [_ text-to-add]] + (let [input-text (get-in chats [current-chat-id :input-text])] + (dispatch [:set-chat-input-text (str input-text text-to-add)]))))) + (def possible-commands {[:confirmation-code :responses] #(re-matches #"^[\d]{4}$" %) [:phone :commands] valid-mobile-number?}) diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index 2523388f7f..7b8259a648 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -25,6 +25,7 @@ [status-im.chat.views.new-message :refer [chat-message-input-view]] [status-im.chat.views.staged-commands :refer [staged-commands-view]] [status-im.chat.views.actions :refer [actions-view]] + [status-im.chat.views.emoji :refer [emoji-view]] [status-im.chat.views.bottom-info :refer [bottom-info-view]] [status-im.chat.views.toolbar-content :refer [toolbar-content-view]] [status-im.chat.views.suggestions :refer [suggestion-container]] @@ -184,6 +185,7 @@ [group-chat [:chat :group-chat] show-actions? [:chat-ui-props :show-actions?] show-bottom-info? [:chat-ui-props :show-bottom-info?] + show-emoji? [:chat-ui-props :show-emoji?] command? [:command?] staged-commands [:get-chat-staged-commands] layout-height [:get :layout-height]] @@ -203,6 +205,8 @@ (when-not command? [suggestion-container]) [response-view] + (when show-emoji? + [emoji-view]) [chat-message-input-view] (when show-actions? [actions-view]) diff --git a/src/status_im/chat/styles/emoji.cljs b/src/status_im/chat/styles/emoji.cljs new file mode 100644 index 0000000000..0c17d7236b --- /dev/null +++ b/src/status_im/chat/styles/emoji.cljs @@ -0,0 +1,23 @@ +(ns status-im.chat.styles.emoji + (:require [status-im.components.styles :refer [color-white]] + [status-im.chat.constants :refer [emoji-container-height]] + [taoensso.timbre :as log])) + +(def container-height emoji-container-height) + +(defn container [height] + {:flexDirection :column + :position :absolute + :left 0 + :right 0 + :bottom 0 + :height (or height emoji-container-height) + :backgroundColor color-white + :elevation 5}) + +(def emoji-container + {:flex 1}) + +(def emoji-picker + {:flex 1 + :background-color color-white}) diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index 0a21c757f6..e414d3f4c3 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -277,13 +277,16 @@ (register-sub :input-margin (fn [] - (let [kb-height (subscribe [:get :keyboard-height]) - focused (subscribe [:get :focused]) - mode (subscribe [:kb-mode])] + (let [kb-height (subscribe [:get :keyboard-height]) + focused (subscribe [:get :focused]) + mode (subscribe [:kb-mode]) + kb-max (subscribe [:get :keyboard-max-height]) + show-emoji? (subscribe [:chat-ui-props :show-emoji?])] (reaction - (cond ios? @kb-height - (and @focused (= :pan @mode) (pos? @kb-height)) 20 - :else 0))))) + (cond @show-emoji? (or @kb-max c/emoji-container-height) + ios? @kb-height + (and @focused (= :pan @mode) (pos? @kb-height)) 20 + :else 0))))) (register-sub :max-layout-height (fn [db [_ status-bar]] diff --git a/src/status_im/chat/views/emoji.cljs b/src/status_im/chat/views/emoji.cljs new file mode 100644 index 0000000000..fb7b07c752 --- /dev/null +++ b/src/status_im/chat/views/emoji.cljs @@ -0,0 +1,21 @@ +(ns status-im.chat.views.emoji + (: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 + text + icon + emoji-picker]] + [status-im.chat.styles.emoji :as st] + [status-im.components.animation :as anim] + [status-im.chat.suggestions-responder :as resp] + [status-im.chat.constants :as c] + [status-im.i18n :refer [label]])) + +(defview emoji-view [] + [keyboard-max-height [:get :keyboard-max-height]] + [view {:style (st/container keyboard-max-height)} + [view st/emoji-container + [emoji-picker {:style st/emoji-picker + :hideClearButton true + :onEmojiSelected #(dispatch [:add-to-chat-input-text %])}]]]) diff --git a/src/status_im/chat/views/message_input.cljs b/src/status_im/chat/views/message_input.cljs index b9db1e67bc..49ad30f116 100644 --- a/src/status_im/chat/views/message_input.cljs +++ b/src/status_im/chat/views/message_input.cljs @@ -47,12 +47,13 @@ :auto-focus false :blur-on-submit true :multiline true - :on-change #(let [size (-> (.-nativeEvent %) + :on-content-size-change #(let [size (-> (.-nativeEvent %) (.-contentSize) (.-height))] - (set-layout-size size)) + (set-layout-size size)) :accessibility-label :input - :on-focus #(dispatch [:set :focused true]) + :on-focus #(do (dispatch [:set :focused true]) + (dispatch [:set-chat-ui-props :show-emoji? false])) :on-blur #(do (dispatch [:set :focused false]) (set-layout-size 0)) :default-value (or input-message "")} @@ -75,7 +76,7 @@ (defn plain-message-get-initial-state [_] {:height 0}) -(defn plain-message-render [_] +(defn plain-message-input-view [_] (let [command? (subscribe [:command?]) command (subscribe [:get-chat-command]) input-command (subscribe [:get-chat-command-content]) @@ -84,7 +85,9 @@ component (r/current-component) set-layout-size #(r/set-state component {:height %})] (r/create-class - {:component-will-update + {:get-initial-state + plain-message-get-initial-state + :component-will-update (fn [_] (when (or (and @command? (str/blank? @input-command)) (and (not @command?) (not @input-message))) @@ -99,20 +102,14 @@ (if @command? [command-input input-options @command] [message-input input-options set-layout-size])] - ;; TODO emoticons: not implemented [plain-message/smile-button height] (when (or (and @command? (not (str/blank? @input-command))) @valid-plain-message?) (let [on-press (if @command? (on-press-commands-handler @command) plain-message/send)] - [send-button {:on-press #(on-press %) - :accessibility-label :send-message}])) + [send-button {:on-press #(do (dispatch [:set-chat-ui-props :show-emoji? false]) + (on-press %))}])) (when (and @command? (= :command (:type @command))) [command/command-icon @command])]]))}))) -(defn plain-message-input-view [_] - (r/create-class {:get-initial-state plain-message-get-initial-state - :reagent-render plain-message-render})) - - diff --git a/src/status_im/chat/views/plain_message.cljs b/src/status_im/chat/views/plain_message.cljs index 699d02e531..24e0c8ed4f 100644 --- a/src/status_im/chat/views/plain_message.cljs +++ b/src/status_im/chat/views/plain_message.cljs @@ -6,7 +6,8 @@ animated-view icon text - touchable-highlight]] + touchable-highlight + dismiss-keyboard!]] [status-im.components.animation :as anim] [status-im.chat.styles.plain-message :as st] [status-im.constants :refer [response-input-hiding-duration]])) @@ -56,7 +57,8 @@ on-update :reagent-render (fn [height on-press] - [touchable-highlight {:on-press #(do (dispatch [:switch-command-suggestions!]) + [touchable-highlight {:on-press #(do (dispatch [:set-chat-ui-props :show-emoji? false]) + (dispatch [:switch-command-suggestions!]) (on-press)) :disabled @command?} [animated-view {:style (st/message-input-button-touchable container-width height)} @@ -97,9 +99,8 @@ on-update :reagent-render (fn [] - [touchable-highlight {:on-press (fn [] - ;; TODO emoticons: not implemented - ) + [touchable-highlight {:on-press #(do (dispatch [:toggle-chat-ui-props :show-emoji?]) + (dismiss-keyboard!)) :disabled @command?} [animated-view {:style (st/message-input-button-touchable container-width height)} [animated-view {:style (st/message-input-button buttons-scale 16)} diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index 73593dec59..30d3b5f7c4 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -123,3 +123,12 @@ (defn copy-to-clipboard [text] (.setString (.-Clipboard react-native) text)) + + +;; Emoji + +(def emoji-picker-class (js/require "react-native-emoji-picker")) + +(def emoji-picker + (let [emoji-picker (.-default emoji-picker-class)] + (r/adapt-react-class emoji-picker))) diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 3d5ed73da5..01888221d6 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -64,7 +64,8 @@ (fn [e] (let [h (.. e -endCoordinates -height)] (when-not (= h @keyboard-height) - (dispatch [:set :keyboard-height h]))))) + (dispatch [:set :keyboard-height h]) + (dispatch [:set :keyboard-max-height h]))))) (.addListener keyboard "keyboardWillHide" #(when-not (= 0 @keyboard-height)