Password and phone inputs [chat-ui]

This commit is contained in:
alwx 2017-04-07 01:09:55 +03:00 committed by Roman Volosovskyi
parent 35210f043d
commit 6e4931417b
11 changed files with 293 additions and 242 deletions

View File

@ -19,6 +19,6 @@
:heads-up-display false
:jsload-callback callback)
(rr/enable-re-frisk-remote!)
(rr/enable-re-frisk-remote! {:host "10.0.2.2:4567"})
(core/init)

View File

@ -16,6 +16,6 @@
:heads-up-display false
:jsload-callback #(swap! cnt inc))
(rr/enable-re-frisk-remote!)
(rr/enable-re-frisk-remote! {:host "localhost:4567"})
(core/init)

View File

@ -1,9 +1,11 @@
var TopLevel = {
"abs" : function () {},
"ActionSheetIOS" : function () {},
"addEntropy" : function () {},
"addEventListener" : function () {},
"addListener" : function () {},
"addOrientationListener" : function () {},
"addSymKey" : function () {},
"Alert" : function () {},
"alert" : function () {},
"Animated" : function () {},
@ -81,13 +83,13 @@ var TopLevel = {
"goog" : function () {},
"guid" : function () {},
"hash" : function () {},
"hasSymKey" : function () {},
"headers" : function () {},
"height" : function () {},
"hex" : function () {},
"hide" : function () {},
"HttpProvider" : function () {},
"IBGLog" : function () {},
"indexOf" : function () {},
"initialPage" : function () {},
"initJail" : function () {},
"isAddress" : function () {},
@ -196,6 +198,7 @@ var TopLevel = {
"toAscii" : function () {},
"toBits" : function () {},
"toDecimal" : function () {},
"toHex" : function () {},
"toLocaleString" : function () {},
"toLowerCase" : function () {},
"toNumber" : function () {},

View File

@ -10,7 +10,7 @@ I18n.translations = {
password_description: 'Password',
password_placeholder: 'Type your password',
password_placeholder2: 'Please re-enter password to confirm',
password_placeholder2: 'Confirm',
password_error: 'Password should be not less then 6 symbols.',
password_error1: 'Password confirmation doesn\'t match password.',
password_validation_title: 'Password',
@ -1653,6 +1653,7 @@ var phoneConfig = {
color: "#5bb2a2",
title: I18n.t('phone_title'),
description: I18n.t('phone_description'),
sequentialParams: true,
validator: function (params) {
return {
validationHandler: "phone",
@ -1872,32 +1873,40 @@ status.response({
color: "#7099e6",
description: I18n.t('password_description'),
icon: "lock_white",
params: [{
name: "password",
type: status.types.PASSWORD,
placeholder: I18n.t('password_placeholder'),
hidden: true
}, {
name: "password_confirmation",
type: status.types.PASSWORD,
placeholder: "Confirm",
hidden: true
}],
sequentialParams: true,
params: [
{
name: "password",
type: status.types.PASSWORD,
placeholder: I18n.t('password_placeholder'),
hidden: true
},
{
name: "password-confirmation",
type: status.types.PASSWORD,
placeholder: I18n.t('password_placeholder2'),
hidden: true
}
],
validator: function (params, context) {
if (params["password_confirmation"] != params["password"]) {
var error = status.components.validationMessage(
I18n.t('password_validation_title'),
I18n.t('password_error1')
);
return {markup: error};
}
if (params.password.length < 6) {
var error = status.components.validationMessage(
I18n.t('password_validation_title'),
I18n.t('password_error')
);
return {markup: error};
if (!params.hasOwnProperty("password-confirmation") || params["password-confirmation"].length === 0) {
if (params.password === null || params.password.length < 6) {
var error = status.components.validationMessage(
I18n.t('password_validation_title'),
I18n.t('password_error')
);
return {markup: error};
}
} else {
if (params.password !== params["password-confirmation"]) {
var error = status.components.validationMessage(
I18n.t('password_validation_title'),
I18n.t('password_error1')
);
return {markup: error};
}
}
},
preview: function (params, context) {
var style = {

View File

@ -36,6 +36,7 @@ Command.prototype.create = function (com) {
this["on-send"] = com.onSend;
this.fullscreen = com.fullscreen;
this.request = com.request;
this["sequential-params"] = com.sequentialParams;
this.addToCatalog();
return this;

View File

@ -3,7 +3,6 @@
[taoensso.timbre :as log]
[status-im.chat.constants :as const]
[status-im.chat.models.input :as input-model]
[status-im.chat.models.password-input :as password-input]
[status-im.chat.models.suggestions :as suggestions]
[status-im.components.react :as react-comp]
[status-im.components.status :as status]
@ -16,27 +15,17 @@
(handlers/register-handler
:set-chat-input-text
(fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]]
(let [chat-id (or chat-id current-chat-id)
selection (get-in chat-ui-props [chat-id :selection])]
(let [chat-id (or chat-id current-chat-id)
ends-with-space? (input-model/text-ends-with-space? text)]
(dispatch [:update-suggestions chat-id text])
(if-let [{command :command} (input-model/selected-chat-command db chat-id text)]
(let [{old-args :args} (input-model/selected-chat-command db chat-id)
text-splitted (input-model/split-command-args text)
new-args (rest text-splitted)
modifiers (input-model/add-modifiers (:params command) new-args)
addition (if (input-model/text-ends-with-space? text)
const/spacing-char)
new-params {:modified-text (str (input-model/apply-modifiers text-splitted modifiers)
addition)
:input-text (str (input-model/make-input-text modifiers
text-splitted
old-args
selection)
addition)}]
(update-in db [:chats chat-id] merge new-params))
(update-in db [:chats chat-id] merge {:input-text text
:modified-text nil})))))
text-splitted (input-model/split-command-args text)
new-args (rest text-splitted)
new-input-text (input-model/make-input-text text-splitted old-args)]
(assoc-in db [:chats chat-id :input-text] new-input-text))
(assoc-in db [:chats chat-id :input-text] text)))))
(handlers/register-handler
:add-to-chat-input-text
@ -58,7 +47,11 @@
(dispatch [:set-chat-ui-props :result-box nil])
(dispatch [:set-chat-ui-props :validation-messages nil])
(dispatch [:load-chat-parameter-box command 0])
(dispatch [:chat-input-focus]))))
(if (:sequential-params command)
(js/setTimeout
#(dispatch [:chat-input-focus :seq-input-ref])
100)
(dispatch [:chat-input-focus :input-ref])))))
(handlers/register-handler
:set-chat-input-metadata
@ -72,22 +65,29 @@
(fn [{:keys [current-chat-id] :as db} [_ [index arg]]]
(let [command (-> (get-in db [:chats current-chat-id :input-text])
(input-model/split-command-args))
command-name (first command)
command-args (into [] (rest command))
command-args (if (< index (count command-args))
(assoc command-args index arg)
(conj command-args arg))]
(dispatch [:set-chat-input-text (str command-name
const/spacing-char
(input-model/join-command-args command-args)
const/spacing-char)])))))
seq-params? (-> (input-model/selected-chat-command db current-chat-id)
(get-in [:command :sequential-params]))]
(if seq-params?
(dispatch [:set-chat-seq-arg-input-text arg])
(let [command-name (first command)
command-args (into [] (rest command))
command-args (if (< index (count command-args))
(assoc command-args index arg)
(conj command-args arg))]
(dispatch [:set-chat-input-text (str command-name
const/spacing-char
(input-model/join-command-args command-args)
const/spacing-char)])))))))
(handlers/register-handler
:chat-input-focus
(handlers/side-effect!
(fn [{:keys [current-chat-id chat-ui-props] :as db}]
(when-let [ref (get-in chat-ui-props [current-chat-id :input-ref])]
(.focus ref)))))
(fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ref]]
(try
(when-let [ref (get-in chat-ui-props [current-chat-id ref])]
(.focus ref))
(catch :default e
(log/debug "Cannot focus the reference"))))))
(handlers/register-handler
:update-suggestions
@ -152,34 +152,35 @@
::proceed-command
(handlers/side-effect!
(fn [db [_ command chat-id]]
(dispatch [::request-command-data
{:command command
:chat-id chat-id
:data-type :validator
:after #(dispatch [::proceed-validation-messages command chat-id %2])}]))))
(let [after-validation #(dispatch [::request-command-data
{:command command
:chat-id chat-id
:data-type :on-send
:after (fn [_ res]
(dispatch [::send-command res command chat-id]))}])]
(dispatch [::request-command-data
{:command command
:chat-id chat-id
:data-type :validator
:after #(dispatch [::proceed-validation-messages
command chat-id %2 after-validation])}])))))
(handlers/register-handler
::proceed-validation-messages
(handlers/side-effect!
(fn [db [_ command chat-id {:keys [markup validationHandler parameters] :as errors}]]
(fn [db [_ command chat-id {:keys [markup validationHandler parameters] :as errors} proceed-fn]]
(let [set-errors #(do (dispatch [:set-chat-ui-props :validation-messages %])
(dispatch [:set-chat-ui-props :sending-in-progress? false]))
proceed #(dispatch [::request-command-data
{:command command
:chat-id chat-id
:data-type :on-send
:after (fn [_ res]
(dispatch [::send-command res command chat-id]))}])]
(dispatch [:set-chat-ui-props :sending-in-progress? false]))]
(cond
markup
(set-errors markup)
validationHandler
(do (dispatch [::execute-validation-handler validationHandler parameters set-errors proceed])
(do (dispatch [::execute-validation-handler validationHandler parameters set-errors proceed-fn])
(dispatch [:set-chat-ui-props :sending-in-progress? false]))
:default
(proceed))))))
(proceed-fn))))))
(handlers/register-handler
::execute-validation-handler
@ -236,11 +237,19 @@
:send-current-message
(handlers/side-effect!
(fn [{:keys [current-chat-id] :as db} [_ chat-id]]
(dispatch [:set-chat-ui-props :sending-in-progress? true])
(let [chat-id (or chat-id current-chat-id)
chat-command (input-model/selected-chat-command db chat-id)]
(if chat-command
chat-command (input-model/selected-chat-command db chat-id)
seq-command? (get-in chat-command [:command :sequential-params])
chat-command (if seq-command?
(let [args (get-in db [:chats chat-id :seq-arguments])]
(assoc chat-command :args args))
(update chat-command :args #(remove str/blank? %)))]
(if (:command chat-command)
(if (= :complete (input-model/command-completion chat-command))
(dispatch [::proceed-command chat-command chat-id])
(do
(dispatch [::proceed-command chat-command chat-id])
(dispatch [:clear-seq-arguments chat-id]))
(let [text (get-in db [:chats chat-id :input-text])]
(dispatch [:set-chat-ui-props :sending-in-progress? false])
(when-not (input-model/text-ends-with-space? text)
@ -261,4 +270,48 @@
params
(fn [{:keys [result] :as data}]
(dispatch [:suggestions-handler {:chat-id chat-id
:result data}])))))))
:result data}])))))))
(handlers/register-handler
:clear-seq-arguments
(fn [{:keys [current-chat-id chats] :as db} [_ chat-id]]
(let [chat-id (or chat-id current-chat-id)]
(-> db
(assoc-in [:chats chat-id :seq-arguments] [])
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
(handlers/register-handler
:update-seq-arguments
(fn [{:keys [current-chat-id chats] :as db} [_ chat-id]]
(let [chat-id (or chat-id current-chat-id)
text (get-in chats [chat-id :seq-argument-input-text])]
(-> db
(update-in [:chats chat-id :seq-arguments] #(into [] (conj % text)))
(assoc-in [:chats chat-id :seq-argument-input-text] nil)))))
(handlers/register-handler
:send-seq-argument
(handlers/side-effect!
(fn [{:keys [current-chat-id chats] :as db} [_ chat-id]]
(let [chat-id (or chat-id current-chat-id)
text (get-in chats [chat-id :seq-argument-input-text])
seq-arguments (get-in db [:chats chat-id :seq-arguments])
command (-> (input-model/selected-chat-command db chat-id)
(assoc :args (into [] (conj seq-arguments text))))
args (get-in chats [chat-id :seq-arguments])
after-validation #(do
(dispatch [:update-seq-arguments chat-id])
(dispatch [:send-current-message]))]
(dispatch [::request-command-data
{:command command
:chat-id chat-id
:data-type :validator
:after #(do
(dispatch [::proceed-validation-messages
command chat-id %2 after-validation]))}])))))
(handlers/register-handler
:set-chat-seq-arg-input-text
(fn [{:keys [current-chat-id] :as db} [_ text chat-id]]
(let [chat-id (or chat-id current-chat-id)]
(assoc-in db [:chats chat-id :seq-argument-input-text] text))))

View File

@ -2,15 +2,15 @@
(:require [clojure.string :as str]
[status-im.components.react :as rc]
[status-im.chat.constants :as const]
[status-im.chat.models.password-input :as password-input]
[status-im.chat.views.input.validation-messages :refer [validation-message]]
[status-im.i18n :as i18n]
[status-im.utils.phone-number :as phone-number]
[taoensso.timbre :as log]))
(defn text-ends-with-space? [text]
(= (str/last-index-of text const/spacing-char)
(dec (count text))))
(when text
(= (str/last-index-of text const/spacing-char)
(dec (count text)))))
(defn possible-chat-actions [db chat-id]
(let [{:keys [commands requests]} (get-in db [:chats chat-id])
@ -25,22 +25,27 @@
(into commands responses)))
(defn split-command-args [command-text]
(let [splitted (str/split command-text const/spacing-char)]
(first
(reduce (fn [[list command-started?] arg]
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
has-quote? (and (= quotes-count 1)
(str/index-of arg const/arg-wrapping-char))
arg (str/replace arg #"\"" "")
new-list (if command-started?
(let [index (dec (count list))]
(update list index str const/spacing-char arg))
(conj list arg))
command-continues? (or (and command-started? (not has-quote?))
(and (not command-started?) has-quote?))]
[new-list command-continues?]))
[[] false]
splitted))))
(let [space? (text-ends-with-space? command-text)
command-text (if space?
(str command-text ".")
command-text)
splitted (cond-> (str/split command-text const/spacing-char)
space? (drop-last))]
(->> splitted
(reduce (fn [[list command-started?] arg]
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
has-quote? (and (= quotes-count 1)
(str/index-of arg const/arg-wrapping-char))
arg (str/replace arg #"\"" "")
new-list (if command-started?
(let [index (dec (count list))]
(update list index str const/spacing-char arg))
(conj list arg))
command-continues? (or (and command-started? (not has-quote?))
(and (not command-started?) has-quote?))]
[new-list command-continues?]))
[[] false])
(first))))
(defn join-command-args [args]
(->> args
@ -54,6 +59,7 @@
([{:keys [current-chat-id] :as db} chat-id input-text]
(let [chat-id (or chat-id current-chat-id)
input-metadata (get-in db [:chats chat-id :input-metadata])
seq-arguments (get-in db [:chats chat-id :seq-arguments])
possible-actions (possible-chat-actions db chat-id)
command-args (split-command-args input-text)
command-name (first command-args)]
@ -66,24 +72,33 @@
:metadata (if (not= :any to-message-id)
(assoc input-metadata :to-message-id to-message-id)
input-metadata)
:args (remove empty? (rest command-args))}))))
:args (if (empty? seq-arguments)
(rest command-args)
seq-arguments)}))))
([{:keys [current-chat-id] :as db} chat-id]
(selected-chat-command db chat-id (get-in db [:chats chat-id :input-text]))))
(defn current-chat-argument-position
[{:keys [args] :as command} input-text]
[{:keys [args] :as command} input-text seq-arguments]
(if command
(let [current (count args)]
(if (= (last input-text) const/spacing-char)
current
(dec current)))
(let [args-count (count args)]
(cond
(:sequential-params command)
(count seq-arguments)
(= (last input-text) const/spacing-char)
args-count
:default
(dec args-count)))
-1))
(defn argument-position [{:keys [current-chat-id] :as db} chat-id]
(let [chat-id (or chat-id current-chat-id)
input-text (get-in db [:chats chat-id :input-text])
seq-arguments (get-in db [:chats chat-id :seq-arguments])
chat-command (selected-chat-command db chat-id)]
(current-chat-argument-position chat-command input-text)))
(current-chat-argument-position chat-command input-text seq-arguments)))
(defn command-completion
([{:keys [current-chat-id] :as db} chat-id]
@ -92,7 +107,8 @@
chat-command (selected-chat-command db chat-id)]
(command-completion chat-command)))
([{:keys [args] :as chat-command}]
(let [params (get-in chat-command [:command :params])
(let [args (remove str/blank? args)
params (get-in chat-command [:command :params])
required-params (remove :optional params)]
(if chat-command
(cond
@ -134,30 +150,6 @@
{:title (i18n/label :t/phone-number)
:description (i18n/label :t/invalid-phone)}]))))
(def text-modifiers
[password-input/modifier])
(defn add-modifiers [params new-args]
(->> new-args
(map-indexed (fn [i arg]
{:position i
:value arg
:modifier (-> (filter
(fn [mod]
((:execute-when mod) (get params i)))
text-modifiers)
(first))}))
(into [])))
(defn apply-modifiers [text-splitted args]
(if-let [{:keys [position modifier]} (first args)]
(if modifier
(let [{:keys [get-modified-text]} modifier
modified-text (get-modified-text text-splitted position)]
(apply-modifiers modified-text (rest args)))
(apply-modifiers text-splitted (rest args)))
(str/join const/spacing-char text-splitted)))
(defn- changed-arg-position [xs ys]
(let [longest (into [] (max-key count xs ys))
shortest (into [] (if (= longest xs) ys xs))]
@ -170,19 +162,15 @@
(remove nil?)
(first))))
(defn make-input-text [modifiers [command & args] old-args selection]
(let [arg-pos (changed-arg-position args old-args)
modifier (get-in modifiers [arg-pos :modifier])
new-arg (if (and arg-pos modifier)
(let [{:keys [make-change]} modifier]
(make-change {:command-name (subs command 1)
:old-args old-args
:new-args args
:arg-pos arg-pos
:selection selection}))
(get (into [] args) arg-pos))
(defn make-input-text [[command & args] old-args]
(let [args (into [] args)
old-args (into [] old-args)
arg-pos (changed-arg-position args old-args)
new-arg (get args arg-pos)
new-args (if arg-pos
(assoc (into [] old-args) arg-pos (when new-arg (str/trim new-arg)))
(assoc old-args arg-pos (when new-arg
(str/trim new-arg)))
old-args)]
(str
command

View File

@ -1,48 +0,0 @@
(ns status-im.chat.models.password-input
(:require [status-im.chat.constants :as const]
[clojure.string :as str]
[taoensso.timbre :as log]))
(defn- get-modified-text [text arg-pos]
(let [hide-fn #(apply str (repeat (count %) const/masking-char))
updated-text (update text (inc arg-pos) hide-fn)]
updated-text))
(defn- get-change [{:keys [command-name old-args new-args arg-pos selection]}]
(let [old-args (into [] old-args)
new-args (into [] new-args)
modification (- (count (get new-args arg-pos))
(count (get old-args arg-pos)))
type (if (> modification 0) :added :removed)
position (-> (:start selection)
(- (inc (count command-name)))
(- (count (str/join const/spacing-char (take arg-pos old-args))))
(- modification)
(- (if (= arg-pos 0) 0 1)))
position (if (= :added type) position (inc position))
symbols-count (.abs js/Math modification)]
{:type type
:position position
:symbols (when (= :added type)
(subs (get new-args arg-pos)
position
(+ position symbols-count)))}))
(defn- make-change [{:keys [command-name old-args new-args arg-pos selection] :as args}]
(let [{:keys [type position symbols] :as c} (get-change args)
make-change #(if (= type :added)
(str (if % (subs % 0 position) "")
symbols
(if % (subs % position) ""))
(str (if % (subs % 0 position) "")
(if % (subs % (+ 1 position (count symbols))) "")))
args (if (= (count old-args) 0)
[const/spacing-char]
(into [] old-args))
updated-args (update args arg-pos make-change)]
(make-change (get args arg-pos))))
(def modifier
{:execute-when :hidden
:make-change make-change
:get-modified-text get-modified-text})

View File

@ -70,10 +70,22 @@
:text-align-vertical :center
:height min-input-height
:align-items :center
:android {:left (+ 18 left)
:android {:left (+ 15 left)
:top -1}
:ios {:line-height min-input-height
:left (+ 15 left)}})
:left (+ 9 left)}})
(defnstyle input-password-text [left]
{:min-width 200
:font-size 14
:position :absolute
:text-align-vertical :center
:height min-input-height
:align-items :center
:android {:left (+ 15 left)
:top 0.5}
:ios {:line-height min-input-height
:left (+ 9 left)}})
(def input-emoji-icon
{:margin-top 7

View File

@ -24,7 +24,6 @@
(reaction))]))
(into {}))))
(register-sub
:chat-ui-props
(fn [db [_ ui-element chat-id]]
@ -87,11 +86,12 @@
(register-sub
:current-chat-argument-position
(fn [db [_ chat-id]]
(let [chat-id (or chat-id (@db :current-chat-id))
command (subscribe [:selected-chat-command chat-id])
input-text (subscribe [:chat :input-text chat-id])]
(let [chat-id (or chat-id (@db :current-chat-id))
command (subscribe [:selected-chat-command chat-id])
input-text (subscribe [:chat :input-text chat-id])
seq-arguments (subscribe [:chat :seq-arguments chat-id])]
(reaction
(input-model/current-chat-argument-position @command @input-text)))))
(input-model/current-chat-argument-position @command @input-text @seq-arguments)))))
(register-sub
:chat-parameter-box

View File

@ -52,36 +52,8 @@
^{:key command-key}
[command-view index command])]]])
(defn- invisible-input [{:keys [set-layout-width value]}]
(let [input-text (subscribe [:chat :input-text])
modified-text (subscribe [:chat :modified-text])]
[text {:style style/invisible-input-text
:on-layout #(let [w (-> (.-nativeEvent %)
(.-layout)
(.-width))]
(set-layout-width w))}
(utils/safe-trim (or @modified-text @input-text ""))]))
(defn- input-helper [_]
(let [input-text (subscribe [:chat :input-text])]
(fn [{:keys [command width]}]
(when-let [placeholder (cond
(= @input-text const/command-char)
(i18n/label :t/type-a-command)
(and command (empty? (:args command)))
(get-in command [:command :params 0 :placeholder])
(and command
(= (count (:args command)) 1)
(input-model/text-ends-with-space? @input-text))
(get-in command [:command :params 1 :placeholder]))]
[text {:style (style/input-helper-text width)}
placeholder]))))
(defn- text-field [_]
(defn- basic-text-input [_]
(let [input-text (subscribe [:chat :input-text])
modified-text (subscribe [:chat :modified-text])
command (subscribe [:selected-chat-command])
sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])]
(fn [{:keys [set-layout-height height]}]
@ -90,7 +62,7 @@
:accessibility-label id/chat-message-input
:blur-on-submit false
:multiline true
:default-value (or @modified-text @input-text "")
:default-value (or @input-text "")
:editable (not @sending-in-progress?)
:on-blur #(do (dispatch [:set-chat-ui-props :input-focused? false])
(set-layout-height 0))
@ -107,21 +79,73 @@
(set-layout-height h))
:on-selection-change #(let [s (-> (.-nativeEvent %)
(.-selection))]
;; This will be a bit tricky:
;; iOS calls onSelectionChange BEFORE onChangeText, while
;; Android calls onChange text first.
;; We need some consistency, so we call the callback with a small delay:
(js/setTimeout
(fn [] (dispatch [:set-chat-ui-props :selection {:start (.-start s)
:end (.-end s)}]))
20))
:on-submit-editing #(do (dispatch [:set-chat-ui-props :sending-in-progress? true])
(dispatch [:send-current-message]))
(when (and (= (.-end s) 10)
(get command [:command :sequential-params]))
(dispatch [:chat-input-focus :seq-input-ref])))
:on-submit-editing #(dispatch [:send-current-message])
:on-focus #(do (dispatch [:set-chat-ui-props :input-focused? true])
(dispatch [:set-chat-ui-props :show-emoji? false]))
:style (style/input-view height)
:placeholder-text-color style/color-input-helper-placeholder}])))
(defn- invisible-input [{:keys [set-layout-width value]}]
(let [input-text (subscribe [:chat :input-text])]
[text {:style style/invisible-input-text
:on-layout #(let [w (-> (.-nativeEvent %)
(.-layout)
(.-width))]
(set-layout-width w))}
(or @input-text "")]))
(defn- input-helper [_]
(let [input-text (subscribe [:chat :input-text])]
(fn [{:keys [command width]}]
(when-not (get-in command [:command :sequential-params])
(let [real-args (remove str/blank? (:args command))]
(when-let [placeholder (cond
(= @input-text const/command-char)
(i18n/label :t/type-a-command)
(and command (empty? real-args))
(get-in command [:command :params 0 :placeholder])
(and command
(= (count real-args) 1)
(input-model/text-ends-with-space? @input-text))
(get-in command [:command :params 1 :placeholder]))]
[text {:style (style/input-helper-text width)}
placeholder]))))))
(defn get-options [type]
(case (keyword type)
:phone {:keyboard-type "phone-pad"}
:password {:secure-text-entry true}
:number {:keyboard-type "numeric"}
nil))
(defn- seq-input [_]
(let [command (subscribe [:selected-chat-command])
arg-pos (subscribe [:current-chat-argument-position])
seq-arg-input-text (subscribe [:chat :seq-argument-input-text])]
(fn [{:keys [command-width]}]
(when (get-in @command [:command :sequential-params])
(let [{:keys [placeholder hidden type]} (get-in @command [:command :params @arg-pos])]
[text-input (merge {:ref #(dispatch [:set-chat-ui-props :seq-input-ref %])
:style (style/input-password-text command-width)
:default-value (or @seq-arg-input-text "")
:on-change-text #(do (dispatch [:set-chat-seq-arg-input-text %])
(dispatch [:set-chat-ui-props :validation-messages nil]))
:secure-text-entry hidden
:placeholder placeholder
:blur-on-submit false
:on-submit-editing (fn []
(when-not (str/blank? @seq-arg-input-text)
(dispatch [:send-seq-argument]))
(js/setTimeout
#(dispatch [:chat-input-focus :seq-input-ref])
100))}
(get-options type))])))))
(defn input-view [_]
(let [component (r/current-component)
set-layout-width #(r/set-state component {:width %})
@ -137,11 +161,12 @@
(let [{:keys [width height]} (r/state component)
command @command]
[animated-view {:style (style/input-root height anim-margin)}
[text-field {:set-layout-height set-layout-height
:height height}]
[basic-text-input {:set-layout-height set-layout-height
:height height}]
[invisible-input {:set-layout-width set-layout-width}]
[input-helper {:command command
:width width}]
[seq-input {:command-width width}]
(if-not command
[touchable-highlight
{:on-press #(do (dispatch [:toggle-chat-ui-props :show-emoji?])
@ -152,21 +177,29 @@
{:on-press #(do (dispatch [:set-chat-input-text nil])
(dispatch [:set-chat-input-metadata nil])
(dispatch [:set-chat-ui-props :result-box nil])
(dispatch [:set-chat-ui-props :validation-messages nil]))}
(dispatch [:set-chat-ui-props :validation-messages nil])
(dispatch [:clear-seq-arguments]))}
[view style/input-clear-container
[icon :close_gray style/input-clear-icon]]])]))})))
(defview input-container [{:keys [anim-margin]}]
[command-completion [:command-completion]
selected-command [:selected-chat-command]
input-text [:chat :input-text]]
input-text [:chat :input-text]
seq-arg-input-text [:chat :seq-argument-input-text]]
[view style/input-container
[input-view {:anim-margin anim-margin}]
(when (and (not (str/blank? input-text))
(or (not selected-command)
(some #{:complete :less-than-needed} [command-completion])))
[touchable-highlight {:on-press #(do (dispatch [:set-chat-ui-props :sending-in-progress? true])
(dispatch [:send-current-message]))}
[touchable-highlight {:on-press #(if (get-in selected-command [:command :sequential-params])
(do
(when-not (str/blank? seq-arg-input-text)
(dispatch [:send-seq-argument]))
(js/setTimeout
(fn [] (dispatch [:chat-input-focus :seq-input-ref]))
100))
(dispatch [:send-current-message]))}
[view style/send-message-container
[icon :arrow_top style/send-message-icon]]])])