[#3366, #3349]: Fixes for expandable, better animations for parameter boxes

Signed-off-by: Julien Eluard <julien.eluard@gmail.com>
This commit is contained in:
alwxndr 2018-02-22 10:54:38 +01:00 committed by Julien Eluard
parent 847795f3a7
commit 64b248268d
No known key found for this signature in database
GPG Key ID: 6FD7DB5437FCBEF6
15 changed files with 196 additions and 417 deletions

View File

@ -1,16 +1,8 @@
var jsSuggestionsContainerStyle = {
keyboardShouldPersistTaps: "always",
backgroundColor: "white",
flexGrow: 1,
bounces: false
};
var jsSuggestionContainerStyle = {
backgroundColor: "white"
};
var jsSubContainerStyle = {
//height: 56,
paddingTop: 9,
borderBottomWidth: 1,
borderBottomColor: "#0000001f"
@ -348,8 +340,7 @@ function jsSuggestions(params, context) {
}
if (sugestionsMarkup.length > 0) {
var view = status.components.scrollView(jsSuggestionsContainerStyle, sugestionsMarkup);
return {markup: view};
return {markup: status.components.view({}, sugestionsMarkup)};
} else {
return {markup: null};
}
@ -473,14 +464,7 @@ function faucetSuggestions(params) {
);
});
var view = status.components.scrollView(
suggestionsContainerStyle,
suggestions
);
var entryHeight = subContainerStyle.height + subContainerStyle.borderBottomWidth;
return {markup: view, height: entryHeight * faucets.length};
return {markup: status.components.view({}, suggestions)};
}
var faucetCommandConfig ={
@ -554,14 +538,7 @@ function debugSuggestions(params) {
);
});
var view = status.components.scrollView(
suggestionsContainerStyle,
suggestions
);
var entryHeight = subContainerStyle.height + subContainerStyle.borderBottomWidth;
return {markup: view, height: entryHeight * values.length};
return {markup: status.components.view({}, suggestions)};
}
status.command({

View File

@ -71,11 +71,11 @@ function amountParameterBox(groupChat, params, context) {
} else {
contactAddress = context.to;
}
var txData;
var amount;
var amountIndex = groupChat ? 1 : 0;
try {
amount = params.args[amountIndex].replace(",", ".");
txData = {
@ -88,7 +88,7 @@ function amountParameterBox(groupChat, params, context) {
to: contactAddress,
value: 0
};
}
}
var sliderValue = params["bot-db"]["sliderValue"] || 0;
@ -109,177 +109,144 @@ function amountParameterBox(groupChat, params, context) {
sliderValue: sliderValue
});
}
return {
title: I18n.t('send_title'),
showBack: true,
markup: status.components.scrollView(
{
keyboardShouldPersistTaps: "always",
bounces: false,
},
[status.components.view(
{
flex: 1
markup: status.components.view({
flex: 1
}, [
status.components.text({
style: {
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingTop: 12,
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 20
}
},
[
status.components.text(
{
I18n.t('send_specify_amount')
),
status.components.touchable(
{
onPress: status.components.dispatch([status.events.FOCUS_INPUT, []])
},
status.components.view({
flexDirection: "row",
alignItems: "center",
textAlign: "center",
justifyContent: "center"
}, [
status.components.text({
font: "light",
numberOfLines: 1,
ellipsizeMode: "tail",
style: {
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingTop: 12,
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 20
maxWidth: 250,
fontSize: 38,
marginLeft: 8,
color: "black"
}
},
I18n.t('send_specify_amount')
amount || "0.00"
),
status.components.touchable(
{
onPress: status.components.dispatch([status.events.FOCUS_INPUT, []])
},
status.components.view(
{
flexDirection: "row",
alignItems: "center",
textAlign: "center",
justifyContent: "center"
},
[
status.components.text(
{
font: "light",
numberOfLines: 1,
ellipsizeMode: "tail",
style: {
maxWidth: 250,
fontSize: 38,
marginLeft: 8,
color: "black"
}
},
amount || "0.00"
),
status.components.text(
{
font: "light",
style: {
fontSize: 38,
marginLeft: 8,
color: "rgb(147, 155, 161)"
}
},
I18n.t('eth')
),
]
)
),
status.components.text(
{
status.components.text({
font: "light",
style: {
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingTop: 14,
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 5
fontSize: 38,
marginLeft: 8,
color: "rgb(147, 155, 161)"
}
},
I18n.t('send_fee')
I18n.t('eth')
),
status.components.view(
{
flexDirection: "row"
},
[
status.components.text(
{
style: {
fontSize: 17,
color: "black",
paddingLeft: 16
}
},
[status.components.subscribe(["calculatedFee"])]
),
status.components.text(
{
style: {
fontSize: 17,
color: "rgb(147, 155, 161)",
paddingLeft: 4,
paddingRight: 4
}
},
I18n.t('eth')
)
]
),
status.components.slider(
{
maximumValue: 2,
minimumValue: -2,
onSlidingComplete: status.components.dispatch(
[status.events.UPDATE_DB, "sliderValue"]
),
step: 1,
style: {
marginLeft: 16,
marginRight: 16
}
])
),
status.components.text({
style: {
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingTop: 14,
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 5
}
},
I18n.t('send_fee')
),
status.components.view({
flexDirection: "row"
}, [
status.components.text({
style: {
fontSize: 17,
color: "black",
paddingLeft: 16
}
}, [status.components.subscribe(["calculatedFee"])]),
status.components.text({
style: {
fontSize: 17,
color: "rgb(147, 155, 161)",
paddingLeft: 4,
paddingRight: 4
}
),
status.components.view(
{
flexDirection: "row"
},
[
status.components.text(
{
style: {
flex: 1,
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingLeft: 16,
alignSelf: "flex-start"
}
},
I18n.t('send_cheaper')
),
status.components.text(
{
style: {
flex: 1,
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingRight: 16,
alignSelf: "flex-end",
textAlign: "right"
}
},
I18n.t('send_faster')
)
]
),
status.components.text(
{
style: {
fontSize: 14,
color: "black",
paddingTop: 16,
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 16,
lineHeight: 24
}
},
[status.components.subscribe(["feeExplanation"])]
)
]
)]
)
},
I18n.t('eth')
)
]),
status.components.slider({
maximumValue: 2,
minimumValue: -2,
onSlidingComplete: status.components.dispatch(
[status.events.UPDATE_DB, "sliderValue"]
),
step: 1,
style: {
marginLeft: 16,
marginRight: 16
}
}),
status.components.view({
flexDirection: "row"
}, [
status.components.text({
style: {
flex: 1,
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingLeft: 16,
alignSelf: "flex-start"
}
},
I18n.t('send_cheaper')
),
status.components.text({
style: {
flex: 1,
fontSize: 14,
color: "rgb(147, 155, 161)",
paddingRight: 16,
alignSelf: "flex-end",
textAlign: "right"
}
},
I18n.t('send_faster')
)
]),
status.components.text({
style: {
fontSize: 14,
color: "black",
paddingTop: 16,
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 16,
lineHeight: 24
}
}, [status.components.subscribe(["feeExplanation"])])
])
};
}
@ -322,7 +289,7 @@ function validateSend(validateRecipient, params, context) {
};
}
}
if (!params["amount"]) {
return {
markup: status.components.validationMessage(
@ -380,7 +347,7 @@ function validateSend(validateRecipient, params, context) {
};
}
var fee = calculateFee(
params["bot-db"]["sliderValue"],
{
@ -406,7 +373,7 @@ function handleSend(groupChat, params, context) {
var gasPrice = calculateGasPrice(params["bot-db"]["sliderValue"]);
var data = {
from: context.from,
from: context.from,
value: val,
gas: web3.toBigNumber(21000)
};
@ -423,14 +390,14 @@ function handleSend(groupChat, params, context) {
web3.eth.sendTransaction(data, function(error, hash) {
if (error) {
// Do nothing, as error handling will be done as response to transaction.failed event from go
// Do nothing, as error handling will be done as response to transaction.failed event from go
} else {
status.sendSignal("handler-result", {
status: "success",
hash: hash,
origParams: context["orig-params"]
});
}
}
});
// async handler, so we don't return anything immediately
}
@ -593,7 +560,7 @@ var paramsGroupRequest = [recipientRequestParam, amountRequestParam];
function handlePersonalRequest(params, context) {
var val = params["amount"].replace(",", ".");
return {
event: "request",
request: {
@ -608,7 +575,7 @@ function handlePersonalRequest(params, context) {
function handleGroupRequest(params, context) {
var val = params["amount"].replace(",", ".");
return {
event: "request",
request: {
@ -654,8 +621,8 @@ function previewRequest(showRecipient, params, context) {
I18n.t('request_requesting_from') + " " + params["bot-db"]["public"]["recipient"]["name"]
);
markup.push(recipientRow);
}
}
return {
markup: status.components.view(
{
@ -694,7 +661,7 @@ function validateRequest(validateRecipient, params) {
};
}
}
if (!params["amount"]) {
return {
markup: status.components.validationMessage(
@ -723,7 +690,7 @@ function validateRequest(validateRecipient, params) {
)
};
}
try {
var val = web3.toWei(amount, "ether");
if (val < 0) {

View File

@ -17,7 +17,6 @@
[status-im.utils.handlers :as handlers]
status-im.chat.events.commands
status-im.chat.events.requests
status-im.chat.events.animation
status-im.chat.events.send-message
status-im.chat.events.queue-message
status-im.chat.events.receive-message

View File

@ -1,75 +0,0 @@
(ns status-im.chat.events.animation
(:require [re-frame.core :as re-frame]
[status-im.chat.views.input.utils :as input-utils]
[status-im.utils.handlers :as handlers]
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]))
;;;; Helper fns
(defn set-expandable-height
[{:keys [current-chat-id] :as db} key value]
(-> db
(assoc-in [:chat-animations current-chat-id key :height] value)
(update-in [:chat-animations current-chat-id key :changes-counter] inc)))
(defn choose-predefined-expandable-height
[{:keys [current-chat-id chat-ui-props layout-height] :as db} key preset]
(if (= preset :max)
(set-expandable-height db key :max)
(let [input-height (get-in chat-ui-props [current-chat-id :input-height])
chat-input-margin (if platform/ios?
(get db :keyboard-height)
0)
bottom (+ input-height chat-input-margin)
height (case preset
:min input-utils/min-height
(input-utils/default-container-area-height bottom layout-height))]
(set-expandable-height db key height))))
;;;; Handlers
(handlers/register-handler-db
:set-expandable-height
[re-frame/trim-v]
(fn [db [key value]]
(set-expandable-height db key value)))
(handlers/register-handler-db
:choose-predefined-expandable-height
[re-frame/trim-v]
(fn [db [key preset]]
(choose-predefined-expandable-height db key preset)))
(handlers/register-handler-db
:fix-expandable-height
[re-frame/trim-v]
(fn [{:keys [current-chat-id chats chat-ui-props layout-height] :as db} [vy current key]]
(let [input-height (get-in chat-ui-props [current-chat-id :input-height])
chat-input-margin (if platform/ios?
(get db :keyboard-height)
0)
bottom (+ input-height chat-input-margin)
min-height input-utils/min-height
max-height (input-utils/max-container-area-height bottom layout-height)
default-height (input-utils/default-container-area-height bottom layout-height)
possible-values [min-height default-height max-height]
moving-down? (pos? vy)
closest-index (->> possible-values
(map-indexed vector)
(sort-by (fn [[i v]] (Math/abs (- v current))))
(ffirst))
height (cond (and moving-down? (not= closest-index 0))
(get possible-values (dec closest-index))
(and (not moving-down?) (not= closest-index 2))
(get possible-values (inc closest-index))
moving-down?
min-height
(not moving-down?)
max-height)]
(set-expandable-height db key height))))

View File

@ -8,7 +8,6 @@
[status-im.chat.models.commands :as commands-model]
[status-im.chat.models.message :as message-model]
[status-im.chat.events.commands :as commands-events]
[status-im.chat.events.animation :as animation-events]
[status-im.bots.events :as bots-events]
[status-im.ui.components.react :as react-comp]
[status-im.utils.datetime :as time]

View File

@ -96,10 +96,11 @@
(defview chat []
(letsubs [{:keys [group-chat public? input-text]} [:get-current-chat]
show-bottom-info? [:get-current-chat-ui-prop :show-bottom-info?]
layout-height [:get :layout-height]
current-view [:get :view-id]]
[react/view {:style style/chat-view}
show-bottom-info? [:get-current-chat-ui-prop :show-bottom-info?]
current-view [:get :view-id]]
[react/view {:style style/chat-view
:on-layout (fn [e]
(re-frame/dispatch [:set :layout-height (-> e .-nativeEvent .-layout .-height)]))}
[chat-toolbar public?]
(when (= :chat current-view)
[messages-view-animation

View File

@ -11,7 +11,7 @@
:right 0
:bottom 0})
(defn expandable-container [anim-value bottom]
(defn expandable-container [anim-value bottom max-height]
{:background-color common/color-white
:height anim-value
:left 0
@ -20,7 +20,8 @@
:position :absolute
:border-top-color color-root-border
:border-top-width 1
:elevation 2})
:elevation 2
:max-height max-height})
(def header-container
{:min-height 19

View File

@ -310,15 +310,6 @@
(subscribe [:get-chat-message-datemark-groups chat-id]))
(comp first second first))
(reg-sub
:get-default-container-area-height
:<- [:get-current-chat-ui-prop :input-height]
:<- [:get :layout-height]
:<- [:chat-input-margin]
(fn [[input-height layout-height chat-input-margin]]
(let [bottom (+ input-height chat-input-margin)]
(input-utils/default-container-area-height bottom layout-height))))
(reg-sub
:chat-animations
(fn [db [_ key type]]

View File

@ -1,69 +1,36 @@
(ns status-im.chat.views.input.animations.expandable
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [reagent.core :as reagent]
[re-frame.core :as re-frame]
[status-im.ui.components.animation :as animation]
[status-im.ui.components.react :as react]
[status-im.chat.views.input.animations.responder :as responder]
[status-im.chat.views.input.utils :as input-utils]
[status-im.chat.styles.animations :as style]
[status-im.chat.styles.input.input :as input-style]))
[status-im.chat.styles.input.input :as input-style]
[status-im.utils.platform :as platform]))
(defn expandable-view-on-update [{:keys [anim-value to-changed-height chat-input-margin height]}]
(let [to-default-height (re-frame/subscribe [:get-default-container-area-height])
layout-height (re-frame/subscribe [:get :layout-height])]
(fn [component]
;; we're going to change the height here
(def top-offset 100)
;; by default the height can be modified by dispatching :set-expandable-height,
;; but there is also a way to make the height adjusted automatically — in this
;; case you just need to set :dynamic-height? to true
(let [{:keys [dynamic-height?] dynamic-height :height} (reagent/props component)
to-changed-height (if dynamic-height?
dynamic-height
@to-changed-height)
to-change-height (if (= to-changed-height :max)
(input-utils/max-container-area-height @chat-input-margin @layout-height)
to-changed-height)
to-value (or to-change-height height @to-default-height)]
(re-frame/dispatch [:set :expandable-view-height-to-value to-value])
(animation/start
(animation/spring anim-value {:toValue to-value
:friction 10
:tension 60}))))))
(defn expandable-view-on-update [anim-value animation-height]
(when animation-height
(animation/start
(animation/spring anim-value {:toValue animation-height
:friction 10
:tension 60}))))
(defn expandable-view [{:keys [key height hide-overlay?]} & _]
(let [anim-value (animation/create-value 0)
input-height (re-frame/subscribe [:get-current-chat-ui-prop :input-height])
fullscreen? (re-frame/subscribe [:get-current-chat-ui-prop :fullscreen?])
chat-input-margin (re-frame/subscribe [:chat-input-margin])
to-changed-height (re-frame/subscribe [:chat-animations key :height])
changes-counter (re-frame/subscribe [:chat-animations key :changes-counter])
on-update (expandable-view-on-update {:anim-value anim-value
:to-changed-height to-changed-height
:chat-input-margin chat-input-margin
:height height})]
(reagent/create-class
{:component-did-mount
on-update
:component-did-update
on-update
:component-will-unmount
(fn []
(re-frame/dispatch [:set-chat-ui-props {:fullscreen? false}])
(if height
(re-frame/dispatch [:set-expandable-height key height])
(re-frame/dispatch [:choose-predefined-expandable-height key :default])))
:display-name
"expandable-view"
:reagent-render
(fn [{:keys [custom-header]} & elements]
@to-changed-height @changes-counter
(let [input-height (or @input-height (+ input-style/padding-vertical
input-style/min-input-height
input-style/padding-vertical
input-style/border-height))
bottom (+ input-height @chat-input-margin)]
[react/view style/overlap-container
(into [react/animated-view {:style (style/expandable-container anim-value bottom)}]
elements)]))})))
(defview expandable-view [{:keys [key custom-header]} & elements]
(letsubs [anim-value (animation/create-value 0)
input-height [:get-current-chat-ui-prop :input-height]
chat-input-margin [:chat-input-margin]
keyboard-height [:get :keyboard-height]
chat-layout-height [:get :layout-height]]
(let [input-height (or input-height (+ input-style/padding-vertical
input-style/min-input-height
input-style/padding-vertical
input-style/border-height))
bottom (+ input-height chat-input-margin)
max-height (- chat-layout-height (when platform/ios? keyboard-height) input-height top-offset)]
[react/view style/overlap-container
[react/animated-view {:style (style/expandable-container anim-value bottom max-height)}
(into [react/scroll-view {:keyboard-should-persist-taps :always
:on-content-size-change #(expandable-view-on-update anim-value %2)
:bounces false}]
elements)]])))

View File

@ -1,33 +0,0 @@
(ns status-im.chat.views.input.animations.responder
(:require [status-im.ui.components.drag-drop :as drag]
[status-im.ui.components.animation :as anim]
[status-im.chat.views.input.utils :as input-utils]
[re-frame.core :refer [dispatch]]
[taoensso.timbre :as log]
[status-im.utils.platform :as p]
[status-im.ui.components.toolbar.styles :as toolbar-st]))
;; todo bad name. Ideas?
(defn enough-dy [gesture]
(> (Math/abs (.-dy gesture)) 10))
(defn on-move [response-height layout-height]
(let [margin-top (+ (get p/platform-specific :status-bar-default-height)
(/ (:height toolbar-st/toolbar) 2))]
(fn [_ gesture]
(when (enough-dy gesture)
(let [to-value (+ (- @layout-height (.-moveY gesture)) margin-top)]
(when (> to-value input-utils/min-height)
(dispatch [:set :expandable-view-height-to-value to-value])
(anim/start
(anim/spring response-height {:toValue to-value}))))))))
(defn on-release [response-height handler-name key]
(fn [_ gesture]
(when (enough-dy gesture)
(dispatch [handler-name (.-vy gesture) (.-_value response-height) key]))))
(defn pan-responder [response-height layout-height handler-name key]
(drag/create-pan-responder
{:on-move (on-move response-height layout-height)
:on-release (on-release response-height handler-name key)}))

View File

@ -18,15 +18,10 @@
(defview parameter-box-view []
(letsubs [show-parameter-box? [:show-parameter-box?]
parameter-box [:chat-parameter-box]]
(let [{:keys [title height]} parameter-box
draggable? (not height)]
(let [{:keys [title]} parameter-box]
(when show-parameter-box?
[expandable/expandable-view
{:key :parameter-box
:draggable? draggable?
:custom-header (when title
(box-header/get-header :parameter-box))
:height (when-not draggable?
(+ height (:border-top-width style/root)))
:dynamic-height? (not draggable?)}
{:key :parameter-box
:custom-header (when title
(box-header/get-header :parameter-box))}
[parameter-box-container]]))))

View File

@ -18,7 +18,6 @@
[markup [:result-box-markup]]
(when markup
[expandable-view {:key :result-box
:draggable? true
:custom-header (box-header/get-header :result-box)}
[result-box-container markup]
[offline-view]]))

View File

@ -35,24 +35,17 @@
:last? last?}])
(defview suggestions-view []
(letsubs [show-suggestions-view? [:show-suggestions-view?]
responses [:get-available-responses]
commands [:get-available-commands]]
(let [number-of-entries (+ (count responses) (count commands))]
[expandable/expandable-view {:key :suggestions
:draggable? false
:height (* number-of-entries
(+ style/item-height
style/border-height))
:dynamic-height? true}
[react/view
[react/scroll-view {:keyboard-should-persist-taps :always
:bounces false}
(when (seq responses)
(for [[i response] (map-indexed vector responses)]
^{:key i}
[response-item response (= i (dec (count responses)))]))
(when (seq commands)
(for [[i command] (map-indexed vector commands)]
^{:key i}
[command-item command (= i (dec (count commands)))]))]]])))
(letsubs [responses [:get-available-responses]
commands [:get-available-commands]]
[expandable/expandable-view {:key :suggestions}
[react/view
[react/scroll-view {:keyboard-should-persist-taps :always
:bounces false}
(when (seq responses)
(for [[i response] (map-indexed vector responses)]
^{:key i}
[response-item response (= i (dec (count responses)))]))
(when (seq commands)
(for [[i command] (map-indexed vector commands)]
^{:key i}
[command-item command (= i (dec (count commands)))]))]]]))

View File

@ -42,7 +42,6 @@
[:chats chat-id :parameter-boxes (:name command) parameter-index]
(when-not (string/blank? current-input)
[:chats chat-id :parameter-boxes :message]))]
(dispatch [:choose-predefined-expandable-height :parameter-box (or (keyword height) :default)])
(when (and contains-markup? path (not= (get-in db path) markup))
(dispatch [:set-in path returned])
(when default-db

View File

@ -249,7 +249,7 @@
:initialize-account-db
(fn [{:keys [accounts/accounts contacts/contacts networks/networks
network network-status view-id navigation-stack chats
access-scope->commands-responses layout-height
access-scope->commands-responses
status-module-initialized? status-node-started?
inbox/wnode]
:or [network (get app-db :network)
@ -259,7 +259,6 @@
(cond-> (assoc app-db
:access-scope->commands-responses access-scope->commands-responses
:accounts/current-account-id address
:layout-height layout-height
;; TODO (yenda) bad, this is derived data and shouldn't be stored in the db
;; the cost of retrieving public key from db with a function taking using
;; current-account-id is negligeable