Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e3b207c3b | ||
|
|
f03671097b | ||
|
|
1db63a9fa1 | ||
|
|
cd92b41214 | ||
|
|
56f7206da7 | ||
|
|
eb5de3506a | ||
|
|
22005f916e | ||
|
|
ff50aacb3a | ||
|
|
91300b9ff8 | ||
|
|
d93b20242a | ||
|
|
0a43e5c97a |
@@ -107,14 +107,15 @@
|
|||||||
[{:keys [db] :as cofx} message]
|
[{:keys [db] :as cofx} message]
|
||||||
(let [current-chat-id (:current-chat-id db)
|
(let [current-chat-id (:current-chat-id db)
|
||||||
text (get-in message [:content :text])]
|
text (get-in message [:content :text])]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
|
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
|
||||||
message)
|
message)
|
||||||
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
|
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
|
||||||
(update-in [:chat/inputs current-chat-id :metadata]
|
(update-in [:chat/inputs current-chat-id :metadata]
|
||||||
dissoc
|
dissoc
|
||||||
:sending-image))
|
:sending-image))
|
||||||
:dispatch [:mention/to-input-field text current-chat-id]}))
|
:dispatch-n [[:chat.ui/set-chat-input-text nil current-chat-id]
|
||||||
|
[:mention/to-input-field text current-chat-id]]}))
|
||||||
|
|
||||||
(rf/defn show-contact-request-input
|
(rf/defn show-contact-request-input
|
||||||
"Sets reference to previous chat message and focuses on input"
|
"Sets reference to previous chat message and focuses on input"
|
||||||
|
|||||||
@@ -225,7 +225,9 @@
|
|||||||
(.. ^js % -nativeEvent -data)])
|
(.. ^js % -nativeEvent -data)])
|
||||||
:on-load #(re-frame/dispatch [:browser/loading-started])
|
:on-load #(re-frame/dispatch [:browser/loading-started])
|
||||||
:on-error #(re-frame/dispatch [:browser/error-occured])
|
:on-error #(re-frame/dispatch [:browser/error-occured])
|
||||||
:injected-java-script-before-content-loaded (js-res/ethereum-provider (str network-id))}])]
|
:injected-java-script-before-content-loaded (js-res/ethereum-provider (str network-id))
|
||||||
|
;; https://github.com/status-im/status-mobile/issues/17854
|
||||||
|
:allows-inline-media-playback true}])]
|
||||||
[navigation
|
[navigation
|
||||||
{:url url-original
|
{:url url-original
|
||||||
:name name
|
:name name
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
(ns status-im2.common.standard-authentication.core
|
||||||
|
(:require
|
||||||
|
status-im2.common.standard-authentication.standard-auth.button.view
|
||||||
|
status-im2.common.standard-authentication.standard-auth.slide-button.view))
|
||||||
|
|
||||||
|
(def button status-im2.common.standard-authentication.standard-auth.button.view/view)
|
||||||
|
(def slide-button status-im2.common.standard-authentication.standard-auth.slide-button.view/view)
|
||||||
+1
-41
@@ -1,10 +1,6 @@
|
|||||||
(ns status-im2.common.standard-authentication.standard-auth.view
|
(ns status-im2.common.standard-authentication.standard-auth.authorize
|
||||||
(:require
|
(:require
|
||||||
[quo.core :as quo]
|
|
||||||
[quo.theme :as quo.theme]
|
|
||||||
[react-native.core :as rn]
|
|
||||||
[react-native.touch-id :as biometric]
|
[react-native.touch-id :as biometric]
|
||||||
[reagent.core :as reagent]
|
|
||||||
[status-im2.common.standard-authentication.enter-password.view :as enter-password]
|
[status-im2.common.standard-authentication.enter-password.view :as enter-password]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
@@ -46,39 +42,3 @@
|
|||||||
{:on-enter-password on-enter-password
|
{:on-enter-password on-enter-password
|
||||||
:button-icon-left auth-button-icon-left
|
:button-icon-left auth-button-icon-left
|
||||||
:button-label auth-button-label}])}]))))))
|
:button-label auth-button-label}])}]))))))
|
||||||
|
|
||||||
(defn- view-internal
|
|
||||||
[_]
|
|
||||||
(let [reset-slider? (reagent/atom false)
|
|
||||||
on-close #(reset! reset-slider? true)]
|
|
||||||
(fn [{:keys [biometric-auth?
|
|
||||||
track-text
|
|
||||||
customization-color
|
|
||||||
auth-button-label
|
|
||||||
on-enter-password
|
|
||||||
on-auth-success
|
|
||||||
on-auth-fail
|
|
||||||
auth-button-icon-left
|
|
||||||
size
|
|
||||||
theme
|
|
||||||
blur?
|
|
||||||
container-style]}]
|
|
||||||
[rn/view {:style {:flex 1}}
|
|
||||||
[quo/slide-button
|
|
||||||
{:size size
|
|
||||||
:container-style container-style
|
|
||||||
:customization-color customization-color
|
|
||||||
:on-reset (when @reset-slider? #(reset! reset-slider? false))
|
|
||||||
:on-complete #(authorize {:on-close on-close
|
|
||||||
:auth-button-icon-left auth-button-icon-left
|
|
||||||
:theme theme
|
|
||||||
:blur? blur?
|
|
||||||
:on-enter-password on-enter-password
|
|
||||||
:biometric-auth? biometric-auth?
|
|
||||||
:on-auth-success on-auth-success
|
|
||||||
:on-auth-fail on-auth-fail
|
|
||||||
:auth-button-label auth-button-label})
|
|
||||||
:track-icon (if biometric-auth? :i/face-id :password)
|
|
||||||
:track-text track-text}]])))
|
|
||||||
|
|
||||||
(def view (quo.theme/with-theme view-internal))
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
(ns status-im2.common.standard-authentication.standard-auth.button.view
|
||||||
|
(:require
|
||||||
|
[quo.core :as quo]
|
||||||
|
[quo.theme :as quo.theme]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]))
|
||||||
|
|
||||||
|
(defn- view-internal
|
||||||
|
[_]
|
||||||
|
(let [reset-slider? (reagent/atom false)
|
||||||
|
on-close #(reset! reset-slider? true)]
|
||||||
|
(fn [{:keys [biometric-auth?
|
||||||
|
customization-color
|
||||||
|
auth-button-label
|
||||||
|
on-enter-password
|
||||||
|
on-auth-success
|
||||||
|
on-press
|
||||||
|
on-auth-fail
|
||||||
|
auth-button-icon-left
|
||||||
|
size
|
||||||
|
button-label
|
||||||
|
theme
|
||||||
|
blur?
|
||||||
|
container-style
|
||||||
|
icon-left]}]
|
||||||
|
[quo/button
|
||||||
|
{:size size
|
||||||
|
:container-style container-style
|
||||||
|
:customization-color customization-color
|
||||||
|
:icon-left icon-left
|
||||||
|
:on-press (if on-press
|
||||||
|
on-press
|
||||||
|
#(authorize/authorize {:on-close on-close
|
||||||
|
:auth-button-icon-left auth-button-icon-left
|
||||||
|
:theme theme
|
||||||
|
:blur? blur?
|
||||||
|
:on-enter-password on-enter-password
|
||||||
|
:biometric-auth? biometric-auth?
|
||||||
|
:on-auth-success on-auth-success
|
||||||
|
:on-auth-fail on-auth-fail
|
||||||
|
:auth-button-label auth-button-label}))}
|
||||||
|
button-label])))
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme view-internal))
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
(ns status-im2.common.standard-authentication.standard-auth.slide-button.view
|
||||||
|
(:require
|
||||||
|
[quo.core :as quo]
|
||||||
|
[quo.theme :as quo.theme]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]))
|
||||||
|
|
||||||
|
(defn- view-internal
|
||||||
|
[_]
|
||||||
|
(let [reset-slider? (reagent/atom false)
|
||||||
|
on-close #(reset! reset-slider? true)]
|
||||||
|
(fn [{:keys [biometric-auth?
|
||||||
|
track-text
|
||||||
|
customization-color
|
||||||
|
auth-button-label
|
||||||
|
on-enter-password
|
||||||
|
on-auth-success
|
||||||
|
on-auth-fail
|
||||||
|
auth-button-icon-left
|
||||||
|
size
|
||||||
|
theme
|
||||||
|
blur?
|
||||||
|
container-style]}]
|
||||||
|
[rn/view {:style {:flex 1}}
|
||||||
|
[quo/slide-button
|
||||||
|
{:size size
|
||||||
|
:container-style container-style
|
||||||
|
:customization-color customization-color
|
||||||
|
:on-reset (when @reset-slider? #(reset! reset-slider? false))
|
||||||
|
:on-complete #(authorize/authorize {:on-close on-close
|
||||||
|
:auth-button-icon-left auth-button-icon-left
|
||||||
|
:theme theme
|
||||||
|
:blur? blur?
|
||||||
|
:on-enter-password on-enter-password
|
||||||
|
:biometric-auth? biometric-auth?
|
||||||
|
:on-auth-success on-auth-success
|
||||||
|
:on-auth-fail on-auth-fail
|
||||||
|
:auth-button-label auth-button-label})
|
||||||
|
:track-icon (if biometric-auth? :i/face-id :password)
|
||||||
|
:track-text track-text}]])))
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme view-internal))
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn edit-message
|
(defn edit-message
|
||||||
[state]
|
[{:keys [text-value input-ref]}]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style style/container
|
{:style style/container
|
||||||
:accessibility-label :edit-message}
|
:accessibility-label :edit-message}
|
||||||
@@ -30,20 +30,18 @@
|
|||||||
{:size 24
|
{:size 24
|
||||||
:icon-only? true
|
:icon-only? true
|
||||||
:accessibility-label :edit-cancel-button
|
:accessibility-label :edit-cancel-button
|
||||||
:on-press (fn []
|
:on-press #(utils/cancel-edit-message text-value input-ref)
|
||||||
(utils/cancel-edit-message state)
|
|
||||||
(rf/dispatch [:chat.ui/cancel-message-edit]))
|
|
||||||
:type :outline}
|
:type :outline}
|
||||||
:i/close]])
|
:i/close]])
|
||||||
|
|
||||||
(defn- f-view
|
(defn- f-view
|
||||||
[state]
|
[props]
|
||||||
(let [edit (rf/sub [:chats/edit-message])
|
(let [edit (rf/sub [:chats/edit-message])
|
||||||
height (reanimated/use-shared-value (if edit constants/edit-container-height 0))]
|
height (reanimated/use-shared-value (if edit constants/edit-container-height 0))]
|
||||||
(rn/use-effect #(reanimated/animate height (if edit constants/edit-container-height 0)) [edit])
|
(rn/use-effect #(reanimated/animate height (if edit constants/edit-container-height 0)) [edit])
|
||||||
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
||||||
(when edit [edit-message state])]))
|
(when edit [edit-message props])]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[state]
|
[props]
|
||||||
[:f> f-view state])
|
[:f> f-view props])
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
|
[reagent.core :as reagent]
|
||||||
[status-im2.contexts.chat.composer.constants :as constants]
|
[status-im2.contexts.chat.composer.constants :as constants]
|
||||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||||
[status-im2.contexts.chat.composer.utils :as utils]
|
[status-im2.contexts.chat.composer.utils :as utils]
|
||||||
@@ -105,53 +106,62 @@
|
|||||||
|
|
||||||
(defn use-edit
|
(defn use-edit
|
||||||
[{:keys [input-ref]}
|
[{:keys [input-ref]}
|
||||||
{:keys [text-value saved-cursor-position]}
|
{:keys [text-value saved-cursor-position cursor-position]}
|
||||||
{:keys [edit]}]
|
{:keys [edit input-with-mentions]}
|
||||||
(rn/use-effect
|
messages-list-on-layout-finished?]
|
||||||
(fn []
|
(let [mention? (some #(= :mention (first %)) (seq input-with-mentions))
|
||||||
(let [edit-text (get-in edit [:content :text])
|
composer-just-opened? (not @messages-list-on-layout-finished?)]
|
||||||
text-value-count (count @text-value)]
|
(rn/use-effect
|
||||||
(when (and edit @input-ref)
|
(fn []
|
||||||
;; A small setTimeout is necessary to ensure the statement is enqueued and will get executed
|
(let [mention-text (reduce (fn [acc item]
|
||||||
;; ASAP.
|
(str acc (second item)))
|
||||||
;; https://github.com/software-mansion/react-native-screens/issues/472
|
""
|
||||||
(js/setTimeout #(.focus ^js @input-ref) 250)
|
input-with-mentions)
|
||||||
(.setNativeProps ^js @input-ref (clj->js {:text edit-text}))
|
edit-text (cond
|
||||||
(reset! text-value edit-text)
|
mention? mention-text
|
||||||
(reset! saved-cursor-position (if (zero? text-value-count)
|
;; NOTE: using text-value for cases when the user
|
||||||
(count edit-text)
|
;; leaves the app with an unfinished edit and re-opens
|
||||||
text-value-count)))))
|
;; the chat.
|
||||||
[(:message-id edit)]))
|
(and (seq @text-value) composer-just-opened?)
|
||||||
|
@text-value
|
||||||
|
:else (get-in edit [:content :text]))
|
||||||
|
selection-pos (count edit-text)
|
||||||
|
inject-edit-text (fn []
|
||||||
|
(reset! text-value edit-text)
|
||||||
|
(reset! cursor-position selection-pos)
|
||||||
|
(reset! saved-cursor-position selection-pos)
|
||||||
|
(when @input-ref
|
||||||
|
(.setNativeProps ^js @input-ref
|
||||||
|
(clj->js {:text edit-text}))))]
|
||||||
|
|
||||||
|
(when (and edit @input-ref)
|
||||||
|
;; NOTE: A small setTimeout is necessary to ensure the focus is enqueued and is executed
|
||||||
|
;; ASAP. Check https://github.com/software-mansion/react-native-screens/issues/472
|
||||||
|
;;
|
||||||
|
;; The nested setTimeout is necessary to avoid both `on-focus` and
|
||||||
|
;; `on-content-size-change` handlers triggering the height animation simultaneously, as
|
||||||
|
;; this causes a jump in the
|
||||||
|
;; UI. This way, `on-focus` will trigger first without changing the height, after which
|
||||||
|
;; `on-content-size-change` will animate the height of the input based on the injected
|
||||||
|
;; text.
|
||||||
|
(js/setTimeout #(do (when @messages-list-on-layout-finished? (.focus ^js @input-ref))
|
||||||
|
(reagent/next-tick inject-edit-text))
|
||||||
|
600))))
|
||||||
|
[(:message-id edit)])))
|
||||||
|
|
||||||
(defn use-reply
|
(defn use-reply
|
||||||
[{:keys [input-ref]}
|
[{:keys [input-ref]}
|
||||||
{:keys [container-opacity]}
|
{:keys [container-opacity]}
|
||||||
{:keys [reply]}]
|
{:keys [reply]}
|
||||||
|
messages-list-on-layout-finished?]
|
||||||
(rn/use-effect
|
(rn/use-effect
|
||||||
(fn []
|
(fn []
|
||||||
(when reply
|
(when reply
|
||||||
(reanimated/animate container-opacity 1))
|
(reanimated/animate container-opacity 1))
|
||||||
(when (and reply @input-ref)
|
(when (and reply @input-ref @messages-list-on-layout-finished?)
|
||||||
(js/setTimeout #(.focus ^js @input-ref) 250)))
|
(js/setTimeout #(.focus ^js @input-ref) 600)))
|
||||||
[(:message-id reply)]))
|
[(:message-id reply)]))
|
||||||
|
|
||||||
(defn edit-mentions
|
|
||||||
[{:keys [input-ref]} {:keys [text-value cursor-position]} {:keys [input-with-mentions]}]
|
|
||||||
(rn/use-effect (fn []
|
|
||||||
(let [input-text (reduce (fn [acc item]
|
|
||||||
(str acc (second item)))
|
|
||||||
""
|
|
||||||
input-with-mentions)]
|
|
||||||
(reset! text-value input-text)
|
|
||||||
(reset! cursor-position (count input-text))
|
|
||||||
(js/setTimeout #(when @input-ref
|
|
||||||
(.setNativeProps ^js @input-ref
|
|
||||||
(clj->js {:selection {:start (count input-text)
|
|
||||||
:end (count
|
|
||||||
input-text)}})))
|
|
||||||
300)))
|
|
||||||
[(some #(= :mention (first %)) (seq input-with-mentions))]))
|
|
||||||
|
|
||||||
(defn update-input-mention
|
(defn update-input-mention
|
||||||
[{:keys [input-ref]}
|
[{:keys [input-ref]}
|
||||||
{:keys [text-value]}
|
{:keys [text-value]}
|
||||||
|
|||||||
@@ -43,8 +43,7 @@
|
|||||||
(reset! emoji-kb-extra-height nil))
|
(reset! emoji-kb-extra-height nil))
|
||||||
(reset! maximized? false)
|
(reset! maximized? false)
|
||||||
(rf/dispatch [:chat.ui/set-input-maximized false])
|
(rf/dispatch [:chat.ui/set-input-maximized false])
|
||||||
(when @input-ref
|
(utils/blur-input input-ref))
|
||||||
(.blur ^js @input-ref)))
|
|
||||||
|
|
||||||
(defn bounce-back
|
(defn bounce-back
|
||||||
[{:keys [height saved-height opacity background-y]}
|
[{:keys [height saved-height opacity background-y]}
|
||||||
@@ -96,13 +95,13 @@
|
|||||||
max-height
|
max-height
|
||||||
bounded-height
|
bounded-height
|
||||||
saved-height))
|
saved-height))
|
||||||
(when @input-ref ; sheet at min-height, collapse keyboard
|
; sheet at min-height, collapse keyboard
|
||||||
(.blur ^js @input-ref)))))))
|
(utils/blur-input input-ref))))))
|
||||||
(gesture/on-end (fn []
|
(gesture/on-end (fn []
|
||||||
(let [diff (- (reanimated/get-shared-value height)
|
(let [diff (- (reanimated/get-shared-value height)
|
||||||
(reanimated/get-shared-value saved-height))]
|
(reanimated/get-shared-value saved-height))]
|
||||||
(if @gesture-enabled?
|
(if @gesture-enabled?
|
||||||
(if (>= diff 0)
|
(if (and @expanding? (>= diff 0))
|
||||||
(if (> diff constants/drag-threshold)
|
(if (> diff constants/drag-threshold)
|
||||||
(maximize state animations dimensions)
|
(maximize state animations dimensions)
|
||||||
(bounce-back animations dimensions starting-opacity))
|
(bounce-back animations dimensions starting-opacity))
|
||||||
|
|||||||
@@ -23,12 +23,14 @@
|
|||||||
show-floating-scroll-down-button?]
|
show-floating-scroll-down-button?]
|
||||||
(reset! focused? true)
|
(reset! focused? true)
|
||||||
(rf/dispatch [:chat.ui/set-input-focused true])
|
(rf/dispatch [:chat.ui/set-input-focused true])
|
||||||
(reanimated/animate height (reanimated/get-shared-value last-height))
|
(let [last-height-value (reanimated/get-shared-value last-height)]
|
||||||
(reanimated/set-shared-value saved-height (reanimated/get-shared-value last-height))
|
(reanimated/animate height last-height-value)
|
||||||
(reanimated/animate container-opacity 1)
|
(reanimated/set-shared-value saved-height last-height-value)
|
||||||
(when (> (reanimated/get-shared-value last-height) (* constants/background-threshold max-height))
|
(reanimated/animate container-opacity 1)
|
||||||
(reanimated/animate opacity 1)
|
(when (> last-height-value (* constants/background-threshold max-height))
|
||||||
(reanimated/set-shared-value background-y 0))
|
(reanimated/animate opacity 1)
|
||||||
|
(reanimated/set-shared-value background-y 0)))
|
||||||
|
|
||||||
(js/setTimeout #(reset! lock-selection? false) 300)
|
(js/setTimeout #(reset! lock-selection? false) 300)
|
||||||
(when (and (not-empty @text-value) @input-ref)
|
(when (and (not-empty @text-value) @input-ref)
|
||||||
(.setNativeProps ^js @input-ref
|
(.setNativeProps ^js @input-ref
|
||||||
@@ -72,7 +74,7 @@
|
|||||||
"Save new text height, expand composer if possible, show background overlay if needed"
|
"Save new text height, expand composer if possible, show background overlay if needed"
|
||||||
[event
|
[event
|
||||||
{:keys [maximized? lock-layout? text-value]}
|
{:keys [maximized? lock-layout? text-value]}
|
||||||
{:keys [height saved-height opacity background-y]}
|
{:keys [height saved-height last-height opacity background-y]}
|
||||||
{:keys [content-height window-height max-height]}
|
{:keys [content-height window-height max-height]}
|
||||||
keyboard-shown]
|
keyboard-shown]
|
||||||
(when keyboard-shown
|
(when keyboard-shown
|
||||||
@@ -87,8 +89,9 @@
|
|||||||
max-height)
|
max-height)
|
||||||
new-height (min new-height max-height)]
|
new-height (min new-height max-height)]
|
||||||
(reset! content-height content-size)
|
(reset! content-height content-size)
|
||||||
(when (utils/update-height? content-size height max-height maximized?)
|
(when (utils/update-height? content-size height max-height)
|
||||||
(reanimated/animate height new-height)
|
(reanimated/animate height new-height)
|
||||||
|
(reanimated/set-shared-value last-height new-height)
|
||||||
(reanimated/set-shared-value saved-height new-height))
|
(reanimated/set-shared-value saved-height new-height))
|
||||||
(when (= new-height max-height)
|
(when (= new-height max-height)
|
||||||
(reset! maximized? true)
|
(reset! maximized? true)
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
[react-native.async-storage :as async-storage]
|
[react-native.async-storage :as async-storage]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[react-native.reanimated :as reanimated]))
|
[react-native.reanimated :as reanimated]
|
||||||
|
[status-im2.contexts.chat.composer.utils :as utils]))
|
||||||
|
|
||||||
(defn get-kb-height
|
(defn get-kb-height
|
||||||
[curr-height default-height]
|
[curr-height default-height]
|
||||||
@@ -20,18 +21,24 @@
|
|||||||
(async-storage/set-item! :kb-default-height (str height)))))
|
(async-storage/set-item! :kb-default-height (str height)))))
|
||||||
|
|
||||||
(defn handle-emoji-kb-ios
|
(defn handle-emoji-kb-ios
|
||||||
"Opening emoji KB on iOS while maximized will cause a flicker up and down. This method handles that."
|
"Opening emoji KB on iOS will cause a flicker up and down due to height differences.
|
||||||
|
This method handles that by adding the extra difference between the keyboards. When the input is
|
||||||
|
expanded to a point where the added difference will make the composer go beyond the screen causing a flicker,
|
||||||
|
we're subtracting the difference so it only reaches the allowed max-height. We're not animating these
|
||||||
|
changes to make it appear seamless during transitions between keyboard types when maximized."
|
||||||
[event
|
[event
|
||||||
{:keys [emoji-kb-extra-height]}
|
{:keys [emoji-kb-extra-height]}
|
||||||
{:keys [text-value]}
|
{:keys [text-value kb-height]}
|
||||||
{:keys [height saved-height]}
|
{:keys [height saved-height]}
|
||||||
{:keys [max-height]}]
|
{:keys [max-height]}]
|
||||||
(let [start-h (oops/oget event "startCoordinates.height")
|
(let [start-h (oops/oget event "startCoordinates.height")
|
||||||
end-h (oops/oget event "endCoordinates.height")
|
end-h (oops/oget event "endCoordinates.height")
|
||||||
diff (- end-h start-h)
|
diff (- end-h start-h)
|
||||||
max-height-diff (- max-height diff)
|
max-height-diff (- max-height diff)
|
||||||
curr-text @text-value]
|
curr-text @text-value
|
||||||
(if (> (reanimated/get-shared-value height) max-height-diff)
|
bigger-than-default-kb? (> end-h @kb-height)
|
||||||
|
almost-expanded? (> (reanimated/get-shared-value height) max-height-diff)]
|
||||||
|
(if (and almost-expanded? bigger-than-default-kb? (pos? diff))
|
||||||
(do
|
(do
|
||||||
(reanimated/set-shared-value height (- (reanimated/get-shared-value height) diff))
|
(reanimated/set-shared-value height (- (reanimated/get-shared-value height) diff))
|
||||||
(reanimated/set-shared-value saved-height (- (reanimated/get-shared-value saved-height) diff))
|
(reanimated/set-shared-value saved-height (- (reanimated/get-shared-value saved-height) diff))
|
||||||
@@ -58,8 +65,8 @@
|
|||||||
#(handle-emoji-kb-ios % props state animations dimensions)))
|
#(handle-emoji-kb-ios % props state animations dimensions)))
|
||||||
(reset! keyboard-hide-listener (.addListener rn/keyboard
|
(reset! keyboard-hide-listener (.addListener rn/keyboard
|
||||||
"keyboardDidHide"
|
"keyboardDidHide"
|
||||||
#(when (and platform/android? @input-ref)
|
#(when platform/android?
|
||||||
(.blur ^js @input-ref)))))
|
(utils/blur-input input-ref)))))
|
||||||
|
|
||||||
(defn handle-refocus-emoji-kb-ios
|
(defn handle-refocus-emoji-kb-ios
|
||||||
[{:keys [saved-emoji-kb-extra-height]}
|
[{:keys [saved-emoji-kb-extra-height]}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[status-im2.constants :as constant]
|
[status-im2.constants :as constant]
|
||||||
[status-im2.contexts.chat.composer.constants :as constants]
|
[status-im2.contexts.chat.composer.constants :as constants]
|
||||||
[status-im2.contexts.chat.composer.reply.style :as style]
|
[status-im2.contexts.chat.composer.reply.style :as style]
|
||||||
|
[status-im2.contexts.chat.composer.utils :as utils]
|
||||||
[utils.ens.stateofus :as stateofus]
|
[utils.ens.stateofus :as stateofus]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
@@ -85,7 +86,7 @@
|
|||||||
(defn quoted-message
|
(defn quoted-message
|
||||||
[{:keys [from content-type contentType parsed-text content deleted? deleted-for-me?
|
[{:keys [from content-type contentType parsed-text content deleted? deleted-for-me?
|
||||||
album-images-count]}
|
album-images-count]}
|
||||||
in-chat-input? pin? recording-audio?]
|
in-chat-input? pin? recording-audio? input-ref]
|
||||||
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])
|
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])
|
||||||
current-public-key (rf/sub [:multiaccount/public-key])
|
current-public-key (rf/sub [:multiaccount/public-key])
|
||||||
content-type (or content-type contentType)
|
content-type (or content-type contentType)
|
||||||
@@ -136,7 +137,7 @@
|
|||||||
{:icon-only? true
|
{:icon-only? true
|
||||||
:size 24
|
:size 24
|
||||||
:accessibility-label :reply-cancel-button
|
:accessibility-label :reply-cancel-button
|
||||||
:on-press #(rf/dispatch [:chat.ui/cancel-message-reply])
|
:on-press #(utils/cancel-reply-message input-ref)
|
||||||
:type :outline}
|
:type :outline}
|
||||||
:i/close])
|
:i/close])
|
||||||
(when (and in-chat-input? recording-audio?)
|
(when (and in-chat-input? recording-audio?)
|
||||||
@@ -148,13 +149,13 @@
|
|||||||
:style style/gradient}])]))
|
:style style/gradient}])]))
|
||||||
|
|
||||||
(defn- f-view
|
(defn- f-view
|
||||||
[recording?]
|
[recording? input-ref]
|
||||||
(let [reply (rf/sub [:chats/reply-message])
|
(let [reply (rf/sub [:chats/reply-message])
|
||||||
height (reanimated/use-shared-value (if reply constants/reply-container-height 0))]
|
height (reanimated/use-shared-value (if reply constants/reply-container-height 0))]
|
||||||
(rn/use-effect #(reanimated/animate height (if reply constants/reply-container-height 0)) [reply])
|
(rn/use-effect #(reanimated/animate height (if reply constants/reply-container-height 0)) [reply])
|
||||||
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
||||||
(when reply [quoted-message reply true false recording?])]))
|
(when reply [quoted-message reply true false recording? input-ref])]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [recording?]}]
|
[{:keys [recording?]} input-ref]
|
||||||
[:f> f-view @recording?])
|
[:f> f-view @recording? input-ref])
|
||||||
|
|||||||
@@ -16,11 +16,10 @@
|
|||||||
(max min-v (min v max-v)))
|
(max min-v (min v max-v)))
|
||||||
|
|
||||||
(defn update-height?
|
(defn update-height?
|
||||||
[content-size height max-height maximized?]
|
[content-size height max-height]
|
||||||
(when-not @maximized?
|
(let [diff (Math/abs (- content-size (reanimated/get-shared-value height)))]
|
||||||
(let [diff (Math/abs (- content-size (reanimated/get-shared-value height)))]
|
(and (not= (reanimated/get-shared-value height) max-height)
|
||||||
(and (not= (reanimated/get-shared-value height) max-height)
|
(> diff constants/content-change-threshold))))
|
||||||
(> diff constants/content-change-threshold)))))
|
|
||||||
|
|
||||||
(defn show-top-gradient?
|
(defn show-top-gradient?
|
||||||
[y lines max-lines gradient-opacity focused?]
|
[y lines max-lines gradient-opacity focused?]
|
||||||
@@ -100,10 +99,28 @@
|
|||||||
(not reply?)
|
(not reply?)
|
||||||
(not audio?)))
|
(not audio?)))
|
||||||
|
|
||||||
|
(defn blur-input
|
||||||
|
[input-ref]
|
||||||
|
(when @input-ref
|
||||||
|
(rf/dispatch [:chat.ui/set-input-focused false])
|
||||||
|
(.blur ^js @input-ref)))
|
||||||
|
|
||||||
|
(defn cancel-reply-message
|
||||||
|
[input-ref]
|
||||||
|
(js/setTimeout #(blur-input input-ref) 100)
|
||||||
|
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height])
|
||||||
|
(rf/dispatch [:chat.ui/cancel-message-reply]))
|
||||||
|
|
||||||
(defn cancel-edit-message
|
(defn cancel-edit-message
|
||||||
[{:keys [text-value]}]
|
[text-value input-ref]
|
||||||
(reset! text-value "")
|
(reset! text-value "")
|
||||||
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
|
;; NOTE: adding a timeout to assure the input is blurred on the next tick
|
||||||
|
;; after the `text-value` was cleared. Otherwise the height will be calculated
|
||||||
|
;; with the old `text-value`, leading to wrong composer height after blur.
|
||||||
|
(js/setTimeout #(blur-input input-ref) 100)
|
||||||
|
(.setNativeProps ^js @input-ref (clj->js {:text ""}))
|
||||||
|
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height])
|
||||||
|
(rf/dispatch [:chat.ui/cancel-message-edit]))
|
||||||
|
|
||||||
(defn count-lines
|
(defn count-lines
|
||||||
[s]
|
[s]
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
blur-height
|
blur-height
|
||||||
opacity
|
opacity
|
||||||
background-y
|
background-y
|
||||||
theme]} props state]
|
theme
|
||||||
|
messages-list-on-layout-finished?]} props state]
|
||||||
(let [{:keys [chat-screen-loaded?]
|
(let [{:keys [chat-screen-loaded?]
|
||||||
:as subscriptions} (utils/init-subs)
|
:as subscriptions} (utils/init-subs)
|
||||||
content-height (reagent/atom (or (:input-content-height ; Actual text height
|
content-height (reagent/atom (or (:input-content-height ; Actual text height
|
||||||
@@ -73,10 +74,9 @@
|
|||||||
animations
|
animations
|
||||||
dimensions
|
dimensions
|
||||||
subscriptions)
|
subscriptions)
|
||||||
(effects/use-edit props state subscriptions)
|
(effects/use-edit props state subscriptions messages-list-on-layout-finished?)
|
||||||
(effects/use-reply props animations subscriptions)
|
(effects/use-reply props animations subscriptions messages-list-on-layout-finished?)
|
||||||
(effects/update-input-mention props state subscriptions)
|
(effects/update-input-mention props state subscriptions)
|
||||||
(effects/edit-mentions props state subscriptions)
|
|
||||||
(effects/link-previews props state animations subscriptions)
|
(effects/link-previews props state animations subscriptions)
|
||||||
(effects/use-images props state animations subscriptions)
|
(effects/use-images props state animations subscriptions)
|
||||||
[:<>
|
[:<>
|
||||||
@@ -98,8 +98,10 @@
|
|||||||
[sub-view/bar]
|
[sub-view/bar]
|
||||||
(when chat-screen-loaded?
|
(when chat-screen-loaded?
|
||||||
[:<>
|
[:<>
|
||||||
[reply/view state]
|
[reply/view state (:input-ref props)]
|
||||||
[edit/view state]])
|
[edit/view
|
||||||
|
{:text-value (:text-value state)
|
||||||
|
:input-ref (:input-ref props)}]])
|
||||||
[reanimated/touchable-opacity
|
[reanimated/touchable-opacity
|
||||||
{:active-opacity 1
|
{:active-opacity 1
|
||||||
:on-press (fn []
|
:on-press (fn []
|
||||||
@@ -147,11 +149,13 @@
|
|||||||
subscriptions]]]]]))
|
subscriptions]]]]]))
|
||||||
|
|
||||||
(defn composer
|
(defn composer
|
||||||
[{:keys [insets scroll-to-bottom-fn show-floating-scroll-down-button?]}]
|
[{:keys [insets scroll-to-bottom-fn show-floating-scroll-down-button?
|
||||||
|
messages-list-on-layout-finished?]}]
|
||||||
(let [window-height (:height (rn/get-window))
|
(let [window-height (:height (rn/get-window))
|
||||||
theme (quo.theme/use-theme-value)
|
theme (quo.theme/use-theme-value)
|
||||||
opacity (reanimated/use-shared-value 0)
|
opacity (reanimated/use-shared-value 0)
|
||||||
background-y (reanimated/use-shared-value (- window-height)) ; Y position of background overlay
|
background-y (reanimated/use-shared-value (- window-height)) ; Y position of background
|
||||||
|
; overlay
|
||||||
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
|
blur-height (reanimated/use-shared-value (+ constants/composer-default-height
|
||||||
(:bottom insets)))
|
(:bottom insets)))
|
||||||
extra-params {:insets insets
|
extra-params {:insets insets
|
||||||
@@ -161,7 +165,8 @@
|
|||||||
:blur-height blur-height
|
:blur-height blur-height
|
||||||
:opacity opacity
|
:opacity opacity
|
||||||
:background-y background-y
|
:background-y background-y
|
||||||
:theme theme}
|
:theme theme
|
||||||
|
:messages-list-on-layout-finished? messages-list-on-layout-finished?}
|
||||||
props (utils/init-non-reactive-state)
|
props (utils/init-non-reactive-state)
|
||||||
state (utils/init-reactive-state)]
|
state (utils/init-reactive-state)]
|
||||||
[rn/view (when platform/ios? {:style {:z-index 1}})
|
[rn/view (when platform/ios? {:style {:z-index 1}})
|
||||||
|
|||||||
@@ -298,7 +298,7 @@
|
|||||||
|
|
||||||
(defn f-messages-list-content
|
(defn f-messages-list-content
|
||||||
[{:keys [chat insets scroll-y content-height cover-bg-color keyboard-shown? inner-state-atoms
|
[{:keys [chat insets scroll-y content-height cover-bg-color keyboard-shown? inner-state-atoms
|
||||||
big-name-visible? animate-topbar-opacity? composer-active?
|
big-name-visible? animate-topbar-opacity? composer-active? messages-list-on-layout-finished?
|
||||||
on-end-reached? animate-topbar-name?]}]
|
on-end-reached? animate-topbar-name?]}]
|
||||||
(rn/use-effect (fn []
|
(rn/use-effect (fn []
|
||||||
(if (and (not @on-end-reached?)
|
(if (and (not @on-end-reached?)
|
||||||
@@ -412,6 +412,15 @@
|
|||||||
;;TODO(rasom) https://github.com/facebook/react-native/issues/30034
|
;;TODO(rasom) https://github.com/facebook/react-native/issues/30034
|
||||||
:inverted (when platform/ios? true)
|
:inverted (when platform/ios? true)
|
||||||
:on-layout (fn [e]
|
:on-layout (fn [e]
|
||||||
|
;; FIXME: the 1s timeout is to assure all effects with
|
||||||
|
;; timeouts that depend on the value are considered.
|
||||||
|
;; Hacky, but we're heavily relying on timeouts in the
|
||||||
|
;; composer and need to react to differently (e.g.
|
||||||
|
;; inside effects/use-edit) when the chat has just
|
||||||
|
;; opened and the subsequent times.
|
||||||
|
(js/setTimeout #(reset! messages-list-on-layout-finished?
|
||||||
|
true)
|
||||||
|
1000)
|
||||||
(let [layout-height (oops/oget e
|
(let [layout-height (oops/oget e
|
||||||
"nativeEvent.layout.height")]
|
"nativeEvent.layout.height")]
|
||||||
(reset! messages-view-height layout-height)))
|
(reset! messages-view-height layout-height)))
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
(defn f-chat
|
(defn f-chat
|
||||||
[{:keys [show-floating-scroll-down-button? animate-topbar-name?
|
[{:keys [show-floating-scroll-down-button? animate-topbar-name?
|
||||||
big-name-visible? animate-topbar-opacity? on-end-reached?]
|
big-name-visible? animate-topbar-opacity? on-end-reached? messages-list-on-layout-finished?]
|
||||||
:as inner-state-atoms}]
|
:as inner-state-atoms}]
|
||||||
(let [insets (safe-area/get-insets)
|
(let [insets (safe-area/get-insets)
|
||||||
scroll-y (reanimated/use-shared-value 0)
|
scroll-y (reanimated/use-shared-value 0)
|
||||||
@@ -53,18 +53,19 @@
|
|||||||
:keyboard-vertical-offset (- (:bottom insets))}
|
:keyboard-vertical-offset (- (:bottom insets))}
|
||||||
|
|
||||||
[list.view/message-list-content-view
|
[list.view/message-list-content-view
|
||||||
{:chat chat
|
{:chat chat
|
||||||
:insets insets
|
:insets insets
|
||||||
:scroll-y scroll-y
|
:scroll-y scroll-y
|
||||||
:content-height content-height
|
:content-height content-height
|
||||||
:cover-bg-color :turquoise
|
:cover-bg-color :turquoise
|
||||||
:keyboard-shown? keyboard-shown
|
:keyboard-shown? keyboard-shown
|
||||||
:inner-state-atoms inner-state-atoms
|
:inner-state-atoms inner-state-atoms
|
||||||
:animate-topbar-name? animate-topbar-name?
|
:animate-topbar-name? animate-topbar-name?
|
||||||
:big-name-visible? big-name-visible?
|
:big-name-visible? big-name-visible?
|
||||||
:animate-topbar-opacity? animate-topbar-opacity?
|
:animate-topbar-opacity? animate-topbar-opacity?
|
||||||
:composer-active? focused?
|
:composer-active? focused?
|
||||||
:on-end-reached? on-end-reached?}]
|
:on-end-reached? on-end-reached?
|
||||||
|
:messages-list-on-layout-finished? messages-list-on-layout-finished?}]
|
||||||
|
|
||||||
[messages.navigation/navigation-view
|
[messages.navigation/navigation-view
|
||||||
{:scroll-y scroll-y
|
{:scroll-y scroll-y
|
||||||
@@ -86,7 +87,8 @@
|
|||||||
[:f> composer.view/composer
|
[:f> composer.view/composer
|
||||||
{:insets insets
|
{:insets insets
|
||||||
:scroll-to-bottom-fn list.view/scroll-to-bottom
|
:scroll-to-bottom-fn list.view/scroll-to-bottom
|
||||||
:show-floating-scroll-down-button? show-floating-scroll-down-button?}]
|
:show-floating-scroll-down-button? show-floating-scroll-down-button?
|
||||||
|
:messages-list-on-layout-finished? messages-list-on-layout-finished?}]
|
||||||
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]))]))
|
[contact-requests.bottom-drawer/view chat-id contact-request-state group-chat]))]))
|
||||||
|
|
||||||
(defn chat
|
(defn chat
|
||||||
@@ -99,5 +101,6 @@
|
|||||||
:animate-topbar-name? (reagent/atom false)
|
:animate-topbar-name? (reagent/atom false)
|
||||||
:big-name-visible? (reagent/atom :initial-render)
|
:big-name-visible? (reagent/atom :initial-render)
|
||||||
:animate-topbar-opacity? (reagent/atom false)
|
:animate-topbar-opacity? (reagent/atom false)
|
||||||
:on-end-reached? (reagent/atom false)}]
|
:on-end-reached? (reagent/atom false)
|
||||||
|
:messages-list-on-layout-finished? (reagent/atom false)}]
|
||||||
[:f> f-chat inner-state-atoms]))
|
[:f> f-chat inner-state-atoms]))
|
||||||
|
|||||||
@@ -42,26 +42,31 @@
|
|||||||
community-id %])
|
community-id %])
|
||||||
:on-error #(log/error "failed to request to join community" community-id %)}]})
|
:on-error #(log/error "failed to request to join community" community-id %)}]})
|
||||||
|
|
||||||
|
(defn request-to-join
|
||||||
|
[{:keys [db]} [{:keys [community-id password]}]]
|
||||||
|
(let [pub-key (get-in db [:profile/profile :public-key])
|
||||||
|
addresses-to-reveal []]
|
||||||
|
{:fx [[:json-rpc/call
|
||||||
|
[{:method "wakuext_generateJoiningCommunityRequestsForSigning"
|
||||||
|
:params [pub-key community-id addresses-to-reveal]
|
||||||
|
:on-success [:communities/sign-data community-id password]
|
||||||
|
:on-error [:communities/requested-to-join-error community-id]}]]]}))
|
||||||
|
|
||||||
;; Event to be called to request to join a community.
|
;; Event to be called to request to join a community.
|
||||||
;; This event will generate the data to be signed and then call the sign-data event.
|
;; This event will generate the data to be signed and then call the sign-data event.
|
||||||
;; This is the only event that should be called from the UI.
|
;; This is the only event that should be called from the UI.
|
||||||
(rf/reg-event-fx :communities/request-to-join
|
(rf/reg-event-fx :communities/request-to-join request-to-join)
|
||||||
(fn [{:keys [db]} [{:keys [community-id password]}]]
|
|
||||||
(let [pub-key (get-in db [:profile/profile :public-key])
|
|
||||||
addresses-to-reveal []]
|
|
||||||
{:fx [[:json-rpc/call
|
|
||||||
[{:method "wakuext_generateJoiningCommunityRequestsForSigning"
|
|
||||||
:params [pub-key community-id addresses-to-reveal]
|
|
||||||
:on-success [:communities/sign-data community-id password]
|
|
||||||
:on-error [:communities/requested-to-join-error community-id]}]]]})))
|
|
||||||
|
|
||||||
(rf/reg-event-fx :communities/sign-data
|
(defn sign-data
|
||||||
(fn [_ [community-id password sign-params]]
|
[_ [community-id password sign-params]]
|
||||||
{:fx [[:json-rpc/call
|
(let [addresses-to-reveal (map :account sign-params)]
|
||||||
[{:method "wakuext_signData"
|
{:fx [[:json-rpc/call
|
||||||
:params [(map #(assoc % :password password) sign-params)]
|
[{:method "wakuext_signData"
|
||||||
:on-success [:communities/request-to-join-with-signatures community-id]
|
:params [(map #(assoc % :password password) sign-params)]
|
||||||
:on-error [:communities/requested-to-join-error community-id]}]]]}))
|
:on-success [:communities/request-to-join-with-signatures community-id addresses-to-reveal]
|
||||||
|
:on-error [:communities/requested-to-join-error community-id]}]]]}))
|
||||||
|
|
||||||
|
(rf/reg-event-fx :communities/sign-data sign-data)
|
||||||
|
|
||||||
(rf/reg-event-fx :communities/requested-to-join-error
|
(rf/reg-event-fx :communities/requested-to-join-error
|
||||||
(fn [{:keys [db]} [community-id error]]
|
(fn [{:keys [db]} [community-id error]]
|
||||||
@@ -71,11 +76,19 @@
|
|||||||
:event :communities/requested-to-join-error})
|
:event :communities/requested-to-join-error})
|
||||||
{:db (assoc-in db [:password-authentication :error] error)}))
|
{:db (assoc-in db [:password-authentication :error] error)}))
|
||||||
|
|
||||||
(rf/reg-event-fx :communities/request-to-join-with-signatures
|
(defn request-to-join-with-signatures
|
||||||
(fn [_ [community-id signatures]]
|
[_ [community-id addresses-to-reveal signatures]]
|
||||||
{:fx [[:json-rpc/call
|
{:fx [[:json-rpc/call
|
||||||
[{:method "wakuext_requestToJoinCommunity"
|
[{:method "wakuext_requestToJoinCommunity"
|
||||||
:params [{:communityId community-id :signatures signatures}]
|
:params [{:communityId community-id
|
||||||
:js-response true
|
:signatures signatures
|
||||||
:on-success [:communities/requested-to-join]
|
:addressesToReveal addresses-to-reveal
|
||||||
:on-error [:communities/requested-to-join-error community-id]}]]]}))
|
;; NOTE: At least one airdrop address is required.
|
||||||
|
;; This is a temporary solution while the address
|
||||||
|
;; selection feature is not implemented in mobile.
|
||||||
|
:airdropAddress (first addresses-to-reveal)}]
|
||||||
|
:js-response true
|
||||||
|
:on-success [:communities/requested-to-join]
|
||||||
|
:on-error [:communities/requested-to-join-error community-id]}]]]})
|
||||||
|
|
||||||
|
(rf/reg-event-fx :communities/request-to-join-with-signatures request-to-join-with-signatures)
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
(ns status-im2.contexts.communities.overview.events-test
|
||||||
|
(:require [cljs.test :refer [deftest is]]
|
||||||
|
[native-module.core :as native-module]
|
||||||
|
[status-im2.contexts.communities.overview.events :as sut]))
|
||||||
|
|
||||||
|
(def password (native-module/sha3 "password123"))
|
||||||
|
(def community-id "0x99")
|
||||||
|
(def account-pub-key "0x1")
|
||||||
|
|
||||||
|
(deftest request-to-join-test
|
||||||
|
(let [cofx {:db {:profile/profile {:public-key account-pub-key}}}
|
||||||
|
expected {:fx [[:json-rpc/call
|
||||||
|
[{:method "wakuext_generateJoiningCommunityRequestsForSigning"
|
||||||
|
:params [account-pub-key community-id []]
|
||||||
|
:on-success [:communities/sign-data community-id password]
|
||||||
|
:on-error [:communities/requested-to-join-error community-id]}]]]}]
|
||||||
|
(is (= expected
|
||||||
|
(sut/request-to-join cofx
|
||||||
|
[{:community-id community-id
|
||||||
|
:password password}])))))
|
||||||
|
|
||||||
|
(deftest sign-data-test
|
||||||
|
(let [cofx {:db {}}
|
||||||
|
sign-params [{:data "123" :account account-pub-key}
|
||||||
|
{:data "456" :account "0x2"}]
|
||||||
|
addresses-to-reveal [account-pub-key "0x2"]
|
||||||
|
expected {:fx
|
||||||
|
[[:json-rpc/call
|
||||||
|
[{:method "wakuext_signData"
|
||||||
|
:params [[{:data "123" :account account-pub-key :password password}
|
||||||
|
{:data "456" :account "0x2" :password password}]]
|
||||||
|
:on-success [:communities/request-to-join-with-signatures
|
||||||
|
community-id addresses-to-reveal]
|
||||||
|
:on-error [:communities/requested-to-join-error community-id]}]]]}]
|
||||||
|
(is (= expected
|
||||||
|
(sut/sign-data cofx [community-id password sign-params])))))
|
||||||
|
|
||||||
|
(deftest request-to-join-with-signatures-test
|
||||||
|
(let [cofx {:db {}}
|
||||||
|
addresses-to-reveal [account-pub-key "0x2"]
|
||||||
|
signatures ["11111" "222222"]
|
||||||
|
expected {:fx [[:json-rpc/call
|
||||||
|
[{:method "wakuext_requestToJoinCommunity"
|
||||||
|
:params [{:communityId community-id
|
||||||
|
:signatures signatures
|
||||||
|
:addressesToReveal addresses-to-reveal
|
||||||
|
:airdropAddress "0x1"}]
|
||||||
|
:js-response true
|
||||||
|
:on-success [:communities/requested-to-join]
|
||||||
|
:on-error [:communities/requested-to-join-error
|
||||||
|
community-id]}]]]}]
|
||||||
|
(is (= expected
|
||||||
|
(sut/request-to-join-with-signatures cofx [community-id addresses-to-reveal signatures])))))
|
||||||
@@ -255,7 +255,7 @@
|
|||||||
(defn community-content
|
(defn community-content
|
||||||
[community]
|
[community]
|
||||||
(rf/dispatch [:communities/check-all-community-channels-permissions (:id community)])
|
(rf/dispatch [:communities/check-all-community-channels-permissions (:id community)])
|
||||||
(fn [{:keys [name description joined images tags color id] :as community}
|
(fn [{:keys [name description joined images tags color id token-permissions] :as community}
|
||||||
pending?
|
pending?
|
||||||
{:keys [on-category-layout
|
{:keys [on-category-layout
|
||||||
collapsed?
|
collapsed?
|
||||||
@@ -273,12 +273,14 @@
|
|||||||
:last-item-style style/last-community-tag
|
:last-item-style style/last-community-tag
|
||||||
:container-style style/community-tag-container}])
|
:container-style style/community-tag-container}])
|
||||||
[join-community community pending?]]
|
[join-community community pending?]]
|
||||||
[channel-list-component
|
(when (or (and (seq token-permissions) joined)
|
||||||
{:on-category-layout on-category-layout
|
(empty? token-permissions))
|
||||||
:community-id id
|
[channel-list-component
|
||||||
:community-color color
|
{:on-category-layout on-category-layout
|
||||||
:on-first-channel-height-changed on-first-channel-height-changed}
|
:community-id id
|
||||||
(add-handlers-to-categorized-chats id chats-by-category joined)]])))
|
:community-color color
|
||||||
|
:on-first-channel-height-changed on-first-channel-height-changed}
|
||||||
|
(add-handlers-to-categorized-chats id chats-by-category joined)])])))
|
||||||
|
|
||||||
(defn sticky-category-header
|
(defn sticky-category-header
|
||||||
[_]
|
[_]
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
(ns status-im2.contexts.onboarding.enable-biometrics.view
|
(ns status-im2.contexts.onboarding.enable-biometrics.view
|
||||||
(:require
|
(:require
|
||||||
[quo.core :as quo]
|
[quo.core :as quo]
|
||||||
|
[quo.theme :as quo.theme]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.safe-area :as safe-area]
|
[react-native.safe-area :as safe-area]
|
||||||
[status-im2.common.biometric.events :as biometric]
|
[status-im2.common.biometric.events :as biometric]
|
||||||
[status-im2.common.parallax.view :as parallax]
|
[status-im2.common.parallax.view :as parallax]
|
||||||
[status-im2.common.parallax.whitelist :as whitelist]
|
[status-im2.common.parallax.whitelist :as whitelist]
|
||||||
[status-im2.common.resources :as resources]
|
[status-im2.common.resources :as resources]
|
||||||
|
[status-im2.common.standard-authentication.core :as standard-auth]
|
||||||
[status-im2.contexts.onboarding.enable-biometrics.style :as style]
|
[status-im2.contexts.onboarding.enable-biometrics.style :as style]
|
||||||
|
[status-im2.navigation.state :as state]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
|
|
||||||
(defn page-title
|
(defn page-title
|
||||||
[]
|
[]
|
||||||
@@ -21,22 +26,39 @@
|
|||||||
:description-accessibility-label :enable-biometrics-sub-title}])
|
:description-accessibility-label :enable-biometrics-sub-title}])
|
||||||
|
|
||||||
(defn enable-biometrics-buttons
|
(defn enable-biometrics-buttons
|
||||||
[insets]
|
[insets theme]
|
||||||
(let [supported-biometric-type (rf/sub [:biometric/supported-type])
|
(let [supported-biometric-type (rf/sub [:biometric/supported-type])
|
||||||
bio-type-label (biometric/get-label-by-type supported-biometric-type)
|
bio-type-label (biometric/get-label-by-type supported-biometric-type)
|
||||||
profile-color (:color (rf/sub [:onboarding-2/profile]))]
|
profile-color (or (:color (rf/sub [:onboarding-2/profile]))
|
||||||
|
(rf/sub [:profile/customization-color]))
|
||||||
|
syncing-results? (= :syncing-results @state/root-id)]
|
||||||
[rn/view {:style (style/buttons insets)}
|
[rn/view {:style (style/buttons insets)}
|
||||||
[quo/button
|
[standard-auth/button
|
||||||
{:accessibility-label :enable-biometrics-button
|
(merge
|
||||||
:on-press #(rf/dispatch [:onboarding-2/enable-biometrics])
|
{:size 40
|
||||||
:icon-left :i/face-id
|
:accessibility-label :enable-biometrics-button
|
||||||
:customization-color profile-color}
|
:icon-left :i/face-id
|
||||||
(i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})]
|
:customization-color profile-color
|
||||||
|
:button-label (i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})}
|
||||||
|
(if syncing-results?
|
||||||
|
{:theme theme
|
||||||
|
:blur? true
|
||||||
|
:on-enter-password (fn [entered-password]
|
||||||
|
(rf/dispatch
|
||||||
|
[:onboarding-2/authenticate-enable-biometrics
|
||||||
|
(security/safe-unmask-data
|
||||||
|
entered-password)])
|
||||||
|
(rf/dispatch [:hide-bottom-sheet]))
|
||||||
|
:auth-button-label (i18n/label :t/confirm)}
|
||||||
|
{:on-press #(rf/dispatch [:onboarding-2/enable-biometrics])}))]
|
||||||
[quo/button
|
[quo/button
|
||||||
{:accessibility-label :maybe-later-button
|
{:accessibility-label :maybe-later-button
|
||||||
:background :blur
|
:background :blur
|
||||||
:type :grey
|
:type :grey
|
||||||
:on-press #(rf/dispatch [:onboarding-2/create-account-and-login])
|
:on-press #(rf/dispatch (if syncing-results?
|
||||||
|
[:navigate-to-within-stack
|
||||||
|
[:enable-notifications :enable-biometrics]]
|
||||||
|
[:onboarding-2/create-account-and-login]))
|
||||||
:container-style {:margin-top 12}}
|
:container-style {:margin-top 12}}
|
||||||
(i18n/label :t/maybe-later)]]))
|
(i18n/label :t/maybe-later)]]))
|
||||||
|
|
||||||
@@ -55,12 +77,19 @@
|
|||||||
:style (style/page-illustration width)
|
:style (style/page-illustration width)
|
||||||
:source (resources/get-image :biometrics)}]))
|
:source (resources/get-image :biometrics)}]))
|
||||||
|
|
||||||
(defn enable-biometrics
|
(defn f-enable-biometrics
|
||||||
[]
|
[{:keys [theme]}]
|
||||||
(let [insets (safe-area/get-insets)]
|
(let [insets (safe-area/get-insets)]
|
||||||
[rn/view {:style (style/page-container insets)}
|
[rn/view {:style (style/page-container insets)}
|
||||||
[page-title]
|
[page-title]
|
||||||
(if whitelist/whitelisted?
|
(if whitelist/whitelisted?
|
||||||
[enable-biometrics-parallax]
|
[enable-biometrics-parallax]
|
||||||
[enable-biometrics-simple])
|
[enable-biometrics-simple])
|
||||||
[enable-biometrics-buttons insets]]))
|
[enable-biometrics-buttons insets theme]]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn- internale-enable-biometrics
|
||||||
|
[params]
|
||||||
|
[:f> f-enable-biometrics params])
|
||||||
|
|
||||||
|
(def view (quo.theme/with-theme internale-enable-biometrics))
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
[quo/page-nav
|
[quo/page-nav
|
||||||
{:background :blur
|
{:background :blur
|
||||||
:icon-name :i/arrow-left
|
:icon-name :i/arrow-left
|
||||||
:on-press #(rf/dispatch [:navigate-back-within-stack :new-to-status])}]
|
:on-press #(rf/dispatch [:navigate-back-within-stack :enable-biometrics])}]
|
||||||
[page-title]
|
[page-title]
|
||||||
[rn/view {:style style/page-illustration}
|
[rn/view {:style style/page-illustration}
|
||||||
[quo/text
|
[quo/text
|
||||||
|
|||||||
@@ -35,11 +35,30 @@
|
|||||||
{:biometric/authenticate {:on-success #(rf/dispatch [:onboarding-2/biometrics-done])
|
{:biometric/authenticate {:on-success #(rf/dispatch [:onboarding-2/biometrics-done])
|
||||||
:on-fail #(rf/dispatch [:onboarding-2/biometrics-fail %])}})
|
:on-fail #(rf/dispatch [:onboarding-2/biometrics-fail %])}})
|
||||||
|
|
||||||
|
(rf/defn authenticate-enable-biometrics
|
||||||
|
{:events [:onboarding-2/authenticate-enable-biometrics]}
|
||||||
|
[{:keys [db]} password]
|
||||||
|
{:db (-> db
|
||||||
|
(assoc-in [:onboarding-2/profile :password] password)
|
||||||
|
(assoc-in [:onboarding-2/profile :syncing?] true))
|
||||||
|
:biometric/authenticate {:on-success #(rf/dispatch [:onboarding-2/biometrics-done])
|
||||||
|
:on-fail #(rf/dispatch [:onboarding-2/biometrics-fail %])}})
|
||||||
|
|
||||||
|
(rf/defn navigate-to-enable-notifications
|
||||||
|
{:events [:onboarding-2/navigate-to-enable-notifications]}
|
||||||
|
[{:keys [db]}]
|
||||||
|
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||||
|
{:db (dissoc db :onboarding-2/profile)
|
||||||
|
:dispatch [:navigate-to-within-stack [:enable-notifications :enable-biometrics]]}))
|
||||||
|
|
||||||
(rf/defn biometrics-done
|
(rf/defn biometrics-done
|
||||||
{:events [:onboarding-2/biometrics-done]}
|
{:events [:onboarding-2/biometrics-done]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
{:db (assoc-in db [:onboarding-2/profile :auth-method] constants/auth-method-biometric)
|
(let [syncing? (get-in db [:onboarding-2/profile :syncing?])]
|
||||||
:dispatch [:onboarding-2/create-account-and-login]})
|
{:db (assoc-in db [:onboarding-2/profile :auth-method] constants/auth-method-biometric)
|
||||||
|
:dispatch (if syncing?
|
||||||
|
[:onboarding-2/finalize-setup]
|
||||||
|
[:onboarding-2/create-account-and-login])}))
|
||||||
|
|
||||||
(rf/defn biometrics-fail
|
(rf/defn biometrics-fail
|
||||||
{:events [:onboarding-2/biometrics-fail]}
|
{:events [:onboarding-2/biometrics-fail]}
|
||||||
@@ -83,6 +102,14 @@
|
|||||||
[:navigate-to-within-stack [:enable-biometrics :new-to-status]]
|
[:navigate-to-within-stack [:enable-biometrics :new-to-status]]
|
||||||
[:onboarding-2/create-account-and-login])}))
|
[:onboarding-2/create-account-and-login])}))
|
||||||
|
|
||||||
|
(rf/defn navigate-to-enable-biometrics
|
||||||
|
{:events [:onboarding-2/navigate-to-enable-biometrics]}
|
||||||
|
[{:keys [db]}]
|
||||||
|
(let [supported-type (:biometric/supported-type db)]
|
||||||
|
{:dispatch (if supported-type
|
||||||
|
[:open-modal :enable-biometrics]
|
||||||
|
[:open-modal :enable-notifications])}))
|
||||||
|
|
||||||
(rf/defn seed-phrase-entered
|
(rf/defn seed-phrase-entered
|
||||||
{:events [:onboarding-2/seed-phrase-entered]}
|
{:events [:onboarding-2/seed-phrase-entered]}
|
||||||
[_ seed-phrase on-error]
|
[_ seed-phrase on-error]
|
||||||
@@ -120,6 +147,7 @@
|
|||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
(let [masked-password (get-in db [:onboarding-2/profile :password])
|
(let [masked-password (get-in db [:onboarding-2/profile :password])
|
||||||
key-uid (get-in db [:profile/profile :key-uid])
|
key-uid (get-in db [:profile/profile :key-uid])
|
||||||
|
syncing? (get-in db [:onboarding-2/profile :syncing?])
|
||||||
biometric-enabled? (= (get-in db [:onboarding-2/profile :auth-method])
|
biometric-enabled? (= (get-in db [:onboarding-2/profile :auth-method])
|
||||||
constants/auth-method-biometric)]
|
constants/auth-method-biometric)]
|
||||||
(cond-> {:db (assoc db :onboarding-2/generated-keys? true)}
|
(cond-> {:db (assoc db :onboarding-2/generated-keys? true)}
|
||||||
@@ -127,7 +155,10 @@
|
|||||||
(assoc :keychain/save-password-and-auth-method
|
(assoc :keychain/save-password-and-auth-method
|
||||||
{:key-uid key-uid
|
{:key-uid key-uid
|
||||||
:masked-password masked-password
|
:masked-password masked-password
|
||||||
:on-success #(log/debug "successfully saved biometric")
|
:on-success (fn []
|
||||||
|
(if syncing?
|
||||||
|
(rf/dispatch [:onboarding-2/navigate-to-enable-notifications])
|
||||||
|
(log/error "successfully saved biometrics")))
|
||||||
:on-error #(log/error "failed to save biometrics"
|
:on-error #(log/error "failed to save biometrics"
|
||||||
{:key-uid key-uid
|
{:key-uid key-uid
|
||||||
:error %})}))))
|
:error %})}))))
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
{:on-press (fn []
|
{:on-press (fn []
|
||||||
(when on-press
|
(when on-press
|
||||||
(on-press))
|
(on-press))
|
||||||
(rf/dispatch [:open-modal :enable-notifications]))
|
(rf/dispatch [:onboarding-2/navigate-to-enable-biometrics]))
|
||||||
:accessibility-label :continue-button
|
:accessibility-label :continue-button
|
||||||
:customization-color profile-color
|
:customization-color profile-color
|
||||||
:container-style style/continue-button}
|
:container-style style/continue-button}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im2.common.qr-codes.view :as qr-codes]
|
[status-im2.common.qr-codes.view :as qr-codes]
|
||||||
[status-im2.common.resources :as resources]
|
[status-im2.common.resources :as resources]
|
||||||
[status-im2.common.standard-authentication.standard-auth.view :as standard-auth]
|
[status-im2.common.standard-authentication.core :as standard-auth]
|
||||||
[status-im2.contexts.syncing.setup-syncing.style :as style]
|
[status-im2.contexts.syncing.setup-syncing.style :as style]
|
||||||
[status-im2.contexts.syncing.utils :as sync-utils]
|
[status-im2.contexts.syncing.utils :as sync-utils]
|
||||||
[utils.datetime :as datetime]
|
[utils.datetime :as datetime]
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
(i18n/label :t/copy-qr)]])
|
(i18n/label :t/copy-qr)]])
|
||||||
(when-not (sync-utils/valid-connection-string? @code)
|
(when-not (sync-utils/valid-connection-string? @code)
|
||||||
[rn/view {:style style/standard-auth}
|
[rn/view {:style style/standard-auth}
|
||||||
[standard-auth/view
|
[standard-auth/slide-button
|
||||||
{:blur? true
|
{:blur? true
|
||||||
:size :size-40
|
:size :size-40
|
||||||
:track-text (i18n/label :t/slide-to-reveal-code)
|
:track-text (i18n/label :t/slide-to-reveal-code)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.safe-area :as safe-area]
|
[react-native.safe-area :as safe-area]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im2.common.standard-authentication.standard-auth.view :as standard-auth]
|
[status-im2.common.standard-authentication.core :as standard-auth]
|
||||||
[status-im2.constants :as constants]
|
[status-im2.constants :as constants]
|
||||||
[status-im2.contexts.emoji-picker.utils :as emoji-picker.utils]
|
[status-im2.contexts.emoji-picker.utils :as emoji-picker.utils]
|
||||||
[status-im2.contexts.wallet.common.utils :as utils]
|
[status-im2.contexts.wallet.common.utils :as utils]
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
{:list-type :settings
|
{:list-type :settings
|
||||||
:label (i18n/label :t/origin)
|
:label (i18n/label :t/origin)
|
||||||
:data (get-keypair-data primary-name @derivation-path @account-color)}]
|
:data (get-keypair-data primary-name @derivation-path @account-color)}]
|
||||||
[standard-auth/view
|
[standard-auth/slide-button
|
||||||
{:size :size-48
|
{:size :size-48
|
||||||
:track-text (i18n/label :t/slide-to-create-account)
|
:track-text (i18n/label :t/slide-to-create-account)
|
||||||
:customization-color @account-color
|
:customization-color @account-color
|
||||||
|
|||||||
@@ -161,11 +161,15 @@
|
|||||||
:component create-password/create-password}
|
:component create-password/create-password}
|
||||||
|
|
||||||
{:name :enable-biometrics
|
{:name :enable-biometrics
|
||||||
:options {:theme :dark
|
:options {:theme :dark
|
||||||
:layout options/onboarding-transparent-layout
|
:layout options/onboarding-transparent-layout
|
||||||
:animations transitions/push-animations-for-transparent-background
|
:animations (merge transitions/new-to-status-modal-animations
|
||||||
:popGesture false}
|
transitions/push-animations-for-transparent-background)
|
||||||
:component enable-biometrics/enable-biometrics}
|
:popGesture false
|
||||||
|
:modalPresentationStyle :overCurrentContext
|
||||||
|
:hardwareBackButton {:dismissModalOnPress false
|
||||||
|
:popStackOnPress false}}
|
||||||
|
:component enable-biometrics/view}
|
||||||
|
|
||||||
{:name :generating-keys
|
{:name :generating-keys
|
||||||
:options {:theme :dark
|
:options {:theme :dark
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||||
"owner": "status-im",
|
"owner": "status-im",
|
||||||
"repo": "status-go",
|
"repo": "status-go",
|
||||||
"version": "v0.171.11",
|
"version": "debug/resend-edits",
|
||||||
"commit-sha1": "8a4c2d8d2f17117aa0a00338e83b0f753ebf1328",
|
"commit-sha1": "f1d1726a4e12159013d72008c949fee77e48627c",
|
||||||
"src-sha256": "160qnl9dsl1ypvqg9w6z8wps4fvgq3qxi16piymhrlzgssdwkz8h"
|
"src-sha256": "0yl33bsq7x59mp8s029qw00h0m5wfg28zk3r1w7zp3m6w4j34p3d"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user