mirror of
https://github.com/status-im/status-mobile.git
synced 2025-03-01 16:50:58 +00:00
chat input performance improvements
Signed-off-by: andrey <motor4ik@gmail.com>
This commit is contained in:
parent
7c4c520712
commit
3de7c37d90
@ -65,11 +65,6 @@
|
|||||||
(s/explain spec prop)
|
(s/explain spec prop)
|
||||||
false)))
|
false)))
|
||||||
|
|
||||||
;; TODO(Ferossgp): Check performance for android layout animations
|
|
||||||
(when (and platform/android?
|
|
||||||
(aget rn/ui-manager "setLayoutAnimationEnabledExperimental"))
|
|
||||||
(ocall rn/ui-manager "setLayoutAnimationEnabledExperimental" true))
|
|
||||||
|
|
||||||
(def height 44) ; 22 line-height + 11*2 vertical padding
|
(def height 44) ; 22 line-height + 11*2 vertical padding
|
||||||
(def multiline-height 88) ; 3 * 22 three line-height + 11* vertical padding
|
(def multiline-height 88) ; 3 * 22 three line-height + 11* vertical padding
|
||||||
|
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
(oset! ref "current" val)
|
(oset! ref "current" val)
|
||||||
val)
|
val)
|
||||||
|
|
||||||
|
(defn set-native-props [^js ref ^js props]
|
||||||
|
(when-let [curr-ref ^js (current-ref ref)]
|
||||||
|
(.setNativeProps curr-ref props)))
|
||||||
|
|
||||||
(deftype StateHook [value set-value]
|
(deftype StateHook [value set-value]
|
||||||
cljs.core/IHash
|
cljs.core/IHash
|
||||||
(-hash [o] (goog/getUid o))
|
(-hash [o] (goog/getUid o))
|
||||||
|
@ -238,12 +238,13 @@
|
|||||||
|
|
||||||
(fx/defn close-chat
|
(fx/defn close-chat
|
||||||
{:events [:close-chat]}
|
{:events [:close-chat]}
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx}]
|
||||||
(chat.state/reset-visible-item)
|
(let [chat-id (:current-chat-id db)]
|
||||||
(fx/merge cofx
|
(chat.state/reset-visible-item)
|
||||||
{:db (dissoc db :current-chat-id)}
|
(fx/merge cofx
|
||||||
(offload-messages chat-id)
|
{:db (dissoc db :current-chat-id)}
|
||||||
(navigation/navigate-back)))
|
(offload-messages chat-id)
|
||||||
|
(navigation/navigate-back))))
|
||||||
|
|
||||||
(fx/defn remove-chat
|
(fx/defn remove-chat
|
||||||
"Removes chat completely from app, producing all necessary effects for that"
|
"Removes chat completely from app, producing all necessary effects for that"
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
|
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
new-text (mentions/new-input-text-with-mention cofx user)
|
new-text (mentions/new-input-text-with-mention cofx user)
|
||||||
at-sign-idx (get-in db [:chats chat-id :mentions :at-sign-idx])
|
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
|
||||||
cursor (+ at-sign-idx (count name) 2)]
|
cursor (+ at-sign-idx (count name) 2)]
|
||||||
(fx/merge
|
(fx/merge
|
||||||
cofx
|
cofx
|
||||||
|
@ -122,6 +122,11 @@
|
|||||||
#(re-frame/dispatch [::messages-loaded chat-id session-id %])
|
#(re-frame/dispatch [::messages-loaded chat-id session-id %])
|
||||||
#(re-frame/dispatch [::failed-loading-messages chat-id session-id %]))))))))
|
#(re-frame/dispatch [::failed-loading-messages chat-id session-id %]))))))))
|
||||||
|
|
||||||
|
(fx/defn load-more-messages-for-current-chat
|
||||||
|
{:events [:chat.ui/load-more-messages-for-current-chat]}
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(load-more-messages cofx (:current-chat-id db) false))
|
||||||
|
|
||||||
(fx/defn load-messages
|
(fx/defn load-messages
|
||||||
[{:keys [db now] :as cofx} chat-id]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
(when-not (get-in db [:pagination-info chat-id :messages-initialized?])
|
(when-not (get-in db [:pagination-info chat-id :messages-initialized?])
|
||||||
|
@ -448,7 +448,7 @@
|
|||||||
|
|
||||||
(fx/defn on-text-input
|
(fx/defn on-text-input
|
||||||
{:events [::on-text-input]}
|
{:events [::on-text-input]}
|
||||||
[{:keys [db] :as cofx} {:keys [new-text previous-text start end] :as args}]
|
[{:keys [db]} {:keys [previous-text start end] :as args}]
|
||||||
(log/debug "[mentions] on-text-input args" args)
|
(log/debug "[mentions] on-text-input args" args)
|
||||||
(let [normalized-previous-text
|
(let [normalized-previous-text
|
||||||
;; NOTE(rasom): on iOS `previous-text` contains entire input's text. To
|
;; NOTE(rasom): on iOS `previous-text` contains entire input's text. To
|
||||||
@ -457,16 +457,14 @@
|
|||||||
previous-text
|
previous-text
|
||||||
(subs previous-text start end))
|
(subs previous-text start end))
|
||||||
chat-id (:current-chat-id db)
|
chat-id (:current-chat-id db)
|
||||||
previous-state (get-in db [:chats chat-id :mentions])
|
previous-state (get-in db [:chats/mentions chat-id :mentions])
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
|
||||||
new-state (-> previous-state
|
new-state (-> previous-state
|
||||||
(merge args)
|
(merge args)
|
||||||
(assoc :previous-text normalized-previous-text))
|
(assoc :previous-text normalized-previous-text))
|
||||||
old-at-idxs (:at-idxs new-state)
|
|
||||||
new-at-idxs (calc-at-idxs new-state)
|
new-at-idxs (calc-at-idxs new-state)
|
||||||
new-state (assoc new-state :at-idxs new-at-idxs)]
|
new-state (assoc new-state :at-idxs new-at-idxs)]
|
||||||
(log/debug "[mentions] on-text-input state" new-state)
|
(log/debug "[mentions] on-text-input state" new-state)
|
||||||
{:db (assoc-in db [:chats chat-id :mentions] new-state)}))
|
{:db (assoc-in db [:chats/mentions chat-id :mentions] new-state)}))
|
||||||
|
|
||||||
(defn calculate-input [text [first-idx :as idxs]]
|
(defn calculate-input [text [first-idx :as idxs]]
|
||||||
(if-not first-idx
|
(if-not first-idx
|
||||||
@ -496,8 +494,7 @@
|
|||||||
[{:keys [db]} mentionable-users]
|
[{:keys [db]} mentionable-users]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
text (get-in db [:chat/inputs chat-id :input-text])
|
||||||
{:keys [new-text start end] :as state}
|
state (get-in db [:chats/mentions chat-id :mentions])
|
||||||
(get-in db [:chats chat-id :mentions])
|
|
||||||
new-at-idxs (check-idx-for-mentions
|
new-at-idxs (check-idx-for-mentions
|
||||||
text
|
text
|
||||||
(:at-idxs state)
|
(:at-idxs state)
|
||||||
@ -506,25 +503,25 @@
|
|||||||
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in
|
(update-in
|
||||||
[:chats chat-id :mentions]
|
[:chats/mentions chat-id :mentions]
|
||||||
assoc
|
assoc
|
||||||
:at-idxs new-at-idxs)
|
:at-idxs new-at-idxs)
|
||||||
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input))}))
|
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input))}))
|
||||||
|
|
||||||
(fx/defn calculate-suggestions
|
(fx/defn calculate-suggestions
|
||||||
{:events [::calculate-suggestions]}
|
{:events [::calculate-suggestions]}
|
||||||
[{:keys [db] :as cofx} mentionable-users]
|
[{:keys [db]} mentionable-users]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
text (get-in db [:chat/inputs chat-id :input-text])
|
||||||
{:keys [new-text at-idxs start end] :as state}
|
{:keys [new-text at-idxs start end] :as state}
|
||||||
(get-in db [:chats chat-id :mentions])
|
(get-in db [:chats/mentions chat-id :mentions])
|
||||||
new-text (or new-text text)]
|
new-text (or new-text text)]
|
||||||
(log/debug "[mentions] calculate suggestions"
|
(log/debug "[mentions] calculate suggestions"
|
||||||
"state" state)
|
"state" state)
|
||||||
(if-not (seq at-idxs)
|
(if-not (seq at-idxs)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chats/mention-suggestions chat-id] nil)
|
(assoc-in [:chats/mention-suggestions chat-id] nil)
|
||||||
(assoc-in [:chats chat-id :mentions :at-idxs] nil)
|
(assoc-in [:chats/mentions chat-id :mentions :at-idxs] nil)
|
||||||
(assoc-in [:chat/inputs-with-mentions chat-id] [[:text text]]))}
|
(assoc-in [:chat/inputs-with-mentions chat-id] [[:text text]]))}
|
||||||
(let [new-at-idxs (check-idx-for-mentions
|
(let [new-at-idxs (check-idx-for-mentions
|
||||||
text
|
text
|
||||||
@ -550,7 +547,7 @@
|
|||||||
"mentions" (count mentions))
|
"mentions" (count mentions))
|
||||||
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:chats chat-id :mentions]
|
(update-in [:chats/mentions chat-id :mentions]
|
||||||
assoc
|
assoc
|
||||||
:at-sign-idx at-sign-idx
|
:at-sign-idx at-sign-idx
|
||||||
:at-idxs new-at-idxs
|
:at-idxs new-at-idxs
|
||||||
@ -563,7 +560,7 @@
|
|||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
text (get-in db [:chat/inputs chat-id :input-text])
|
text (get-in db [:chat/inputs chat-id :input-text])
|
||||||
{:keys [mention-end at-sign-idx]}
|
{:keys [mention-end at-sign-idx]}
|
||||||
(get-in db [:chats chat-id :mentions])]
|
(get-in db [:chats/mentions chat-id :mentions])]
|
||||||
(log/debug "[mentions] clear suggestions"
|
(log/debug "[mentions] clear suggestions"
|
||||||
"state" new-input-text-with-mention)
|
"state" new-input-text-with-mention)
|
||||||
(string/join
|
(string/join
|
||||||
@ -589,7 +586,7 @@
|
|||||||
(fx/merge
|
(fx/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:chats chat-id] dissoc :mentions)
|
(update-in [:chats/mentions chat-id] dissoc :mentions)
|
||||||
(update :chat/inputs-with-mentions dissoc chat-id))}
|
(update :chat/inputs-with-mentions dissoc chat-id))}
|
||||||
(clear-suggestions))))
|
(clear-suggestions))))
|
||||||
|
|
||||||
@ -607,7 +604,7 @@
|
|||||||
mentionable-users]
|
mentionable-users]
|
||||||
(let [chat-id (:current-chat-id db)
|
(let [chat-id (:current-chat-id db)
|
||||||
{:keys [mention-end at-idxs]}
|
{:keys [mention-end at-idxs]}
|
||||||
(get-in db [:chats chat-id :mentions])]
|
(get-in db [:chats/mentions chat-id :mentions])]
|
||||||
(when (seq at-idxs)
|
(when (seq at-idxs)
|
||||||
(if (some
|
(if (some
|
||||||
(fn [{:keys [from to] :as idx}]
|
(fn [{:keys [from to] :as idx}]
|
||||||
@ -617,7 +614,7 @@
|
|||||||
at-idxs)
|
at-idxs)
|
||||||
(fx/merge
|
(fx/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (update-in db [:chats chat-id :mentions]
|
{:db (update-in db [:chats/mentions chat-id :mentions]
|
||||||
assoc
|
assoc
|
||||||
:start end
|
:start end
|
||||||
:end end
|
:end end
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
[status-im.wallet.db :as wallet.db]))
|
[status-im.wallet.db :as wallet.db]))
|
||||||
|
|
||||||
;; initial state of app-db
|
;; initial state of app-db
|
||||||
(def app-db {:keyboard-height 0
|
(def app-db {:contacts/contacts {}
|
||||||
:contacts/contacts {}
|
|
||||||
:pairing/installations {}
|
:pairing/installations {}
|
||||||
:group/selected-contacts #{}
|
:group/selected-contacts #{}
|
||||||
:chats {}
|
:chats {}
|
||||||
|
@ -66,8 +66,6 @@
|
|||||||
(reg-root-key-sub :animations :animations)
|
(reg-root-key-sub :animations :animations)
|
||||||
(reg-root-key-sub :ui/search :ui/search)
|
(reg-root-key-sub :ui/search :ui/search)
|
||||||
(reg-root-key-sub :web3-node-version :web3-node-version)
|
(reg-root-key-sub :web3-node-version :web3-node-version)
|
||||||
(reg-root-key-sub :keyboard-height :keyboard-height)
|
|
||||||
(reg-root-key-sub :keyboard-max-height :keyboard-max-height)
|
|
||||||
(reg-root-key-sub :sync-data :sync-data)
|
(reg-root-key-sub :sync-data :sync-data)
|
||||||
(reg-root-key-sub :mobile-network/remember-choice? :mobile-network/remember-choice?)
|
(reg-root-key-sub :mobile-network/remember-choice? :mobile-network/remember-choice?)
|
||||||
(reg-root-key-sub :qr-modal :qr-modal)
|
(reg-root-key-sub :qr-modal :qr-modal)
|
||||||
@ -789,12 +787,6 @@
|
|||||||
(fn [input]
|
(fn [input]
|
||||||
(:input-text input)))
|
(:input-text input)))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
|
||||||
:chats/current-chat-input-text
|
|
||||||
:<- [:chats/current-chat-inputs]
|
|
||||||
(fn [input]
|
|
||||||
(:input-text input)))
|
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:chats/current-chat-membership
|
:chats/current-chat-membership
|
||||||
:<- [:chats/current-chat-id]
|
:<- [:chats/current-chat-id]
|
||||||
@ -827,6 +819,12 @@
|
|||||||
(not group-chat)
|
(not group-chat)
|
||||||
(assoc :show-input? true)))))
|
(assoc :show-input? true)))))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:chats/current-chat-chat-view
|
||||||
|
:<- [:chats/current-chat]
|
||||||
|
(fn [current-chat]
|
||||||
|
(select-keys current-chat [:chat-id :show-input? :group-chat :admins :invitation-admin :public? :chat-type :color :chat-name])))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:current-chat/metadata
|
:current-chat/metadata
|
||||||
:<- [:chats/current-raw-chat]
|
:<- [:chats/current-raw-chat]
|
||||||
@ -914,6 +912,12 @@
|
|||||||
(fn [chats [_ chat-id]]
|
(fn [chats [_ chat-id]]
|
||||||
(get-in chats [chat-id :public?])))
|
(get-in chats [chat-id :public?])))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:chats/might-have-join-time-messages?
|
||||||
|
:<- [::chats]
|
||||||
|
(fn [chats [_ chat-id]]
|
||||||
|
(get-in chats [chat-id :might-have-join-time-messages?])))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:chats/message-list
|
:chats/message-list
|
||||||
:<- [::message-lists]
|
:<- [::message-lists]
|
||||||
@ -1019,6 +1023,31 @@
|
|||||||
(fn [{:keys [metadata]}]
|
(fn [{:keys [metadata]}]
|
||||||
(:sending-image metadata)))
|
(:sending-image metadata)))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:chats/chat-toolbar
|
||||||
|
:<- [:disconnected?]
|
||||||
|
:<- [:multiaccounts/login]
|
||||||
|
:<- [:chats/sending-image]
|
||||||
|
:<- [:mainnet?]
|
||||||
|
:<- [:current-chat/one-to-one-chat?]
|
||||||
|
:<- [:current-chat/metadata]
|
||||||
|
:<- [:chats/reply-message]
|
||||||
|
(fn [[disconnected? {:keys [processing]} sending-image mainnet? one-to-one-chat? {:keys [public?]} reply]]
|
||||||
|
(let [sending-image (seq sending-image)]
|
||||||
|
{:send (and (not (or processing disconnected?)))
|
||||||
|
:stickers (and mainnet?
|
||||||
|
(not sending-image)
|
||||||
|
(not reply))
|
||||||
|
:image (and (not reply)
|
||||||
|
(not public?))
|
||||||
|
:extensions (and one-to-one-chat?
|
||||||
|
(or config/commands-enabled? mainnet?)
|
||||||
|
(not reply))
|
||||||
|
:audio (and (not sending-image)
|
||||||
|
(not reply)
|
||||||
|
(not public?))
|
||||||
|
:sending-image sending-image})))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:public-chat.new/topic-error-message
|
:public-chat.new/topic-error-message
|
||||||
:<- [:public-group-topic]
|
:<- [:public-group-topic]
|
||||||
|
@ -49,26 +49,27 @@
|
|||||||
(animation/parallel
|
(animation/parallel
|
||||||
[(animation/timing blue-bar-left-margin (easing :out 0))
|
[(animation/timing blue-bar-left-margin (easing :out 0))
|
||||||
(animation/timing white-bar-left-margin (easing :out 0))])]))))}
|
(animation/timing white-bar-left-margin (easing :out 0))])]))))}
|
||||||
[react/view {:style {:width parent-width
|
[react/view
|
||||||
:position :absolute
|
[react/view {:style {:width parent-width
|
||||||
:top -3
|
:position :absolute
|
||||||
:z-index 3
|
:top -3
|
||||||
:height 3
|
:z-index 3
|
||||||
:background-color colors/white}
|
:height 3
|
||||||
:accessibility-label :loading-indicator}
|
:background-color colors/white}
|
||||||
[react/animated-view {:style (animated-bar-style blue-bar-left-margin
|
:accessibility-label :loading-indicator}
|
||||||
parent-width
|
[react/animated-view {:style (animated-bar-style blue-bar-left-margin
|
||||||
colors/blue)}]
|
parent-width
|
||||||
[react/animated-view {:style (assoc (animated-bar-style white-bar-left-margin
|
colors/blue)}]
|
||||||
parent-width
|
[react/animated-view {:style (assoc (animated-bar-style white-bar-left-margin
|
||||||
colors/white)
|
parent-width
|
||||||
:left (* 0.15 parent-width))}]]))
|
colors/white)
|
||||||
|
:left (* 0.15 parent-width))}]]]))
|
||||||
|
|
||||||
(defview loading-indicator []
|
(defview loading-indicator []
|
||||||
(letsubs [ui-status-properties [:connectivity/ui-status-properties]
|
(letsubs [fetching? [:mailserver/fetching?]
|
||||||
window-width [:dimensions/window-width]]
|
window-width [:dimensions/window-width]]
|
||||||
(when (:loading-indicator? ui-status-properties)
|
(when fetching?
|
||||||
[loading-indicator-anim @window-width])))
|
[loading-indicator-anim window-width])))
|
||||||
|
|
||||||
(defn hide-sheet-and-dispatch [event]
|
(defn hide-sheet-and-dispatch [event]
|
||||||
(re-frame/dispatch [:bottom-sheet/hide])
|
(re-frame/dispatch [:bottom-sheet/hide])
|
||||||
|
@ -230,7 +230,7 @@
|
|||||||
[components/separator-dark]
|
[components/separator-dark]
|
||||||
[react/view
|
[react/view
|
||||||
(when loading?
|
(when loading?
|
||||||
[connectivity/loading-indicator window-width])]
|
[connectivity/loading-indicator-anim window-width])]
|
||||||
[browser-component {:dapp? dapp?
|
[browser-component {:dapp? dapp?
|
||||||
:dapp dapp
|
:dapp dapp
|
||||||
:error? error?
|
:error? error?
|
||||||
|
@ -281,14 +281,14 @@
|
|||||||
[cancel-button (:cancel-disabled? @state) #(stop-recording base-params)]]
|
[cancel-button (:cancel-disabled? @state) #(stop-recording base-params)]]
|
||||||
[rec-button-view (merge base-params {:state state})]
|
[rec-button-view (merge base-params {:state state})]
|
||||||
[react/animated-view {:style {:opacity ctrl-buttons-anim-value}}
|
[react/animated-view {:style {:opacity ctrl-buttons-anim-value}}
|
||||||
[input/send-button {:on-send-press (fn [] (cond
|
[input/send-button (fn [] (cond
|
||||||
(= :ready-to-send (:general @state))
|
(= :ready-to-send (:general @state))
|
||||||
(do
|
(do
|
||||||
(reset-timer timer)
|
(reset-timer timer)
|
||||||
(animate-buttons false false base-params)
|
(animate-buttons false false base-params)
|
||||||
(send-audio-msessage state))
|
(send-audio-msessage state))
|
||||||
|
|
||||||
(#{:recording :recording-paused} (:general @state))
|
(#{:recording :recording-paused} (:general @state))
|
||||||
(stop-recording (merge base-params
|
(stop-recording (merge base-params
|
||||||
{:on-success
|
{:on-success
|
||||||
#(send-audio-msessage state)}))))}]]]])))
|
#(send-audio-msessage state)}))))]]]])))
|
||||||
|
@ -10,16 +10,17 @@
|
|||||||
[status-im.chat.constants :as chat.constants]
|
[status-im.chat.constants :as chat.constants]
|
||||||
[status-im.utils.utils :as utils.utils]
|
[status-im.utils.utils :as utils.utils]
|
||||||
[quo.components.animated.pressable :as pressable]
|
[quo.components.animated.pressable :as pressable]
|
||||||
[quo.animated :as animated]
|
|
||||||
[status-im.utils.config :as config]
|
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.chat.models.mentions :as mentions]
|
[status-im.chat.models.mentions :as mentions]
|
||||||
[status-im.ui.components.list.views :as list]
|
[status-im.ui.components.list.views :as list]
|
||||||
[quo.components.list.item :as list-item]
|
[quo.components.list.item :as list-item]
|
||||||
[status-im.ui.screens.chat.photos :as photos]
|
[status-im.ui.screens.chat.photos :as photos]
|
||||||
[reagent.core :as reagent]))
|
[reagent.core :as reagent]
|
||||||
|
[clojure.string :as string]))
|
||||||
|
|
||||||
|
(defn input-focus [text-input-ref]
|
||||||
|
(some-> ^js (react/current-ref text-input-ref) .focus))
|
||||||
|
|
||||||
(def panel->icons {:extensions :main-icons/commands
|
(def panel->icons {:extensions :main-icons/commands
|
||||||
:images :main-icons/photo})
|
:images :main-icons/photo})
|
||||||
@ -70,9 +71,8 @@
|
|||||||
[icons/icon :main-icons/keyboard (styles/icon false)]
|
[icons/icon :main-icons/keyboard (styles/icon false)]
|
||||||
[icons/icon :main-icons/speech (styles/icon false)])]])
|
[icons/icon :main-icons/speech (styles/icon false)])]])
|
||||||
|
|
||||||
(defn send-button [{:keys [on-send-press]}]
|
(defn send-button [on-send]
|
||||||
[pressable/pressable {:type :scale
|
[rn/touchable-opacity {:on-press-in on-send}
|
||||||
:on-press on-send-press}
|
|
||||||
[rn/view {:style (styles/send-message-button)}
|
[rn/view {:style (styles/send-message-button)}
|
||||||
[icons/icon :main-icons/arrow-up
|
[icons/icon :main-icons/arrow-up
|
||||||
{:container-style (styles/send-message-container)
|
{:container-style (styles/send-message-container)
|
||||||
@ -81,8 +81,8 @@
|
|||||||
|
|
||||||
(defn on-selection-change [timeout-id last-text-change mentionable-users args]
|
(defn on-selection-change [timeout-id last-text-change mentionable-users args]
|
||||||
(let [selection (.-selection ^js (.-nativeEvent ^js args))
|
(let [selection (.-selection ^js (.-nativeEvent ^js args))
|
||||||
start (.-start selection)
|
start (.-start selection)
|
||||||
end (.-end selection)]
|
end (.-end selection)]
|
||||||
;; NOTE(rasom): on iOS we do not dispatch this event immediately
|
;; NOTE(rasom): on iOS we do not dispatch this event immediately
|
||||||
;; because it is needed only in case if selection is changed without
|
;; because it is needed only in case if selection is changed without
|
||||||
;; typing. Timeout might be canceled on `on-change`.
|
;; typing. Timeout might be canceled on `on-change`.
|
||||||
@ -107,8 +107,50 @@
|
|||||||
:end end}
|
:end end}
|
||||||
mentionable-users]))))
|
mentionable-users]))))
|
||||||
|
|
||||||
(defn on-change [on-text-change last-text-change timeout-id mentionable-users args]
|
(defonce input-texts (atom {}))
|
||||||
(let [text (.-text ^js (.-nativeEvent ^js args))]
|
(defonce mentions-enabled (reagent/atom {}))
|
||||||
|
|
||||||
|
(defn show-send [{:keys [actions-ref send-ref sticker-ref]}]
|
||||||
|
(quo.react/set-native-props actions-ref #js {:width 0 :left -88})
|
||||||
|
(quo.react/set-native-props send-ref #js {:width nil :right nil})
|
||||||
|
(quo.react/set-native-props sticker-ref #js {:width 0 :right -100}))
|
||||||
|
|
||||||
|
(defn hide-send [{:keys [actions-ref send-ref sticker-ref]}]
|
||||||
|
(quo.react/set-native-props actions-ref #js {:width nil :left nil})
|
||||||
|
(quo.react/set-native-props send-ref #js {:width 0 :right -100})
|
||||||
|
(quo.react/set-native-props sticker-ref #js {:width nil :right nil}))
|
||||||
|
|
||||||
|
(defn reset-input [refs chat-id]
|
||||||
|
(some-> ^js (react/current-ref (:text-input-ref refs)) .clear)
|
||||||
|
(swap! mentions-enabled update :render not)
|
||||||
|
(swap! input-texts dissoc chat-id))
|
||||||
|
|
||||||
|
(defn clear-input [chat-id refs]
|
||||||
|
(hide-send refs)
|
||||||
|
(if (get @mentions-enabled chat-id)
|
||||||
|
(do
|
||||||
|
(swap! mentions-enabled dissoc chat-id)
|
||||||
|
;;we need this timeout, because if we clear text input and first index was a mention object with blue color,
|
||||||
|
;;after clearing text will be typed with this blue color, so we render white text first and then clear it
|
||||||
|
(js/setTimeout #(reset-input refs chat-id) 50))
|
||||||
|
(reset-input refs chat-id)))
|
||||||
|
|
||||||
|
(defn on-text-change [val chat-id]
|
||||||
|
(swap! input-texts assoc chat-id val)
|
||||||
|
;;we still store it in app-db for mentions, we don't have reactions in views
|
||||||
|
(re-frame/dispatch [:chat.ui/set-chat-input-text val]))
|
||||||
|
|
||||||
|
(defn on-change [last-text-change timeout-id mentionable-users refs chat-id sending-image args]
|
||||||
|
(let [text (.-text ^js (.-nativeEvent ^js args))
|
||||||
|
prev-text (get @input-texts chat-id)]
|
||||||
|
(when (and (seq prev-text) (empty? text) (not sending-image))
|
||||||
|
(hide-send refs))
|
||||||
|
(when (and (empty? prev-text) (seq text))
|
||||||
|
(show-send refs))
|
||||||
|
|
||||||
|
(when (and (not (get @mentions-enabled chat-id)) (string/index-of text "@"))
|
||||||
|
(swap! mentions-enabled assoc chat-id true))
|
||||||
|
|
||||||
;; NOTE(rasom): on iOS `on-selection-change` is canceled in case if it
|
;; NOTE(rasom): on iOS `on-selection-change` is canceled in case if it
|
||||||
;; happens during typing because it is not needed for mention
|
;; happens during typing because it is not needed for mention
|
||||||
;; suggestions calculation
|
;; suggestions calculation
|
||||||
@ -116,19 +158,23 @@
|
|||||||
(utils.utils/clear-timeout @timeout-id))
|
(utils.utils/clear-timeout @timeout-id))
|
||||||
(when platform/android?
|
(when platform/android?
|
||||||
(reset! last-text-change (js/Date.now)))
|
(reset! last-text-change (js/Date.now)))
|
||||||
(on-text-change text)
|
|
||||||
|
(on-text-change text chat-id)
|
||||||
;; NOTE(rasom): on iOS `on-change` is dispatched after `on-text-input`,
|
;; NOTE(rasom): on iOS `on-change` is dispatched after `on-text-input`,
|
||||||
;; that's why mention suggestions are calculated on `on-change`
|
;; that's why mention suggestions are calculated on `on-change`
|
||||||
(when platform/ios?
|
(when platform/ios?
|
||||||
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
||||||
|
|
||||||
(defn on-text-input [mentionable-users args]
|
(defn on-text-input [mentionable-users chat-id args]
|
||||||
(let [native-event (.-nativeEvent ^js args)
|
(let [native-event (.-nativeEvent ^js args)
|
||||||
text (.-text ^js native-event)
|
text (.-text ^js native-event)
|
||||||
previous-text (.-previousText ^js native-event)
|
previous-text (.-previousText ^js native-event)
|
||||||
range (.-range ^js native-event)
|
range (.-range ^js native-event)
|
||||||
start (.-start ^js range)
|
start (.-start ^js range)
|
||||||
end (.-end ^js range)]
|
end (.-end ^js range)]
|
||||||
|
(when (and (not (get @mentions-enabled chat-id)) (string/index-of text "@"))
|
||||||
|
(swap! mentions-enabled assoc chat-id true))
|
||||||
|
|
||||||
(re-frame/dispatch
|
(re-frame/dispatch
|
||||||
[::mentions/on-text-input
|
[::mentions/on-text-input
|
||||||
{:new-text text
|
{:new-text text
|
||||||
@ -141,14 +187,15 @@
|
|||||||
(when platform/android?
|
(when platform/android?
|
||||||
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
(re-frame/dispatch [::mentions/calculate-suggestions mentionable-users]))))
|
||||||
|
|
||||||
(defn text-input
|
(defn text-input [{:keys [set-active-panel refs chat-id sending-image]}]
|
||||||
[{:keys [cooldown-enabled? input-with-mentions on-text-change set-active-panel text-input-ref]}]
|
(let [cooldown-enabled? @(re-frame/subscribe [:chats/cooldown-enabled?])
|
||||||
(let [mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
|
mentionable-users @(re-frame/subscribe [:chats/mentionable-users])
|
||||||
timeout-id (atom nil)
|
timeout-id (atom nil)
|
||||||
last-text-change (atom nil)]
|
last-text-change (atom nil)
|
||||||
|
mentions-enabled (get @mentions-enabled chat-id)]
|
||||||
[rn/text-input
|
[rn/text-input
|
||||||
{:style (styles/text-input)
|
{:style (styles/text-input)
|
||||||
:ref text-input-ref
|
:ref (:text-input-ref refs)
|
||||||
:max-font-size-multiplier 1
|
:max-font-size-multiplier 1
|
||||||
:accessibility-label :chat-message-input
|
:accessibility-label :chat-message-input
|
||||||
:text-align-vertical :center
|
:text-align-vertical :center
|
||||||
@ -165,45 +212,45 @@
|
|||||||
:underline-color-android :transparent
|
:underline-color-android :transparent
|
||||||
:auto-capitalize :sentences
|
:auto-capitalize :sentences
|
||||||
:on-selection-change (partial on-selection-change timeout-id last-text-change mentionable-users)
|
:on-selection-change (partial on-selection-change timeout-id last-text-change mentionable-users)
|
||||||
:on-change (partial on-change
|
:on-change (partial on-change last-text-change timeout-id mentionable-users refs chat-id sending-image)
|
||||||
on-text-change last-text-change timeout-id mentionable-users)
|
:on-text-input (partial on-text-input mentionable-users chat-id)}
|
||||||
:on-text-input (partial on-text-input mentionable-users)}
|
(if mentions-enabled
|
||||||
(for [[idx [type text]] (map-indexed
|
(for [[idx [type text]] (map-indexed
|
||||||
(fn [idx item]
|
(fn [idx item]
|
||||||
[idx item])
|
[idx item])
|
||||||
input-with-mentions)]
|
@(re-frame/subscribe [:chat/input-with-mentions]))]
|
||||||
^{:key (str idx "_" type "_" text)}
|
^{:key (str idx "_" type "_" text)}
|
||||||
[rn/text (when (= type :mention)
|
[rn/text (when (= type :mention) {:style {:color "#0DA4C9"}})
|
||||||
{:style {:color "#0DA4C9"}})
|
text])
|
||||||
text])]))
|
(get @input-texts chat-id))]))
|
||||||
|
|
||||||
(defn mention-item
|
(defn mention-item
|
||||||
[[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref]
|
[[public-key {:keys [alias name nickname] :as user}] _ _ text-input-ref]
|
||||||
(let [ens-name? (not= alias name)]
|
(let [ens-name? (not= alias name)]
|
||||||
[list-item/list-item
|
[list-item/list-item
|
||||||
(cond-> {:icon [photos/member-photo public-key]
|
(cond-> {:icon [photos/member-photo public-key]
|
||||||
:size :small
|
:size :small
|
||||||
:text-size :small
|
:text-size :small
|
||||||
:title
|
:title
|
||||||
[text/text
|
[text/text
|
||||||
{:weight :medium
|
{:weight :medium
|
||||||
:ellipsize-mode :tail
|
:ellipsize-mode :tail
|
||||||
:number-of-lines 1
|
:number-of-lines 1
|
||||||
:size :small}
|
:size :small}
|
||||||
(if nickname
|
(if nickname
|
||||||
nickname
|
nickname
|
||||||
name)
|
name)
|
||||||
(when nickname
|
(when nickname
|
||||||
[text/text
|
[text/text
|
||||||
{:weight :regular
|
{:weight :regular
|
||||||
:color :secondary
|
:color :secondary
|
||||||
:ellipsize-mode :tail
|
:ellipsize-mode :tail
|
||||||
:size :small}
|
:size :small}
|
||||||
" "
|
" "
|
||||||
(when ens-name?
|
(when ens-name?
|
||||||
"@")
|
"@")
|
||||||
name])]
|
name])]
|
||||||
:title-text-weight :medium
|
:title-text-weight :medium
|
||||||
:on-press
|
:on-press
|
||||||
(fn []
|
(fn []
|
||||||
(re-frame/dispatch [:chat.ui/select-mention text-input-ref user]))}
|
(re-frame/dispatch [:chat.ui/select-mention text-input-ref user]))}
|
||||||
@ -211,14 +258,14 @@
|
|||||||
ens-name?
|
ens-name?
|
||||||
(assoc :subtitle alias))]))
|
(assoc :subtitle alias))]))
|
||||||
|
|
||||||
(def chat-input-height (reagent/atom nil))
|
(def chat-toolbar-height (reagent/atom nil))
|
||||||
|
|
||||||
(defn autocomplete-mentions [text-input-ref]
|
(defn autocomplete-mentions [text-input-ref bottom]
|
||||||
(let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])]
|
(let [suggestions @(re-frame/subscribe [:chat/mention-suggestions])]
|
||||||
(when (and (seq suggestions) @chat-input-height)
|
(when (seq suggestions)
|
||||||
(let [height (+ 16 (* 52 (min 4.5 (count suggestions))))]
|
(let [height (+ 16 (* 52 (min 4.5 (count suggestions))))]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style (styles/autocomplete-container @chat-input-height)
|
{:style (styles/autocomplete-container bottom)
|
||||||
:accessibility-label :suggestions-list}
|
:accessibility-label :suggestions-list}
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style {:height height}}
|
{:style {:height height}}
|
||||||
@ -231,120 +278,87 @@
|
|||||||
:render-data text-input-ref
|
:render-data text-input-ref
|
||||||
:render-fn mention-item}]]]))))
|
:render-fn mention-item}]]]))))
|
||||||
|
|
||||||
(defn chat-input
|
(defn on-chat-toolbar-layout [^js ev]
|
||||||
[{:keys [set-active-panel active-panel on-send-press reply
|
(reset! chat-toolbar-height (-> ev .-nativeEvent .-layout .-height)))
|
||||||
show-send show-image show-stickers show-extensions
|
|
||||||
sending-image input-focus show-audio]
|
(defn focus-input-on-reply [reply had-reply text-input-ref]
|
||||||
:as props}]
|
;;when we show reply we focus input
|
||||||
[rn/view {:style (styles/toolbar)
|
(when-not (= reply @had-reply)
|
||||||
:on-layout #(reset! chat-input-height
|
(reset! had-reply reply)
|
||||||
(-> ^js % .-nativeEvent .-layout .-height))}
|
(when reply
|
||||||
[rn/view {:style (styles/actions-wrapper (and (not show-extensions)
|
(js/setTimeout #(input-focus text-input-ref) 250))))
|
||||||
(not show-image)))}
|
|
||||||
(when show-extensions
|
(defn reply-message [text-input-ref]
|
||||||
[touchable-icon {:panel :extensions
|
(let [had-reply (atom nil)]
|
||||||
:accessibility-label :show-extensions-icon
|
(fn []
|
||||||
:active active-panel
|
(let [reply @(re-frame/subscribe [:chats/reply-message])]
|
||||||
:set-active set-active-panel}])
|
(focus-input-on-reply reply had-reply text-input-ref)
|
||||||
(when show-image
|
(when reply
|
||||||
[touchable-icon {:panel :images
|
[reply/reply-message reply])))))
|
||||||
:accessibility-label :show-photo-icon
|
|
||||||
:active active-panel
|
(defn send-image []
|
||||||
:set-active set-active-panel}])]
|
(let [sending-image @(re-frame/subscribe [:chats/sending-image])]
|
||||||
[:<>
|
(when (seq sending-image)
|
||||||
;; NOTE(rasom): on iOS `autocomplete-mentions` should be placed inside
|
[reply/send-image sending-image])))
|
||||||
;; `chat-input` (otherwise suggestions will be hidden by keyboard) but
|
|
||||||
;; outside animated view below because it adds horizontal margin
|
(defn actions [extensions image show-send actions-ref active-panel set-active-panel]
|
||||||
(when platform/ios?
|
[rn/view {:style (styles/actions-wrapper show-send)
|
||||||
[autocomplete-mentions])
|
:ref actions-ref}
|
||||||
[animated/view
|
(when extensions
|
||||||
{:style (styles/input-container)}
|
[touchable-icon {:panel :extensions
|
||||||
(when reply
|
:accessibility-label :show-extensions-icon
|
||||||
[reply/reply-message reply])
|
:active active-panel
|
||||||
(when (seq sending-image)
|
:set-active set-active-panel}])
|
||||||
[reply/send-image sending-image])
|
(when image
|
||||||
[rn/view {:style (styles/input-row)}
|
[touchable-icon {:panel :images
|
||||||
[text-input props]
|
:accessibility-label :show-photo-icon
|
||||||
[rn/view {:style (styles/in-input-buttons)}
|
:active active-panel
|
||||||
(when show-send
|
:set-active set-active-panel}])])
|
||||||
[send-button {:on-send-press on-send-press}])
|
|
||||||
(when show-stickers
|
|
||||||
[touchable-stickers-icon {:panel :stickers
|
|
||||||
:accessibility-label :show-stickers-icon
|
|
||||||
:active active-panel
|
|
||||||
:input-focus input-focus
|
|
||||||
:set-active set-active-panel}])
|
|
||||||
(when show-audio
|
|
||||||
[touchable-audio-icon {:panel :audio
|
|
||||||
:accessibility-label :show-audio-message-icon
|
|
||||||
:active active-panel
|
|
||||||
:input-focus input-focus
|
|
||||||
:set-active set-active-panel}])]]]]])
|
|
||||||
|
|
||||||
(defn chat-toolbar []
|
(defn chat-toolbar []
|
||||||
(let [previous-layout (atom nil)
|
(let [actions-ref (quo.react/create-ref)
|
||||||
had-reply (atom nil)]
|
send-ref (quo.react/create-ref)
|
||||||
(fn [{:keys [active-panel set-active-panel text-input-ref on-text-change]}]
|
sticker-ref (quo.react/create-ref)
|
||||||
(let [disconnected? @(re-frame/subscribe [:disconnected?])
|
toolbar-options (re-frame/subscribe [:chats/chat-toolbar])]
|
||||||
{:keys [processing]} @(re-frame/subscribe [:multiaccounts/login])
|
(fn [{:keys [active-panel set-active-panel text-input-ref chat-id]}]
|
||||||
mainnet? @(re-frame/subscribe [:mainnet?])
|
(let [;we want to control components on native level, so instead of RN state we set native props via reference
|
||||||
input-text
|
;we don't react on input text in this view, @input-texts below is a regular atom
|
||||||
@(re-frame/subscribe [:chats/current-chat-input-text])
|
refs {:actions-ref actions-ref
|
||||||
input-with-mentions
|
:send-ref send-ref
|
||||||
@(re-frame/subscribe [:chat/input-with-mentions])
|
:sticker-ref sticker-ref
|
||||||
cooldown-enabled? @(re-frame/subscribe [:chats/cooldown-enabled?])
|
:text-input-ref text-input-ref}
|
||||||
one-to-one-chat? @(re-frame/subscribe [:current-chat/one-to-one-chat?])
|
{:keys [send stickers image extensions audio sending-image]} @toolbar-options
|
||||||
{:keys [public?
|
show-send (or sending-image (seq (get @input-texts chat-id)))]
|
||||||
chat-id]} @(re-frame/subscribe [:current-chat/metadata])
|
[rn/view {:style (styles/toolbar)
|
||||||
reply @(re-frame/subscribe [:chats/reply-message])
|
:on-layout on-chat-toolbar-layout}
|
||||||
sending-image @(re-frame/subscribe [:chats/sending-image])
|
;;EXTENSIONS and IMAGE buttons
|
||||||
input-focus (fn []
|
[actions extensions image show-send actions-ref active-panel set-active-panel]
|
||||||
(some-> ^js (react/current-ref text-input-ref) .focus))
|
[rn/view {:style (styles/input-container)}
|
||||||
clear-input (fn []
|
[reply-message text-input-ref]
|
||||||
(some-> ^js (react/current-ref text-input-ref) .clear))
|
[send-image]
|
||||||
empty-text (string/blank? (string/trim (or input-text "")))
|
[rn/view {:style styles/input-row}
|
||||||
show-send (and (or (not empty-text)
|
[text-input {:chat-id chat-id
|
||||||
sending-image)
|
:sending-image sending-image
|
||||||
(not (or processing disconnected?)))
|
:refs refs
|
||||||
show-stickers (and empty-text
|
:set-active-panel set-active-panel}]
|
||||||
mainnet?
|
;;SEND button
|
||||||
(not sending-image)
|
[rn/view {:ref send-ref :style (when-not show-send {:width 0 :right -100})}
|
||||||
(not reply))
|
(when send
|
||||||
show-image (and empty-text
|
[send-button #(do (clear-input chat-id refs)
|
||||||
(not reply)
|
(re-frame/dispatch [:chat.ui/send-current-message]))])]
|
||||||
(not public?))
|
|
||||||
show-extensions (and empty-text
|
;;STICKERS and AUDIO buttons
|
||||||
one-to-one-chat?
|
[rn/view {:style (merge {:flex-direction :row} (when show-send {:width 0 :right -100}))
|
||||||
(or config/commands-enabled? mainnet?)
|
:ref sticker-ref}
|
||||||
(not reply))
|
(when stickers
|
||||||
show-audio (and empty-text
|
[touchable-stickers-icon {:panel :stickers
|
||||||
(not sending-image)
|
:accessibility-label :show-stickers-icon
|
||||||
(not reply)
|
:active active-panel
|
||||||
(not public?))]
|
:input-focus #(input-focus text-input-ref)
|
||||||
(when-not (= reply @had-reply)
|
:set-active set-active-panel}])
|
||||||
(reset! had-reply reply)
|
(when audio
|
||||||
(when reply
|
[touchable-audio-icon {:panel :audio
|
||||||
(js/setTimeout input-focus 250)))
|
:accessibility-label :show-audio-message-icon
|
||||||
(when (and platform/ios? (not= @previous-layout [show-send show-stickers show-extensions show-audio]))
|
:active active-panel
|
||||||
(reset! previous-layout [show-send show-stickers show-extensions show-audio])
|
:input-focus #(input-focus text-input-ref)
|
||||||
(when (seq @previous-layout)
|
:set-active set-active-panel}])]]]]))))
|
||||||
(rn/configure-next
|
|
||||||
(:ease-opacity-200 rn/custom-animations))))
|
|
||||||
[chat-input {:set-active-panel set-active-panel
|
|
||||||
:active-panel active-panel
|
|
||||||
:text-input-ref text-input-ref
|
|
||||||
:input-focus input-focus
|
|
||||||
:reply reply
|
|
||||||
:on-send-press #(do (re-frame/dispatch [:chat.ui/send-current-message])
|
|
||||||
(clear-input))
|
|
||||||
:text-value input-text
|
|
||||||
:input-with-mentions input-with-mentions
|
|
||||||
:on-text-change on-text-change
|
|
||||||
:cooldown-enabled? cooldown-enabled?
|
|
||||||
:show-send show-send
|
|
||||||
:show-stickers show-stickers
|
|
||||||
:show-image show-image
|
|
||||||
:show-audio show-audio
|
|
||||||
:sending-image sending-image
|
|
||||||
:show-extensions show-extensions
|
|
||||||
:chat-id chat-id}]))))
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
:padding-vertical 8
|
:padding-vertical 8
|
||||||
:border-top-width 1
|
:border-top-width 1
|
||||||
:border-top-color (:ui-01 @colors/theme)
|
:border-top-color (:ui-01 @colors/theme)
|
||||||
:background-color (:ui-background @colors/theme)
|
|
||||||
:align-items :flex-end
|
:align-items :flex-end
|
||||||
:flex-direction :row})
|
:flex-direction :row})
|
||||||
|
|
||||||
@ -21,8 +20,9 @@
|
|||||||
:border-bottom-left-radius 16
|
:border-bottom-left-radius 16
|
||||||
:margin-horizontal 8})
|
:margin-horizontal 8})
|
||||||
|
|
||||||
(defn input-row []
|
(def input-row
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
|
:overflow :hidden
|
||||||
:align-items :flex-end})
|
:align-items :flex-end})
|
||||||
|
|
||||||
(defn text-input-wrapper []
|
(defn text-input-wrapper []
|
||||||
@ -41,7 +41,6 @@
|
|||||||
:min-height 34
|
:min-height 34
|
||||||
:max-height 144
|
:max-height 144
|
||||||
:margin 0
|
:margin 0
|
||||||
:border-width 0
|
|
||||||
:flex-shrink 1
|
:flex-shrink 1
|
||||||
:color (:text-01 @colors/theme)
|
:color (:text-01 @colors/theme)
|
||||||
:padding-horizontal 12}
|
:padding-horizontal 12}
|
||||||
@ -50,11 +49,13 @@
|
|||||||
{:padding-top 2
|
{:padding-top 2
|
||||||
:padding-bottom 6})))
|
:padding-bottom 6})))
|
||||||
|
|
||||||
(defn actions-wrapper [invisible]
|
(defn actions-wrapper [show-send]
|
||||||
{:flex-direction :row
|
(merge
|
||||||
:padding-left 4
|
(when show-send
|
||||||
:min-height 34
|
{:width 0 :left -88})
|
||||||
:left (if invisible -88 0)})
|
{:flex-direction :row
|
||||||
|
:padding-left 4
|
||||||
|
:min-height 34}))
|
||||||
|
|
||||||
(defn touchable-icon []
|
(defn touchable-icon []
|
||||||
{:padding-horizontal 10
|
{:padding-horizontal 10
|
||||||
@ -97,17 +98,12 @@
|
|||||||
:margin-horizontal 5})
|
:margin-horizontal 5})
|
||||||
|
|
||||||
(defn send-message-container []
|
(defn send-message-container []
|
||||||
{:background-color (:interactive-01 @colors/theme)
|
{:background-color (:interactive-01 @colors/theme)
|
||||||
:width 26
|
:width 26
|
||||||
:height 26
|
:height 26
|
||||||
:border-radius 13
|
:border-radius 13
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:align-items :center})
|
:align-items :center})
|
||||||
|
|
||||||
(defn in-input-buttons []
|
|
||||||
{:flex-direction :row
|
|
||||||
:height 34
|
|
||||||
:overflow :hidden})
|
|
||||||
|
|
||||||
(defn send-icon-color []
|
(defn send-icon-color []
|
||||||
colors/white)
|
colors/white)
|
||||||
@ -118,6 +114,5 @@
|
|||||||
:right 0
|
:right 0
|
||||||
:bottom bottom
|
:bottom bottom
|
||||||
:background-color (colors/get-color :ui-background)
|
:background-color (colors/get-color :ui-background)
|
||||||
:flex-direction :column
|
|
||||||
:border-top-width 1
|
:border-top-width 1
|
||||||
:border-top-color (colors/get-color :ui-01)})
|
:border-top-color (colors/get-color :ui-01)})
|
@ -30,7 +30,7 @@
|
|||||||
connected? [:mailserver/connected?]]
|
connected? [:mailserver/connected?]]
|
||||||
(let [ids (:ids gaps)]
|
(let [ids (:ids gaps)]
|
||||||
(when-not (and first-gap? might-have-join-time-messages?)
|
(when-not (and first-gap? might-have-join-time-messages?)
|
||||||
[react/view {:style style/gap-container}
|
[react/view {:style (style/gap-container)}
|
||||||
[react/touchable-highlight
|
[react/touchable-highlight
|
||||||
{:on-press (when (and connected? (not in-progress?))
|
{:on-press (when (and connected? (not in-progress?))
|
||||||
(on-press ids first-gap? idx list-ref chat-id))
|
(on-press ids first-gap? idx list-ref chat-id))
|
||||||
|
@ -163,6 +163,9 @@
|
|||||||
|
|
||||||
:else [one-to-one-chat-accents current-chat]))
|
:else [one-to-one-chat-accents current-chat]))
|
||||||
|
|
||||||
|
(defn current-chat-actions []
|
||||||
|
[actions @(re-frame/subscribe [:chats/current-chat])])
|
||||||
|
|
||||||
(defn options [chat-id message-id]
|
(defn options [chat-id message-id]
|
||||||
(fn []
|
(fn []
|
||||||
[react/view
|
[react/view
|
||||||
|
@ -4,5 +4,11 @@
|
|||||||
|
|
||||||
(defonce scrolling (atom nil))
|
(defonce scrolling (atom nil))
|
||||||
|
|
||||||
|
(defn start-scrolling []
|
||||||
|
(reset! scrolling true))
|
||||||
|
|
||||||
|
(defn stop-scrolling []
|
||||||
|
(reset! scrolling false))
|
||||||
|
|
||||||
(defn reset-visible-item []
|
(defn reset-visible-item []
|
||||||
(reset! first-not-visible-item nil))
|
(reset! first-not-visible-item nil))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
(ns status-im.ui.screens.chat.styles.input.gap
|
(ns status-im.ui.screens.chat.styles.input.gap
|
||||||
(:require [status-im.ui.components.colors :as colors]))
|
(:require [status-im.ui.components.colors :as colors]))
|
||||||
|
|
||||||
(def gap-container
|
(defn gap-container []
|
||||||
{:align-self :stretch
|
{:align-self :stretch
|
||||||
:margin-top 24
|
:margin-top 24
|
||||||
:margin-bottom 24
|
:margin-bottom 24
|
||||||
|
@ -31,15 +31,9 @@
|
|||||||
(i18n/label :chat-is-a-contact)
|
(i18n/label :chat-is-a-contact)
|
||||||
(i18n/label :chat-is-not-a-contact))]]))
|
(i18n/label :chat-is-not-a-contact))]]))
|
||||||
|
|
||||||
(defn toolbar-content-view [{:keys [group-chat
|
(defn toolbar-content-view []
|
||||||
invitation-admin
|
(let [{:keys [group-chat invitation-admin color chat-id contacts chat-type chat-name public?]}
|
||||||
color
|
@(re-frame/subscribe [:chats/current-chat])]
|
||||||
chat-id
|
|
||||||
contacts
|
|
||||||
chat-type
|
|
||||||
chat-name
|
|
||||||
public?]}]
|
|
||||||
(when chat-id
|
|
||||||
[react/view {:style st/toolbar-container}
|
[react/view {:style st/toolbar-container}
|
||||||
[react/view {:margin-right 10}
|
[react/view {:margin-right 10}
|
||||||
[react/touchable-highlight {:on-press #(when-not group-chat (re-frame/dispatch [:chat.ui/show-profile chat-id]))}
|
[react/touchable-highlight {:on-press #(when-not group-chat (re-frame/dispatch [:chat.ui/show-profile chat-id]))}
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
[status-im.ui.screens.chat.image.views :as image]
|
[status-im.ui.screens.chat.image.views :as image]
|
||||||
[status-im.ui.screens.chat.state :as state]
|
[status-im.ui.screens.chat.state :as state]
|
||||||
[status-im.ui.screens.chat.extensions.views :as extensions]
|
[status-im.ui.screens.chat.extensions.views :as extensions]
|
||||||
[status-im.ui.components.topbar :as topbar]
|
|
||||||
[status-im.ui.screens.chat.group :as chat.group]
|
[status-im.ui.screens.chat.group :as chat.group]
|
||||||
[status-im.ui.screens.chat.message.gap :as gap]
|
[status-im.ui.screens.chat.message.gap :as gap]
|
||||||
[status-im.ui.components.invite.chat :as invite.chat]
|
[status-im.ui.components.invite.chat :as invite.chat]
|
||||||
@ -32,18 +31,28 @@
|
|||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.utils :as utils]))
|
[status-im.utils.utils :as utils]
|
||||||
|
[quo.design-system.colors :as quo.colors]))
|
||||||
|
|
||||||
(defn topbar [current-chat]
|
(defn topbar []
|
||||||
[topbar/topbar
|
;;we don't use topbar component, because we want chat view as simple (fast) as possible
|
||||||
{:content [toolbar-content/toolbar-content-view current-chat]
|
[react/view {:height 56 :border-bottom-width 1 :border-bottom-color (:ui-01 @quo.colors/theme)}
|
||||||
:navigation {:on-press #(re-frame/dispatch [:close-chat (:chat-id current-chat)])}
|
[react/touchable-highlight {:on-press-in #(re-frame/dispatch [:close-chat])
|
||||||
:right-accessories [{:icon :main-icons/more
|
:accessibility-label :back-button
|
||||||
:accessibility-label :chat-menu-button
|
:style {:height 56 :width 40 :align-items :center :justify-content :center
|
||||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
:padding-left 16}}
|
||||||
{:content (fn []
|
[icons/icon :main-icons/arrow-left]]
|
||||||
[sheets/actions current-chat])
|
[react/view {:flex 1 :left 52 :right 52 :top 0 :bottom 0 :position :absolute}
|
||||||
:height 256}])}]}])
|
[toolbar-content/toolbar-content-view]]
|
||||||
|
[react/touchable-highlight {:on-press-in #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||||
|
{:content (fn []
|
||||||
|
[sheets/current-chat-actions])
|
||||||
|
:height 256}])
|
||||||
|
:accessibility-label :chat-menu-button
|
||||||
|
:style {:right 0 :top 0 :bottom 0 :position :absolute
|
||||||
|
:height 56 :width 40 :align-items :center :justify-content :center
|
||||||
|
:padding-right 16}}
|
||||||
|
[icons/icon :main-icons/more]]])
|
||||||
|
|
||||||
(defn invitation-requests [chat-id admins]
|
(defn invitation-requests [chat-id admins]
|
||||||
(let [current-pk @(re-frame/subscribe [:multiaccount/public-key])
|
(let [current-pk @(re-frame/subscribe [:multiaccount/public-key])
|
||||||
@ -59,16 +68,15 @@
|
|||||||
(i18n/label :t/group-membership-request)]]])))))
|
(i18n/label :t/group-membership-request)]]])))))
|
||||||
|
|
||||||
(defn add-contact-bar [public-key]
|
(defn add-contact-bar [public-key]
|
||||||
(let [added? @(re-frame/subscribe [:contacts/contact-added? public-key])]
|
(when-not @(re-frame/subscribe [:contacts/contact-added? public-key])
|
||||||
(when-not added?
|
[react/touchable-highlight
|
||||||
[react/touchable-highlight
|
{:on-press
|
||||||
{:on-press
|
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
|
||||||
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
|
:accessibility-label :add-to-contacts-button}
|
||||||
:accessibility-label :add-to-contacts-button}
|
[react/view {:style (style/add-contact)}
|
||||||
[react/view {:style (style/add-contact)}
|
[icons/icon :main-icons/add
|
||||||
[icons/icon :main-icons/add
|
{:color colors/blue}]
|
||||||
{:color colors/blue}]
|
[react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]]))
|
||||||
[react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]])))
|
|
||||||
|
|
||||||
(defn chat-intro [{:keys [chat-id
|
(defn chat-intro [{:keys [chat-id
|
||||||
chat-name
|
chat-name
|
||||||
@ -114,7 +122,6 @@
|
|||||||
(defn chat-intro-header-container
|
(defn chat-intro-header-container
|
||||||
[{:keys [group-chat invitation-admin
|
[{:keys [group-chat invitation-admin
|
||||||
chat-type
|
chat-type
|
||||||
might-have-join-time-messages?
|
|
||||||
color chat-id chat-name
|
color chat-id chat-name
|
||||||
public?]}
|
public?]}
|
||||||
no-messages]
|
no-messages]
|
||||||
@ -131,7 +138,7 @@
|
|||||||
:chat-name chat-name
|
:chat-name chat-name
|
||||||
:public? public?
|
:public? public?
|
||||||
:color color
|
:color color
|
||||||
:loading-messages? might-have-join-time-messages?
|
:loading-messages? @(re-frame/subscribe [:chats/might-have-join-time-messages? chat-id])
|
||||||
:no-messages? no-messages}]
|
:no-messages? no-messages}]
|
||||||
(if group-chat
|
(if group-chat
|
||||||
[chat-intro opts]
|
[chat-intro opts]
|
||||||
@ -233,6 +240,7 @@
|
|||||||
(let [loading-messages? @(re-frame/subscribe [:chats/loading-messages? chat-id])
|
(let [loading-messages? @(re-frame/subscribe [:chats/loading-messages? chat-id])
|
||||||
no-messages? @(re-frame/subscribe [:chats/chat-no-messages? chat-id])
|
no-messages? @(re-frame/subscribe [:chats/chat-no-messages? chat-id])
|
||||||
all-loaded? @(re-frame/subscribe [:chats/all-loaded? chat-id])]
|
all-loaded? @(re-frame/subscribe [:chats/all-loaded? chat-id])]
|
||||||
|
(println "LIST FOOTER" (or loading-messages? (not chat-id) (not all-loaded?)))
|
||||||
[react/view {:style (when platform/android? {:scaleY -1})}
|
[react/view {:style (when platform/android? {:scaleY -1})}
|
||||||
(if (or loading-messages? (not chat-id) (not all-loaded?))
|
(if (or loading-messages? (not chat-id) (not all-loaded?))
|
||||||
[react/view {:height 324 :align-items :center :justify-content :center}
|
[react/view {:height 324 :align-items :center :justify-content :center}
|
||||||
@ -265,16 +273,28 @@
|
|||||||
:show-input? show-input?)
|
:show-input? show-input?)
|
||||||
space-keeper]))])
|
space-keeper]))])
|
||||||
|
|
||||||
(defn messages-view
|
(def list-key-fn #(or (:message-id %) (:value %)))
|
||||||
[{:keys [chat bottom-space pan-responder space-keeper show-input?]}]
|
(def list-ref #(reset! messages-list-ref %))
|
||||||
|
|
||||||
|
;;TODO this is not really working in pair with inserting new messages because we stop inserting new messages
|
||||||
|
;;if they outside the viewarea, but we load more here because end is reached,so its slowdown UI because we
|
||||||
|
;;load and render 20 messages more, but we can't prevent this , because otherwise :on-end-reached will work wrong
|
||||||
|
(defn list-on-end-reached []
|
||||||
|
(if @state/scrolling
|
||||||
|
(re-frame/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||||
|
(utils/set-timeout #(re-frame/dispatch [:chat.ui/load-more-messages-for-current-chat])
|
||||||
|
(if platform/low-device? 700 200))))
|
||||||
|
|
||||||
|
(defn messages-view [{:keys [chat bottom-space pan-responder space-keeper show-input?]}]
|
||||||
(let [{:keys [group-chat chat-id public?]} chat
|
(let [{:keys [group-chat chat-id public?]} chat
|
||||||
messages @(re-frame/subscribe [:chats/chat-messages-stream chat-id])
|
messages @(re-frame/subscribe [:chats/chat-messages-stream chat-id])
|
||||||
current-public-key @(re-frame/subscribe [:multiaccount/public-key])]
|
current-public-key @(re-frame/subscribe [:multiaccount/public-key])]
|
||||||
|
;;do not use anonymous functions for handlers
|
||||||
[list/flat-list
|
[list/flat-list
|
||||||
(merge
|
(merge
|
||||||
pan-responder
|
pan-responder
|
||||||
{:key-fn #(or (:message-id %) (:value %))
|
{:key-fn list-key-fn
|
||||||
:ref #(reset! messages-list-ref %)
|
:ref list-ref
|
||||||
:header [list-header chat]
|
:header [list-header chat]
|
||||||
:footer [list-footer chat]
|
:footer [list-footer chat]
|
||||||
:data messages
|
:data messages
|
||||||
@ -286,75 +306,63 @@
|
|||||||
:show-input? show-input?}
|
:show-input? show-input?}
|
||||||
:render-fn render-fn
|
:render-fn render-fn
|
||||||
:on-viewable-items-changed on-viewable-items-changed
|
:on-viewable-items-changed on-viewable-items-changed
|
||||||
;;TODO this is not really working in pair with inserting new messages because we stop inserting new messages
|
:on-end-reached list-on-end-reached
|
||||||
;;if they outside the viewarea, but we load more here because end is reached,so its slowdown UI because we
|
:on-scroll-to-index-failed identity ;;don't remove this
|
||||||
;;load and render 20 messages more, but we can't prevent this , because otherwise :on-end-reached will work wrong
|
|
||||||
:on-end-reached (fn []
|
|
||||||
(if @state/scrolling
|
|
||||||
(re-frame/dispatch [:chat.ui/load-more-messages chat-id])
|
|
||||||
(utils/set-timeout #(re-frame/dispatch [:chat.ui/load-more-messages chat-id])
|
|
||||||
(if platform/low-device? 500 200))))
|
|
||||||
|
|
||||||
:on-scroll-to-index-failed #() ;;don't remove this
|
|
||||||
:content-container-style {:padding-top (+ bottom-space 16)
|
:content-container-style {:padding-top (+ bottom-space 16)
|
||||||
:padding-bottom 16}
|
:padding-bottom 16}
|
||||||
:scroll-indicator-insets {:top bottom-space} ;;ios only
|
:scroll-indicator-insets {:top bottom-space} ;;ios only
|
||||||
:keyboard-dismiss-mode :interactive
|
:keyboard-dismiss-mode :interactive
|
||||||
:keyboard-should-persist-taps :handled
|
:keyboard-should-persist-taps :handled
|
||||||
:onMomentumScrollBegin #(reset! state/scrolling true)
|
:onMomentumScrollBegin state/start-scrolling
|
||||||
:onMomentumScrollEnd #(reset! state/scrolling false)
|
:onMomentumScrollEnd state/stop-scrolling
|
||||||
;;TODO https://github.com/facebook/react-native/issues/30034
|
;;TODO https://github.com/facebook/react-native/issues/30034
|
||||||
:inverted (when platform/ios? true)
|
:inverted (when platform/ios? true)
|
||||||
:style (when platform/android? {:scaleY -1})})]))
|
:style (when platform/android? {:scaleY -1})})]))
|
||||||
|
|
||||||
(defn chat []
|
(defn chat []
|
||||||
(let [bottom-space (reagent/atom 0)
|
(let [bottom-space (reagent/atom 0)
|
||||||
panel-space (reagent/atom 52)
|
panel-space (reagent/atom 52)
|
||||||
active-panel (reagent/atom nil)
|
active-panel (reagent/atom nil)
|
||||||
position-y (animated/value 0)
|
position-y (animated/value 0)
|
||||||
pan-state (animated/value 0)
|
pan-state (animated/value 0)
|
||||||
text-input-ref (quo.react/create-ref)
|
text-input-ref (quo.react/create-ref)
|
||||||
on-update #(when-not (zero? %) (reset! panel-space %))
|
on-update #(when-not (zero? %) (reset! panel-space %))
|
||||||
pan-responder (accessory/create-pan-responder position-y pan-state)
|
pan-responder (accessory/create-pan-responder position-y pan-state)
|
||||||
space-keeper (get-space-keeper-ios bottom-space panel-space active-panel text-input-ref)
|
space-keeper (get-space-keeper-ios bottom-space panel-space active-panel text-input-ref)
|
||||||
set-active-panel (get-set-active-panel active-panel)
|
set-active-panel (get-set-active-panel active-panel)
|
||||||
on-text-change #(re-frame/dispatch [:chat.ui/set-chat-input-text %])]
|
on-close #(set-active-panel nil)]
|
||||||
(fn []
|
(fn []
|
||||||
(let [{:keys [chat-id show-input? group-chat admins invitation-admin] :as current-chat}
|
(let [{:keys [chat-id show-input? group-chat admins invitation-admin] :as chat}
|
||||||
@(re-frame/subscribe [:chats/current-chat])]
|
;;we want to react only on these fields, do not use full chat map here
|
||||||
|
@(re-frame/subscribe [:chats/current-chat-chat-view])
|
||||||
|
max-bottom-space (max @bottom-space @panel-space)]
|
||||||
[:<>
|
[:<>
|
||||||
|
[topbar]
|
||||||
[connectivity/loading-indicator]
|
[connectivity/loading-indicator]
|
||||||
[topbar current-chat]
|
(when chat-id
|
||||||
[:<>
|
(if group-chat
|
||||||
(when current-chat
|
[invitation-requests chat-id admins]
|
||||||
(if group-chat
|
[add-contact-bar chat-id]))
|
||||||
[invitation-requests chat-id admins]
|
;;MESSAGES LIST
|
||||||
[add-contact-bar chat-id]))
|
[messages-view {:chat chat
|
||||||
;;MESSAGES LIST
|
:bottom-space max-bottom-space
|
||||||
[messages-view {:chat current-chat
|
:pan-responder pan-responder
|
||||||
:bottom-space (max @bottom-space @panel-space)
|
:space-keeper space-keeper
|
||||||
:pan-responder pan-responder
|
:show-input? show-input?}]
|
||||||
:space-keeper space-keeper
|
|
||||||
:show-input? show-input?}]]
|
|
||||||
(when (and group-chat invitation-admin)
|
(when (and group-chat invitation-admin)
|
||||||
[accessory/view {:y position-y
|
[accessory/view {:y position-y
|
||||||
:on-update-inset on-update}
|
:on-update-inset on-update}
|
||||||
[invitation-bar chat-id]])
|
[invitation-bar chat-id]])
|
||||||
;; NOTE(rasom): on android we have to place `autocomplete-mentions`
|
[components/autocomplete-mentions text-input-ref max-bottom-space]
|
||||||
;; outside `accessory/view` because otherwise :keyboardShouldPersistTaps
|
|
||||||
;; :always doesn't work and keyboard is hidden on pressing suggestion.
|
|
||||||
;; Scrolling of suggestions doesn't work neither in this case.
|
|
||||||
(when platform/android?
|
|
||||||
[components/autocomplete-mentions text-input-ref])
|
|
||||||
(when show-input?
|
(when show-input?
|
||||||
[accessory/view {:y position-y
|
[accessory/view {:y position-y
|
||||||
:pan-state pan-state
|
:pan-state pan-state
|
||||||
:has-panel (boolean @active-panel)
|
:has-panel (boolean @active-panel)
|
||||||
:on-close #(set-active-panel nil)
|
:on-close on-close
|
||||||
:on-update-inset on-update}
|
:on-update-inset on-update}
|
||||||
[components/chat-toolbar
|
[components/chat-toolbar
|
||||||
{:active-panel @active-panel
|
{:chat-id chat-id
|
||||||
:set-active-panel set-active-panel
|
:active-panel @active-panel
|
||||||
:text-input-ref text-input-ref
|
:set-active-panel set-active-panel
|
||||||
:on-text-change on-text-change}]
|
:text-input-ref text-input-ref}]
|
||||||
[bottom-sheet @active-panel]])]))))
|
[bottom-sheet @active-panel]])]))))
|
||||||
|
@ -152,29 +152,31 @@
|
|||||||
[communities.views/community-home-list-item home-item]))
|
[communities.views/community-home-list-item home-item]))
|
||||||
|
|
||||||
(defn communities-and-chats [items loading? search-filter hide-home-tooltip?]
|
(defn communities-and-chats [items loading? search-filter hide-home-tooltip?]
|
||||||
(if loading?
|
[:<>
|
||||||
[react/view {:flex 1 :align-items :center :justify-content :center}
|
[connectivity/loading-indicator]
|
||||||
[react/activity-indicator {:animating true}]]
|
(if loading?
|
||||||
(if (and (empty? items)
|
[react/view {:flex 1 :align-items :center :justify-content :center}
|
||||||
(empty? search-filter)
|
[react/activity-indicator {:animating true}]]
|
||||||
hide-home-tooltip?
|
(if (and (empty? items)
|
||||||
(not @search-active?))
|
(empty? search-filter)
|
||||||
[welcome-blank-page]
|
hide-home-tooltip?
|
||||||
[list/flat-list
|
(not @search-active?))
|
||||||
{:key-fn :chat-id
|
[welcome-blank-page]
|
||||||
:keyboard-should-persist-taps :always
|
[list/flat-list
|
||||||
:data items
|
{:key-fn #(or (:chat-id %) (:id %))
|
||||||
:render-fn render-fn
|
:keyboard-should-persist-taps :always
|
||||||
:header [:<>
|
:data items
|
||||||
(when (or (seq items) @search-active? (seq search-filter))
|
:render-fn render-fn
|
||||||
[search-input-wrapper search-filter items])
|
:header [:<>
|
||||||
[referral-item/list-item]
|
(when (or (seq items) @search-active? (seq search-filter))
|
||||||
(when (and (empty? items)
|
[search-input-wrapper search-filter items])
|
||||||
(or @search-active? (seq search-filter)))
|
[referral-item/list-item]
|
||||||
[start-suggestion search-filter])]
|
(when (and (empty? items)
|
||||||
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
|
(or @search-active? (seq search-filter)))
|
||||||
[home-tooltip-view]
|
[start-suggestion search-filter])]
|
||||||
[react/view {:height 68}])}])))
|
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
|
||||||
|
[home-tooltip-view]
|
||||||
|
[react/view {:height 68}])}]))])
|
||||||
|
|
||||||
(views/defview chats-list []
|
(views/defview chats-list []
|
||||||
(views/letsubs [loading? [:chats/loading?]
|
(views/letsubs [loading? [:chats/loading?]
|
||||||
@ -196,6 +198,5 @@
|
|||||||
[topbar/topbar {:title (i18n/label :t/chat)
|
[topbar/topbar {:title (i18n/label :t/chat)
|
||||||
:navigation :none
|
:navigation :none
|
||||||
:right-component [connectivity/connectivity-button]}]
|
:right-component [connectivity/connectivity-button]}]
|
||||||
[connectivity/loading-indicator]
|
|
||||||
[chats-list]
|
[chats-list]
|
||||||
[plus-button]])
|
[plus-button]])
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
[status-im.ui.screens.bottom-sheets.views :as bottom-sheets]
|
[status-im.ui.screens.bottom-sheets.views :as bottom-sheets]
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.reloader :as reloader]
|
[status-im.reloader :as reloader]
|
||||||
[status-im.utils.platform :as platform]
|
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
["react-native" :as rn]
|
["react-native" :as rn]
|
||||||
["react-native-languages" :default react-native-languages]
|
["react-native-languages" :default react-native-languages]
|
||||||
@ -60,25 +59,9 @@
|
|||||||
(reagent/create-class
|
(reagent/create-class
|
||||||
{:component-did-mount
|
{:component-did-mount
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(.addListener ^js react/keyboard
|
|
||||||
(if platform/ios?
|
|
||||||
"keyboardWillShow"
|
|
||||||
"keyboardDidShow")
|
|
||||||
(fn [^js e]
|
|
||||||
(let [h (.. e -endCoordinates -height)]
|
|
||||||
(re-frame/dispatch-sync [:set :keyboard-height h])
|
|
||||||
(re-frame/dispatch-sync [:set :keyboard-max-height h]))))
|
|
||||||
(.addListener ^js react/keyboard
|
|
||||||
(if platform/ios?
|
|
||||||
"keyboardWillHide"
|
|
||||||
"keyboardDidHide")
|
|
||||||
(fn [_]
|
|
||||||
(re-frame/dispatch-sync [:set :keyboard-height 0])))
|
|
||||||
(.addEventListener ^js react/app-state "change" app-state-change-handler)
|
(.addEventListener ^js react/app-state "change" app-state-change-handler)
|
||||||
(.addEventListener react-native-languages "change" on-languages-change)
|
(.addEventListener react-native-languages "change" on-languages-change)
|
||||||
(.addEventListener react-native-shake
|
(.addEventListener react-native-shake "ShakeEvent" on-shake)
|
||||||
"ShakeEvent"
|
|
||||||
on-shake)
|
|
||||||
(.hide ^js splash-screen)
|
(.hide ^js splash-screen)
|
||||||
(utils.universal-links/initialize))
|
(utils.universal-links/initialize))
|
||||||
:component-will-unmount
|
:component-will-unmount
|
||||||
|
@ -108,39 +108,33 @@
|
|||||||
:font-size 15 :line-height 22}}
|
:font-size 15 :line-height 22}}
|
||||||
(str (i18n/format-currency (* amount price) (:code wallet-currency)) " " (:code wallet-currency))])))
|
(str (i18n/format-currency (* amount price) (:code wallet-currency)) " " (:code wallet-currency))])))
|
||||||
|
|
||||||
(views/defview select-account-sheet [{:keys [from message]}]
|
(defn select-account-sheet [{:keys [from message]}]
|
||||||
(views/letsubs [window-height [:dimensions/window-height]
|
[react/view {:style (styles/acc-sheet)}
|
||||||
keyboard-height [:keyboard-height]]
|
[header {:small-screen? false
|
||||||
(let [small-screen? (< (- window-height keyboard-height) 450)]
|
:label :t/select-account}]
|
||||||
[react/view {:style (styles/acc-sheet)}
|
[react/view {:flex-direction :row :padding-horizontal 24 :align-items :center
|
||||||
[header {:small-screen? small-screen?
|
:margin-vertical 16}]
|
||||||
:label :t/select-account}]
|
[quo/list-header
|
||||||
[react/view {:flex-direction :row :padding-horizontal 24 :align-items :center
|
(i18n/label :t/from)]
|
||||||
:margin-vertical (if small-screen? 8 16)}]
|
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
||||||
(when-not small-screen?
|
[react/view {:flex 1}
|
||||||
[quo/list-header
|
[render-account from nil ::commands/set-selected-account]]]
|
||||||
(i18n/label :t/from)])
|
[toolbar/toolbar
|
||||||
[react/view {:flex-direction :row :flex 1 :align-items :center}
|
{:left
|
||||||
(when small-screen?
|
[react/view {:padding-horizontal 8}
|
||||||
[react/i18n-text {:style {:width 50 :text-align :right :color colors/gray} :key :t/from}])
|
[quo/button
|
||||||
[react/view {:flex 1}
|
{:type :secondary
|
||||||
[render-account from nil ::commands/set-selected-account]]]
|
:on-press #(re-frame/dispatch [:set :commands/select-account nil])}
|
||||||
[toolbar/toolbar
|
(i18n/label :t/cancel)]]
|
||||||
{:left
|
:right
|
||||||
[react/view {:padding-horizontal 8}
|
[quo/button
|
||||||
[quo/button
|
{:accessibility-label :select-account-bottom-sheet
|
||||||
{:type :secondary
|
:disabled (nil? from)
|
||||||
:on-press #(re-frame/dispatch [:set :commands/select-account nil])}
|
:on-press #(re-frame/dispatch
|
||||||
(i18n/label :t/cancel)]]
|
[::commands/accept-request-address-for-transaction
|
||||||
:right
|
(:message-id message)
|
||||||
[quo/button
|
(:address from)])}
|
||||||
{:accessibility-label :select-account-bottom-sheet
|
(i18n/label :t/share)]}]])
|
||||||
:disabled (nil? from)
|
|
||||||
:on-press #(re-frame/dispatch
|
|
||||||
[::commands/accept-request-address-for-transaction
|
|
||||||
(:message-id message)
|
|
||||||
(:address from)])}
|
|
||||||
(i18n/label :t/share)]}]])))
|
|
||||||
|
|
||||||
(defview select-account []
|
(defview select-account []
|
||||||
(letsubs [data [:commands/select-account]]
|
(letsubs [data [:commands/select-account]]
|
||||||
|
@ -60,8 +60,6 @@
|
|||||||
;; TODO: Add message explaining db export
|
;; TODO: Add message explaining db export
|
||||||
(let [db-json (types/clj->json (select-keys db [:app-state
|
(let [db-json (types/clj->json (select-keys db [:app-state
|
||||||
:current-chat-id
|
:current-chat-id
|
||||||
:keyboard-height
|
|
||||||
:keyboard-max-height
|
|
||||||
:network
|
:network
|
||||||
:network-status
|
:network-status
|
||||||
:peers-count
|
:peers-count
|
||||||
|
Loading…
x
Reference in New Issue
Block a user