Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e3b207c3b | ||
|
|
f03671097b | ||
|
|
1db63a9fa1 | ||
|
|
cd92b41214 | ||
|
|
56f7206da7 | ||
|
|
eb5de3506a | ||
|
|
22005f916e | ||
|
|
ff50aacb3a | ||
|
|
91300b9ff8 | ||
|
|
d93b20242a | ||
|
|
0a43e5c97a | ||
|
|
c150070cfe | ||
|
|
1b745857e8 | ||
|
|
87c9946092 | ||
|
|
f3e47ac1a2 |
@@ -1,3 +1,3 @@
|
||||
(ns quo.components.colors.color.constants)
|
||||
|
||||
(def ^:const IPHONE_11_PRO_VIEWPORT_WIDTH 375)
|
||||
(def ^:const color-size 48)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
(ns quo.components.colors.color.style
|
||||
(:require
|
||||
[quo.components.colors.color.constants :as constants]
|
||||
[quo.foundations.colors :as colors]
|
||||
[utils.responsiveness :as responsiveness]))
|
||||
|
||||
(defn color-button-common
|
||||
[window-width]
|
||||
{:width 48
|
||||
:height 48
|
||||
{:width constants/color-size
|
||||
:height constants/color-size
|
||||
:border-width 4
|
||||
:border-radius 24
|
||||
:margin-right (-> window-width
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "color-picker"
|
||||
(h/test "color picker rendered"
|
||||
(h/render [color-picker/view])
|
||||
(-> (h/expect (h/get-all-by-label-text :color-picker-item))
|
||||
(.toHaveLength 11)))
|
||||
(h/test "clicks on a color item"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [color-picker/view {:on-change #(event)}])
|
||||
@@ -20,11 +16,6 @@
|
||||
(h/render [color-picker/view {:on-change #(reset! selected %)}])
|
||||
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
|
||||
(-> (h/expect @selected)
|
||||
(.toStrictEqual :blue))))
|
||||
(h/test "all of the values of colors-list are rendered"
|
||||
(h/render [color-picker/view])
|
||||
(js/Promise.all (map (fn [color]
|
||||
(h/is-truthy (h/get-all-by-label-text color)))
|
||||
color-picker/color-list))))
|
||||
(.toStrictEqual :blue)))))
|
||||
|
||||
|
||||
|
||||
@@ -1,39 +1,67 @@
|
||||
(ns quo.components.colors.color-picker.view
|
||||
(:require
|
||||
[quo.components.colors.color.constants :as constants]
|
||||
[quo.components.colors.color.view :as color]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def color-list
|
||||
[:blue :yellow :purple :turquoise :magenta :sky :orange :army :flamingo :camel :copper])
|
||||
|
||||
(defn- on-change-handler
|
||||
[selected color-name on-change]
|
||||
(reset! selected color-name)
|
||||
(when on-change (on-change color-name)))
|
||||
|
||||
(defn view
|
||||
(defn get-item-layout
|
||||
[_ index]
|
||||
#js
|
||||
{:length constants/color-size
|
||||
:offset (* (+ constants/color-size 8) index)
|
||||
:index index})
|
||||
|
||||
(defn- view-internal
|
||||
"Options
|
||||
- `default-selected` Default selected color name.
|
||||
- `on-change` Callback called when a color is selected `(fn [color-name])`.
|
||||
- `blur?` Boolean to enable blur background support.}"
|
||||
[{:keys [default-selected]}]
|
||||
[{:keys [default-selected blur? on-change feng-shui? container-style]}]
|
||||
(let [selected (reagent/atom default-selected)
|
||||
{window-width :width} (rn/get-window)]
|
||||
(fn [{:keys [blur? on-change feng-shui? container-style]}]
|
||||
[rn/scroll-view
|
||||
{:horizontal true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:content-container-style container-style}
|
||||
(doall (map-indexed (fn [idx color]
|
||||
[color/view
|
||||
{:selected? (= color @selected)
|
||||
:on-press #(on-change-handler selected % on-change)
|
||||
:blur? blur?
|
||||
:key color
|
||||
:color color
|
||||
:idx idx
|
||||
:window-width window-width}])
|
||||
;; TODO: using :feng-shui? temporarily while b & w is being developed.
|
||||
;; https://github.com/status-im/status-mobile/discussions/16676
|
||||
(if feng-shui? (conj color-list :feng-shui) color-list)))])))
|
||||
{window-width :width} (rn/get-window)
|
||||
ref (atom nil)]
|
||||
(rn/use-effect #(js/setTimeout (fn []
|
||||
(.scrollToIndex ^js @ref
|
||||
#js
|
||||
{:animated true
|
||||
:index (.indexOf colors/account-colors
|
||||
default-selected)
|
||||
:viewPosition 0.5}))
|
||||
50))
|
||||
[rn/flat-list
|
||||
{:ref #(reset! ref %)
|
||||
;; TODO: using :feng-shui? temporarily while b & w is being developed.
|
||||
;; https://github.com/status-im/status-mobile/discussions/16676
|
||||
:data (if feng-shui?
|
||||
(conj colors/account-colors :feng-shui)
|
||||
colors/account-colors)
|
||||
:render-fn (fn [color idx]
|
||||
[color/view
|
||||
{:selected? (= color @selected)
|
||||
:on-press (fn [e]
|
||||
(.scrollToIndex ^js @ref
|
||||
#js
|
||||
{:animated true
|
||||
:index idx
|
||||
:viewPosition 0.5})
|
||||
(on-change-handler selected e on-change))
|
||||
:blur? blur?
|
||||
:key color
|
||||
:color color
|
||||
:idx idx
|
||||
:window-width window-width}])
|
||||
:get-item-layout get-item-layout
|
||||
:horizontal true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:content-container-style container-style}]))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[:f> view-internal props])
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
:scroll? - bool (default false) - Whether the iOS Home Indicator should be rendered"
|
||||
[props]
|
||||
(let [{:keys [actions description button-one-label button-two-label
|
||||
button-one-props button-two-props theme scroll? customization-color]}
|
||||
button-one-props button-two-props theme scroll? customization-color container-style]}
|
||||
(merge default-props props)]
|
||||
[:<>
|
||||
[rn/view {:style container-style}
|
||||
[rn/view {:style style/buttons-container}
|
||||
(when (= actions :2-actions)
|
||||
[button/button
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns quo.components.text-combinations.view
|
||||
(:require
|
||||
[quo.components.buttons.button.view :as button]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.components.text-combinations.style :as style]
|
||||
[quo.theme :as theme]
|
||||
@@ -23,20 +24,31 @@
|
||||
avatar
|
||||
title-accessibility-label
|
||||
description
|
||||
description-accessibility-label]}]
|
||||
description-accessibility-label
|
||||
button-icon
|
||||
button-on-press
|
||||
customization-color]}]
|
||||
[rn/view {:style container-style}
|
||||
[rn/view {:style style/title-container}
|
||||
(when avatar
|
||||
[rn/view {:style style/avatar-container}
|
||||
[icon avatar 32]])
|
||||
|
||||
[text/text
|
||||
{:accessibility-label title-accessibility-label
|
||||
:weight :semi-bold
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:size :heading-1}
|
||||
title]]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between}}
|
||||
[rn/view {:style style/title-container}
|
||||
(when avatar
|
||||
[rn/view {:style style/avatar-container}
|
||||
[icon avatar 32]])
|
||||
[text/text
|
||||
{:accessibility-label title-accessibility-label
|
||||
:weight :semi-bold
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:size :heading-1}
|
||||
title]]
|
||||
(when button-icon
|
||||
[button/button
|
||||
{:icon-only? true
|
||||
:on-press button-on-press
|
||||
:customization-color customization-color
|
||||
:size 32} button-icon])]
|
||||
(when description
|
||||
[text/text
|
||||
{:accessibility-label description-accessibility-label
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
(defn container
|
||||
[{:keys [blur? customization-color theme selected?]}]
|
||||
{:flex 1
|
||||
:border-radius 20
|
||||
{:border-radius 16
|
||||
:border-width 1
|
||||
:border-color (if selected?
|
||||
(if blur?
|
||||
@@ -28,5 +27,4 @@
|
||||
(def title-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:flex 1})
|
||||
:justify-content :space-between})
|
||||
|
||||
@@ -27,13 +27,16 @@
|
||||
(defn avatar
|
||||
[{{:keys [full-name]} :details
|
||||
avatar-type :type
|
||||
customization-color :customization-color}]
|
||||
customization-color :customization-color
|
||||
profile-picture :profile-picture}]
|
||||
(if (= avatar-type :default-keypair)
|
||||
[user-avatar/user-avatar
|
||||
{:full-name full-name
|
||||
:ring? true
|
||||
:size :small
|
||||
:customization-color customization-color}]
|
||||
:status-indicator? false
|
||||
:customization-color customization-color
|
||||
:profile-picture profile-picture}]
|
||||
[icon-avatar/icon-avatar
|
||||
{:size :size-32
|
||||
:icon :i/placeholder
|
||||
@@ -84,9 +87,9 @@
|
||||
(defn- view-internal
|
||||
[]
|
||||
(let [selected? (reagent/atom true)]
|
||||
(fn [{:keys [accounts action] :as props}]
|
||||
(fn [{:keys [accounts action container-style] :as props}]
|
||||
[rn/pressable
|
||||
{:style (style/container (merge props {:selected? @selected?}))
|
||||
{:style (merge (style/container (merge props {:selected? @selected?})) container-style)
|
||||
:on-press #(when (= action :selector) (reset! selected? (not @selected?)))}
|
||||
[rn/view {:style style/header-container}
|
||||
[avatar props]
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
[quo.theme :as theme]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def account-colors
|
||||
[:blue :yellow :purple :turquoise :magenta :sky :orange :army :flamingo :camel :copper])
|
||||
|
||||
(defn alpha
|
||||
[value opacity]
|
||||
(when value
|
||||
|
||||
@@ -29,3 +29,6 @@
|
||||
(testing
|
||||
"when using opacity theme is ignored and uses the light suffix resolver"
|
||||
(is (colors/resolve-color :blue :light 10) (colors/resolve-color :blue :dark 10))))
|
||||
|
||||
(deftest test-account-colors-customization
|
||||
(is (every? #(contains? colors/customization %) colors/account-colors)))
|
||||
|
||||
@@ -107,14 +107,15 @@
|
||||
[{:keys [db] :as cofx} message]
|
||||
(let [current-chat-id (:current-chat-id db)
|
||||
text (get-in message [:content :text])]
|
||||
{:db (-> db
|
||||
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
|
||||
message)
|
||||
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
|
||||
(update-in [:chat/inputs current-chat-id :metadata]
|
||||
dissoc
|
||||
:sending-image))
|
||||
:dispatch [:mention/to-input-field text current-chat-id]}))
|
||||
{:db (-> db
|
||||
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
|
||||
message)
|
||||
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
|
||||
(update-in [:chat/inputs current-chat-id :metadata]
|
||||
dissoc
|
||||
:sending-image))
|
||||
: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
|
||||
"Sets reference to previous chat message and focuses on input"
|
||||
|
||||
@@ -225,7 +225,9 @@
|
||||
(.. ^js % -nativeEvent -data)])
|
||||
:on-load #(re-frame/dispatch [:browser/loading-started])
|
||||
: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
|
||||
{:url url-original
|
||||
: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
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.touch-id :as biometric]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.standard-authentication.enter-password.view :as enter-password]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -46,39 +42,3 @@
|
||||
{:on-enter-password on-enter-password
|
||||
:button-icon-left auth-button-icon-left
|
||||
: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]))
|
||||
|
||||
(defn edit-message
|
||||
[state]
|
||||
[{:keys [text-value input-ref]}]
|
||||
[rn/view
|
||||
{:style style/container
|
||||
:accessibility-label :edit-message}
|
||||
@@ -30,20 +30,18 @@
|
||||
{:size 24
|
||||
:icon-only? true
|
||||
:accessibility-label :edit-cancel-button
|
||||
:on-press (fn []
|
||||
(utils/cancel-edit-message state)
|
||||
(rf/dispatch [:chat.ui/cancel-message-edit]))
|
||||
:on-press #(utils/cancel-edit-message text-value input-ref)
|
||||
:type :outline}
|
||||
:i/close]])
|
||||
|
||||
(defn- f-view
|
||||
[state]
|
||||
[props]
|
||||
(let [edit (rf/sub [:chats/edit-message])
|
||||
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])
|
||||
[reanimated/view {:style (reanimated/apply-animations-to-style {:height height} {})}
|
||||
(when edit [edit-message state])]))
|
||||
(when edit [edit-message props])]))
|
||||
|
||||
(defn view
|
||||
[state]
|
||||
[:f> f-view state])
|
||||
[props]
|
||||
[:f> f-view props])
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.keyboard :as kb]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
@@ -105,53 +106,62 @@
|
||||
|
||||
(defn use-edit
|
||||
[{:keys [input-ref]}
|
||||
{:keys [text-value saved-cursor-position]}
|
||||
{:keys [edit]}]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(let [edit-text (get-in edit [:content :text])
|
||||
text-value-count (count @text-value)]
|
||||
(when (and edit @input-ref)
|
||||
;; A small setTimeout is necessary to ensure the statement is enqueued and will get executed
|
||||
;; ASAP.
|
||||
;; https://github.com/software-mansion/react-native-screens/issues/472
|
||||
(js/setTimeout #(.focus ^js @input-ref) 250)
|
||||
(.setNativeProps ^js @input-ref (clj->js {:text edit-text}))
|
||||
(reset! text-value edit-text)
|
||||
(reset! saved-cursor-position (if (zero? text-value-count)
|
||||
(count edit-text)
|
||||
text-value-count)))))
|
||||
[(:message-id edit)]))
|
||||
{:keys [text-value saved-cursor-position cursor-position]}
|
||||
{:keys [edit input-with-mentions]}
|
||||
messages-list-on-layout-finished?]
|
||||
(let [mention? (some #(= :mention (first %)) (seq input-with-mentions))
|
||||
composer-just-opened? (not @messages-list-on-layout-finished?)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(let [mention-text (reduce (fn [acc item]
|
||||
(str acc (second item)))
|
||||
""
|
||||
input-with-mentions)
|
||||
edit-text (cond
|
||||
mention? mention-text
|
||||
;; NOTE: using text-value for cases when the user
|
||||
;; leaves the app with an unfinished edit and re-opens
|
||||
;; the chat.
|
||||
(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
|
||||
[{:keys [input-ref]}
|
||||
{:keys [container-opacity]}
|
||||
{:keys [reply]}]
|
||||
{:keys [reply]}
|
||||
messages-list-on-layout-finished?]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when reply
|
||||
(reanimated/animate container-opacity 1))
|
||||
(when (and reply @input-ref)
|
||||
(js/setTimeout #(.focus ^js @input-ref) 250)))
|
||||
(when (and reply @input-ref @messages-list-on-layout-finished?)
|
||||
(js/setTimeout #(.focus ^js @input-ref) 600)))
|
||||
[(: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
|
||||
[{:keys [input-ref]}
|
||||
{:keys [text-value]}
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
(reset! emoji-kb-extra-height nil))
|
||||
(reset! maximized? false)
|
||||
(rf/dispatch [:chat.ui/set-input-maximized false])
|
||||
(when @input-ref
|
||||
(.blur ^js @input-ref)))
|
||||
(utils/blur-input input-ref))
|
||||
|
||||
(defn bounce-back
|
||||
[{:keys [height saved-height opacity background-y]}
|
||||
@@ -96,13 +95,13 @@
|
||||
max-height
|
||||
bounded-height
|
||||
saved-height))
|
||||
(when @input-ref ; sheet at min-height, collapse keyboard
|
||||
(.blur ^js @input-ref)))))))
|
||||
; sheet at min-height, collapse keyboard
|
||||
(utils/blur-input input-ref))))))
|
||||
(gesture/on-end (fn []
|
||||
(let [diff (- (reanimated/get-shared-value height)
|
||||
(reanimated/get-shared-value saved-height))]
|
||||
(if @gesture-enabled?
|
||||
(if (>= diff 0)
|
||||
(if (and @expanding? (>= diff 0))
|
||||
(if (> diff constants/drag-threshold)
|
||||
(maximize state animations dimensions)
|
||||
(bounce-back animations dimensions starting-opacity))
|
||||
|
||||
@@ -23,12 +23,14 @@
|
||||
show-floating-scroll-down-button?]
|
||||
(reset! focused? true)
|
||||
(rf/dispatch [:chat.ui/set-input-focused true])
|
||||
(reanimated/animate height (reanimated/get-shared-value last-height))
|
||||
(reanimated/set-shared-value saved-height (reanimated/get-shared-value last-height))
|
||||
(reanimated/animate container-opacity 1)
|
||||
(when (> (reanimated/get-shared-value last-height) (* constants/background-threshold max-height))
|
||||
(reanimated/animate opacity 1)
|
||||
(reanimated/set-shared-value background-y 0))
|
||||
(let [last-height-value (reanimated/get-shared-value last-height)]
|
||||
(reanimated/animate height last-height-value)
|
||||
(reanimated/set-shared-value saved-height last-height-value)
|
||||
(reanimated/animate container-opacity 1)
|
||||
(when (> last-height-value (* constants/background-threshold max-height))
|
||||
(reanimated/animate opacity 1)
|
||||
(reanimated/set-shared-value background-y 0)))
|
||||
|
||||
(js/setTimeout #(reset! lock-selection? false) 300)
|
||||
(when (and (not-empty @text-value) @input-ref)
|
||||
(.setNativeProps ^js @input-ref
|
||||
@@ -72,7 +74,7 @@
|
||||
"Save new text height, expand composer if possible, show background overlay if needed"
|
||||
[event
|
||||
{: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]}
|
||||
keyboard-shown]
|
||||
(when keyboard-shown
|
||||
@@ -87,8 +89,9 @@
|
||||
max-height)
|
||||
new-height (min new-height max-height)]
|
||||
(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/set-shared-value last-height new-height)
|
||||
(reanimated/set-shared-value saved-height new-height))
|
||||
(when (= new-height max-height)
|
||||
(reset! maximized? true)
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
[react-native.async-storage :as async-storage]
|
||||
[react-native.core :as rn]
|
||||
[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
|
||||
[curr-height default-height]
|
||||
@@ -20,18 +21,24 @@
|
||||
(async-storage/set-item! :kb-default-height (str height)))))
|
||||
|
||||
(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
|
||||
{:keys [emoji-kb-extra-height]}
|
||||
{:keys [text-value]}
|
||||
{:keys [text-value kb-height]}
|
||||
{:keys [height saved-height]}
|
||||
{:keys [max-height]}]
|
||||
(let [start-h (oops/oget event "startCoordinates.height")
|
||||
end-h (oops/oget event "endCoordinates.height")
|
||||
diff (- end-h start-h)
|
||||
max-height-diff (- max-height diff)
|
||||
curr-text @text-value]
|
||||
(if (> (reanimated/get-shared-value height) max-height-diff)
|
||||
(let [start-h (oops/oget event "startCoordinates.height")
|
||||
end-h (oops/oget event "endCoordinates.height")
|
||||
diff (- end-h start-h)
|
||||
max-height-diff (- max-height diff)
|
||||
curr-text @text-value
|
||||
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
|
||||
(reanimated/set-shared-value height (- (reanimated/get-shared-value 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)))
|
||||
(reset! keyboard-hide-listener (.addListener rn/keyboard
|
||||
"keyboardDidHide"
|
||||
#(when (and platform/android? @input-ref)
|
||||
(.blur ^js @input-ref)))))
|
||||
#(when platform/android?
|
||||
(utils/blur-input input-ref)))))
|
||||
|
||||
(defn handle-refocus-emoji-kb-ios
|
||||
[{:keys [saved-emoji-kb-extra-height]}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
[status-im2.constants :as constant]
|
||||
[status-im2.contexts.chat.composer.constants :as constants]
|
||||
[status-im2.contexts.chat.composer.reply.style :as style]
|
||||
[status-im2.contexts.chat.composer.utils :as utils]
|
||||
[utils.ens.stateofus :as stateofus]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -85,7 +86,7 @@
|
||||
(defn quoted-message
|
||||
[{:keys [from content-type contentType parsed-text content deleted? deleted-for-me?
|
||||
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])
|
||||
current-public-key (rf/sub [:multiaccount/public-key])
|
||||
content-type (or content-type contentType)
|
||||
@@ -136,7 +137,7 @@
|
||||
{:icon-only? true
|
||||
:size 24
|
||||
:accessibility-label :reply-cancel-button
|
||||
:on-press #(rf/dispatch [:chat.ui/cancel-message-reply])
|
||||
:on-press #(utils/cancel-reply-message input-ref)
|
||||
:type :outline}
|
||||
:i/close])
|
||||
(when (and in-chat-input? recording-audio?)
|
||||
@@ -148,13 +149,13 @@
|
||||
:style style/gradient}])]))
|
||||
|
||||
(defn- f-view
|
||||
[recording?]
|
||||
[recording? input-ref]
|
||||
(let [reply (rf/sub [:chats/reply-message])
|
||||
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])
|
||||
[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
|
||||
[{:keys [recording?]}]
|
||||
[:f> f-view @recording?])
|
||||
[{:keys [recording?]} input-ref]
|
||||
[:f> f-view @recording? input-ref])
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
(max min-v (min v max-v)))
|
||||
|
||||
(defn update-height?
|
||||
[content-size height max-height maximized?]
|
||||
(when-not @maximized?
|
||||
(let [diff (Math/abs (- content-size (reanimated/get-shared-value height)))]
|
||||
(and (not= (reanimated/get-shared-value height) max-height)
|
||||
(> diff constants/content-change-threshold)))))
|
||||
[content-size height max-height]
|
||||
(let [diff (Math/abs (- content-size (reanimated/get-shared-value height)))]
|
||||
(and (not= (reanimated/get-shared-value height) max-height)
|
||||
(> diff constants/content-change-threshold))))
|
||||
|
||||
(defn show-top-gradient?
|
||||
[y lines max-lines gradient-opacity focused?]
|
||||
@@ -100,10 +99,28 @@
|
||||
(not reply?)
|
||||
(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
|
||||
[{:keys [text-value]}]
|
||||
[text-value input-ref]
|
||||
(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
|
||||
[s]
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
blur-height
|
||||
opacity
|
||||
background-y
|
||||
theme]} props state]
|
||||
theme
|
||||
messages-list-on-layout-finished?]} props state]
|
||||
(let [{:keys [chat-screen-loaded?]
|
||||
:as subscriptions} (utils/init-subs)
|
||||
content-height (reagent/atom (or (:input-content-height ; Actual text height
|
||||
@@ -73,10 +74,9 @@
|
||||
animations
|
||||
dimensions
|
||||
subscriptions)
|
||||
(effects/use-edit props state subscriptions)
|
||||
(effects/use-reply props animations subscriptions)
|
||||
(effects/use-edit props state subscriptions messages-list-on-layout-finished?)
|
||||
(effects/use-reply props animations subscriptions messages-list-on-layout-finished?)
|
||||
(effects/update-input-mention props state subscriptions)
|
||||
(effects/edit-mentions props state subscriptions)
|
||||
(effects/link-previews props state animations subscriptions)
|
||||
(effects/use-images props state animations subscriptions)
|
||||
[:<>
|
||||
@@ -98,8 +98,10 @@
|
||||
[sub-view/bar]
|
||||
(when chat-screen-loaded?
|
||||
[:<>
|
||||
[reply/view state]
|
||||
[edit/view state]])
|
||||
[reply/view state (:input-ref props)]
|
||||
[edit/view
|
||||
{:text-value (:text-value state)
|
||||
:input-ref (:input-ref props)}]])
|
||||
[reanimated/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
@@ -147,11 +149,13 @@
|
||||
subscriptions]]]]]))
|
||||
|
||||
(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))
|
||||
theme (quo.theme/use-theme-value)
|
||||
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
|
||||
(:bottom insets)))
|
||||
extra-params {:insets insets
|
||||
@@ -161,7 +165,8 @@
|
||||
:blur-height blur-height
|
||||
:opacity opacity
|
||||
:background-y background-y
|
||||
:theme theme}
|
||||
:theme theme
|
||||
:messages-list-on-layout-finished? messages-list-on-layout-finished?}
|
||||
props (utils/init-non-reactive-state)
|
||||
state (utils/init-reactive-state)]
|
||||
[rn/view (when platform/ios? {:style {:z-index 1}})
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
|
||||
(defn f-messages-list-content
|
||||
[{: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?]}]
|
||||
(rn/use-effect (fn []
|
||||
(if (and (not @on-end-reached?)
|
||||
@@ -412,6 +412,15 @@
|
||||
;;TODO(rasom) https://github.com/facebook/react-native/issues/30034
|
||||
:inverted (when platform/ios? true)
|
||||
: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
|
||||
"nativeEvent.layout.height")]
|
||||
(reset! messages-view-height layout-height)))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
(defn f-chat
|
||||
[{: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}]
|
||||
(let [insets (safe-area/get-insets)
|
||||
scroll-y (reanimated/use-shared-value 0)
|
||||
@@ -53,18 +53,19 @@
|
||||
:keyboard-vertical-offset (- (:bottom insets))}
|
||||
|
||||
[list.view/message-list-content-view
|
||||
{:chat chat
|
||||
:insets insets
|
||||
:scroll-y scroll-y
|
||||
:content-height content-height
|
||||
:cover-bg-color :turquoise
|
||||
:keyboard-shown? keyboard-shown
|
||||
:inner-state-atoms inner-state-atoms
|
||||
:animate-topbar-name? animate-topbar-name?
|
||||
:big-name-visible? big-name-visible?
|
||||
:animate-topbar-opacity? animate-topbar-opacity?
|
||||
:composer-active? focused?
|
||||
:on-end-reached? on-end-reached?}]
|
||||
{:chat chat
|
||||
:insets insets
|
||||
:scroll-y scroll-y
|
||||
:content-height content-height
|
||||
:cover-bg-color :turquoise
|
||||
:keyboard-shown? keyboard-shown
|
||||
:inner-state-atoms inner-state-atoms
|
||||
:animate-topbar-name? animate-topbar-name?
|
||||
:big-name-visible? big-name-visible?
|
||||
:animate-topbar-opacity? animate-topbar-opacity?
|
||||
:composer-active? focused?
|
||||
:on-end-reached? on-end-reached?
|
||||
:messages-list-on-layout-finished? messages-list-on-layout-finished?}]
|
||||
|
||||
[messages.navigation/navigation-view
|
||||
{:scroll-y scroll-y
|
||||
@@ -86,7 +87,8 @@
|
||||
[:f> composer.view/composer
|
||||
{:insets insets
|
||||
: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]))]))
|
||||
|
||||
(defn chat
|
||||
@@ -99,5 +101,6 @@
|
||||
:animate-topbar-name? (reagent/atom false)
|
||||
:big-name-visible? (reagent/atom :initial-render)
|
||||
: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]))
|
||||
|
||||
@@ -42,26 +42,31 @@
|
||||
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.
|
||||
;; 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.
|
||||
(rf/reg-event-fx :communities/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/request-to-join request-to-join)
|
||||
|
||||
(rf/reg-event-fx :communities/sign-data
|
||||
(fn [_ [community-id password sign-params]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_signData"
|
||||
:params [(map #(assoc % :password password) sign-params)]
|
||||
:on-success [:communities/request-to-join-with-signatures community-id]
|
||||
:on-error [:communities/requested-to-join-error community-id]}]]]}))
|
||||
(defn sign-data
|
||||
[_ [community-id password sign-params]]
|
||||
(let [addresses-to-reveal (map :account sign-params)]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_signData"
|
||||
:params [(map #(assoc % :password password) sign-params)]
|
||||
: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
|
||||
(fn [{:keys [db]} [community-id error]]
|
||||
@@ -71,11 +76,19 @@
|
||||
:event :communities/requested-to-join-error})
|
||||
{:db (assoc-in db [:password-authentication :error] error)}))
|
||||
|
||||
(rf/reg-event-fx :communities/request-to-join-with-signatures
|
||||
(fn [_ [community-id signatures]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_requestToJoinCommunity"
|
||||
:params [{:communityId community-id :signatures signatures}]
|
||||
:js-response true
|
||||
:on-success [:communities/requested-to-join]
|
||||
:on-error [:communities/requested-to-join-error community-id]}]]]}))
|
||||
(defn request-to-join-with-signatures
|
||||
[_ [community-id addresses-to-reveal signatures]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_requestToJoinCommunity"
|
||||
:params [{:communityId community-id
|
||||
:signatures signatures
|
||||
:addressesToReveal addresses-to-reveal
|
||||
;; 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
|
||||
[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?
|
||||
{:keys [on-category-layout
|
||||
collapsed?
|
||||
@@ -273,12 +273,14 @@
|
||||
:last-item-style style/last-community-tag
|
||||
:container-style style/community-tag-container}])
|
||||
[join-community community pending?]]
|
||||
[channel-list-component
|
||||
{:on-category-layout on-category-layout
|
||||
:community-id id
|
||||
:community-color color
|
||||
:on-first-channel-height-changed on-first-channel-height-changed}
|
||||
(add-handlers-to-categorized-chats id chats-by-category joined)]])))
|
||||
(when (or (and (seq token-permissions) joined)
|
||||
(empty? token-permissions))
|
||||
[channel-list-component
|
||||
{:on-category-layout on-category-layout
|
||||
:community-id id
|
||||
: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
|
||||
[_]
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
(ns status-im2.contexts.onboarding.enable-biometrics.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im2.common.biometric.events :as biometric]
|
||||
[status-im2.common.parallax.view :as parallax]
|
||||
[status-im2.common.parallax.whitelist :as whitelist]
|
||||
[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.navigation.state :as state]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
|
||||
(defn page-title
|
||||
[]
|
||||
@@ -21,22 +26,39 @@
|
||||
:description-accessibility-label :enable-biometrics-sub-title}])
|
||||
|
||||
(defn enable-biometrics-buttons
|
||||
[insets]
|
||||
[insets theme]
|
||||
(let [supported-biometric-type (rf/sub [:biometric/supported-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)}
|
||||
[quo/button
|
||||
{:accessibility-label :enable-biometrics-button
|
||||
:on-press #(rf/dispatch [:onboarding-2/enable-biometrics])
|
||||
:icon-left :i/face-id
|
||||
:customization-color profile-color}
|
||||
(i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})]
|
||||
[standard-auth/button
|
||||
(merge
|
||||
{:size 40
|
||||
:accessibility-label :enable-biometrics-button
|
||||
:icon-left :i/face-id
|
||||
: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
|
||||
{:accessibility-label :maybe-later-button
|
||||
:background :blur
|
||||
: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}}
|
||||
(i18n/label :t/maybe-later)]]))
|
||||
|
||||
@@ -55,12 +77,19 @@
|
||||
:style (style/page-illustration width)
|
||||
:source (resources/get-image :biometrics)}]))
|
||||
|
||||
(defn enable-biometrics
|
||||
[]
|
||||
(defn f-enable-biometrics
|
||||
[{:keys [theme]}]
|
||||
(let [insets (safe-area/get-insets)]
|
||||
[rn/view {:style (style/page-container insets)}
|
||||
[page-title]
|
||||
(if whitelist/whitelisted?
|
||||
[enable-biometrics-parallax]
|
||||
[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
|
||||
{:background :blur
|
||||
: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]
|
||||
[rn/view {:style style/page-illustration}
|
||||
[quo/text
|
||||
|
||||
@@ -35,11 +35,30 @@
|
||||
{:biometric/authenticate {:on-success #(rf/dispatch [:onboarding-2/biometrics-done])
|
||||
: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
|
||||
{:events [:onboarding-2/biometrics-done]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:onboarding-2/profile :auth-method] constants/auth-method-biometric)
|
||||
:dispatch [:onboarding-2/create-account-and-login]})
|
||||
(let [syncing? (get-in db [:onboarding-2/profile :syncing?])]
|
||||
{: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
|
||||
{:events [:onboarding-2/biometrics-fail]}
|
||||
@@ -83,6 +102,14 @@
|
||||
[:navigate-to-within-stack [:enable-biometrics :new-to-status]]
|
||||
[: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
|
||||
{:events [:onboarding-2/seed-phrase-entered]}
|
||||
[_ seed-phrase on-error]
|
||||
@@ -120,6 +147,7 @@
|
||||
[{:keys [db]}]
|
||||
(let [masked-password (get-in db [:onboarding-2/profile :password])
|
||||
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])
|
||||
constants/auth-method-biometric)]
|
||||
(cond-> {:db (assoc db :onboarding-2/generated-keys? true)}
|
||||
@@ -127,7 +155,10 @@
|
||||
(assoc :keychain/save-password-and-auth-method
|
||||
{:key-uid key-uid
|
||||
: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"
|
||||
{:key-uid key-uid
|
||||
:error %})}))))
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
{:on-press (fn []
|
||||
(when on-press
|
||||
(on-press))
|
||||
(rf/dispatch [:open-modal :enable-notifications]))
|
||||
(rf/dispatch [:onboarding-2/navigate-to-enable-biometrics]))
|
||||
:accessibility-label :continue-button
|
||||
:customization-color profile-color
|
||||
:container-style style/continue-button}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.quo-preview.wallet.keypair
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
@@ -101,8 +102,9 @@
|
||||
:component-container-style {:padding-vertical 30
|
||||
:flex-direction :row
|
||||
:justify-content :center}}
|
||||
[quo/keypair
|
||||
(merge
|
||||
@state
|
||||
{:details (if (= (:type @state) :default-keypair) default-details other-details)
|
||||
:accounts (get-accounts (:blur? @state))})]])))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/keypair
|
||||
(merge
|
||||
@state
|
||||
{:details (if (= (:type @state) :default-keypair) default-details other-details)
|
||||
:accounts (get-accounts (:blur? @state))})]]])))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[quo.foundations.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.data-store.settings :as data-store.settings]
|
||||
@@ -36,6 +37,26 @@
|
||||
:custom-bootnodes-enabled? false}}]
|
||||
(node/get-multiaccount-node-config db)))
|
||||
|
||||
(defn- extract-error
|
||||
[json-str]
|
||||
(-> json-str
|
||||
transforms/json->clj
|
||||
(get :error "")
|
||||
not-empty))
|
||||
|
||||
(defn- input-connection-string-callback
|
||||
[res]
|
||||
(log/info "[local-pairing] input-connection-string-for-bootstrapping callback"
|
||||
{:response res
|
||||
:event :syncing/input-connection-string-for-bootstrapping})
|
||||
(let [error (when (extract-error res)
|
||||
(str "generic-error: " res))]
|
||||
(when (some? error)
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:icon :i/alert
|
||||
:icon-color colors/danger-50
|
||||
:text error}]))))
|
||||
|
||||
(rf/defn preflight-outbound-check-for-local-pairing
|
||||
{:events [:syncing/preflight-outbound-check]}
|
||||
[_ set-checks-passed]
|
||||
@@ -60,19 +81,18 @@
|
||||
(fn [final-node-config]
|
||||
(let [config-map (.stringify js/JSON
|
||||
(clj->js
|
||||
{:receiverConfig {:kdfIterations config/default-kdf-iterations
|
||||
:nodeConfig final-node-config
|
||||
:settingCurrentNetwork config/default-network
|
||||
:deviceType platform/os
|
||||
:deviceName
|
||||
(native-module/get-installation-name)}}))]
|
||||
{:receiverConfig
|
||||
{:kdfIterations config/default-kdf-iterations
|
||||
:nodeConfig final-node-config
|
||||
:settingCurrentNetwork config/default-network
|
||||
:deviceType platform/os
|
||||
:deviceName
|
||||
(native-module/get-installation-name)}}))]
|
||||
(rf/dispatch [:syncing/update-role constants/local-pairing-role-receiver])
|
||||
(native-module/input-connection-string-for-bootstrapping
|
||||
connection-string
|
||||
config-map
|
||||
#(log/info "Initiated local pairing"
|
||||
{:response %
|
||||
:event :syncing/input-connection-string-for-bootstrapping}))))]
|
||||
input-connection-string-callback)))]
|
||||
(native-module/prepare-dir-and-update-config "" default-node-config-string callback)))
|
||||
|
||||
(rf/defn preparations-for-connection-string
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.qr-codes.view :as qr-codes]
|
||||
[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.utils :as sync-utils]
|
||||
[utils.datetime :as datetime]
|
||||
@@ -119,7 +119,7 @@
|
||||
(i18n/label :t/copy-qr)]])
|
||||
(when-not (sync-utils/valid-connection-string? @code)
|
||||
[rn/view {:style style/standard-auth}
|
||||
[standard-auth/view
|
||||
[standard-auth/slide-button
|
||||
{:blur? true
|
||||
:size :size-40
|
||||
:track-text (i18n/label :t/slide-to-reveal-code)
|
||||
|
||||
@@ -62,10 +62,11 @@
|
||||
{:content buy-drawer}])
|
||||
:bridge-action #(rf/dispatch [:open-modal :wallet-bridge])}]
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:default-active @selected-tab
|
||||
:data tabs-data
|
||||
:on-change #(reset! selected-tab %)
|
||||
:scrollable? true}]
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:default-active @selected-tab
|
||||
:data tabs-data
|
||||
:on-change #(reset! selected-tab %)
|
||||
:scrollable? true
|
||||
:scroll-on-press? true}]
|
||||
[tabs/view {:selected-tab @selected-tab}]]))))
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.wallet.add-watch-only-account.style)
|
||||
(ns status-im2.contexts.wallet.add-address-to-watch.confirm-address.style)
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
+5
-4
@@ -1,13 +1,14 @@
|
||||
(ns status-im2.contexts.wallet.add-watch-only-account.views
|
||||
(ns status-im2.contexts.wallet.add-address-to-watch.confirm-address.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.emoji-picker.utils :as emoji-picker.utils]
|
||||
[status-im2.contexts.wallet.add-watch-only-account.style :as style]
|
||||
[status-im2.contexts.wallet.add-address-to-watch.confirm-address.style :as style]
|
||||
[status-im2.contexts.wallet.common.screen-base.create-or-edit-account.view :as
|
||||
create-or-edit-account]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -20,7 +21,7 @@
|
||||
account-name (reagent/atom (i18n/label :t/default-account-name
|
||||
{:number (inc number-of-accounts)}))
|
||||
address-title (i18n/label :t/watch-address)
|
||||
account-color (reagent/atom :blue)
|
||||
account-color (reagent/atom (rand-nth colors/account-colors))
|
||||
account-emoji (reagent/atom (emoji-picker.utils/random-emoji))
|
||||
on-change-name #(reset! account-name %)
|
||||
on-change-color #(reset! account-color %)
|
||||
@@ -57,4 +58,4 @@
|
||||
:container-style style/data-item
|
||||
:on-press #(js/alert "To be implemented")}]]])))
|
||||
|
||||
(def address-add-edit (quo.theme/with-theme view-internal))
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
+3
-4
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.wallet.select-address-to-watch.style)
|
||||
(ns status-im2.contexts.wallet.add-address-to-watch.style)
|
||||
|
||||
(def header-container
|
||||
{:margin-horizontal 20
|
||||
@@ -10,9 +10,8 @@
|
||||
:padding-horizontal 20
|
||||
:align-items :flex-end})
|
||||
|
||||
(defn button-container
|
||||
[bottom]
|
||||
(def button-container
|
||||
{:position :absolute
|
||||
:bottom (- bottom 22)
|
||||
:bottom 22
|
||||
:left 20
|
||||
:right 20})
|
||||
+6
-10
@@ -1,4 +1,4 @@
|
||||
(ns status-im2.contexts.wallet.select-address-to-watch.view
|
||||
(ns status-im2.contexts.wallet.add-address-to-watch.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
@@ -6,22 +6,18 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.wallet.select-address-to-watch.style :as style]
|
||||
[status-im2.contexts.wallet.add-address-to-watch.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view-internal
|
||||
[]
|
||||
(let [top (safe-area/get-top)
|
||||
bottom (safe-area/get-bottom)
|
||||
input-value (reagent/atom "")
|
||||
(let [input-value (reagent/atom "")
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
(fn []
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:margin-top top}}
|
||||
{:style {:flex 1}}
|
||||
[quo/page-nav
|
||||
{:type :no-title
|
||||
:icon-name :i/close
|
||||
@@ -48,9 +44,9 @@
|
||||
{:customization-color customization-color
|
||||
:disabled? (clojure.string/blank? @input-value)
|
||||
:on-press #(re-frame/dispatch [:navigate-to
|
||||
:address-to-watch-edit
|
||||
:confirm-address-to-watch
|
||||
{:address @input-value}])
|
||||
:container-style (style/button-container bottom)}
|
||||
:container-style style/button-container}
|
||||
(i18n/label :t/continue)]])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
@@ -58,7 +58,8 @@
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/colour)
|
||||
:container-style style/section-container}]
|
||||
[rn/view {:style style/color-picker-container}
|
||||
[rn/view
|
||||
{:style style/color-picker-container}
|
||||
[quo/color-picker
|
||||
{:default-selected account-color
|
||||
:on-change on-change-color
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
(defn get-derivation-path
|
||||
[number-of-accounts]
|
||||
(str constants/path-wallet-root "/" number-of-accounts))
|
||||
|
||||
(defn format-derivation-path
|
||||
[path]
|
||||
(string/replace path "/" " / "))
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
(ns status-im2.contexts.wallet.create-account.select-keypair.style)
|
||||
|
||||
(def header-container
|
||||
{:margin-horizontal 20
|
||||
:margin-top 12
|
||||
:margin-bottom 20})
|
||||
|
||||
(def bottom-action-container
|
||||
{:position :absolute
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
@@ -0,0 +1,62 @@
|
||||
(ns status-im2.contexts.wallet.create-account.select-keypair.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.profile.utils :as profile.utils]
|
||||
[status-im2.contexts.wallet.create-account.select-keypair.style :as style]
|
||||
[utils.address :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def accounts
|
||||
[{:account-props {:customization-color :turquoise
|
||||
:size 32
|
||||
:emoji "\uD83C\uDFB2"
|
||||
:type :default
|
||||
:name "Trip to Vegas"
|
||||
:address "0x0ah...71a"}
|
||||
:networks [{:network-name :ethereum :short-name "eth"}
|
||||
{:network-name :optimism :short-name "opt"}]
|
||||
:state :default
|
||||
:action :none}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [public-key compressed-key
|
||||
customization-color]} (rf/sub [:profile/profile])
|
||||
display-name (first (rf/sub [:contacts/contact-two-names-by-identity
|
||||
public-key]))
|
||||
profile-with-image (rf/sub [:profile/profile-with-image])
|
||||
profile-picture (profile.utils/photo profile-with-image)]
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:accessibility-label :top-bar}]
|
||||
[quo/text-combinations
|
||||
{:container-style style/header-container
|
||||
:title (i18n/label :t/keypairs)
|
||||
:description (i18n/label :t/keypairs-description)
|
||||
:button-icon :i/add
|
||||
:button-on-press #(js/alert "not implemented")
|
||||
:customization-color customization-color}]
|
||||
[quo/keypair
|
||||
(merge
|
||||
{:customization-color customization-color
|
||||
:profile-picture profile-picture
|
||||
:status-indicator false
|
||||
:type :default-keypair
|
||||
:stored :on-device
|
||||
:on-options-press #(js/alert "Options pressed")
|
||||
:action :selector
|
||||
:blur? false
|
||||
:details {:full-name display-name
|
||||
:address (utils/get-shortened-compressed-key compressed-key)}
|
||||
:accounts accounts
|
||||
:container-style {:margin-horizontal 20
|
||||
:margin-vertical 8}})]
|
||||
[quo/bottom-actions
|
||||
{:button-one-label (i18n/label :t/confirm-account-origin)
|
||||
:button-one-props {:disabled? true
|
||||
:customization-color customization-color}
|
||||
:container-style style/bottom-action-container}]]))
|
||||
@@ -1,18 +1,21 @@
|
||||
(ns status-im2.contexts.wallet.create-account.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[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.contexts.emoji-picker.utils :as emoji-picker.utils]
|
||||
[status-im2.contexts.wallet.common.utils :as utils]
|
||||
[status-im2.contexts.wallet.create-account.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.responsiveness :refer [iphone-11-Pro-20-pixel-from-width]]))
|
||||
[utils.responsiveness :refer [iphone-11-Pro-20-pixel-from-width]]
|
||||
[utils.string]))
|
||||
|
||||
(defn keypair-string
|
||||
[full-name]
|
||||
@@ -20,30 +23,34 @@
|
||||
(i18n/label :t/keypair-title {:name first-name})))
|
||||
|
||||
(defn get-keypair-data
|
||||
[name derivation-path]
|
||||
[name derivation-path account-color]
|
||||
[{:title (keypair-string name)
|
||||
:left-icon :i/placeholder
|
||||
:image :avatar
|
||||
:image-props {:full-name (utils.string/get-initials name 1)
|
||||
:size :xxs
|
||||
:customization-color account-color}
|
||||
:action :button
|
||||
:action-props {:on-press #(js/alert "Button pressed!")
|
||||
:action-props {:on-press #(rf/dispatch [:navigate-to :wallet-select-keypair])
|
||||
:button-text (i18n/label :t/edit)
|
||||
:alignment :flex-start}
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/on-device)}}
|
||||
{:title (i18n/label :t/derivation-path)
|
||||
:image :icon
|
||||
:image-props :i/derivated-path
|
||||
:action :button
|
||||
:action-props {:on-press #(rf/dispatch [:navigate-to :wallet-edit-derivation-path])
|
||||
:action-props {:on-press #(js/alert "Button pressed!")
|
||||
:button-text (i18n/label :t/edit)
|
||||
:icon-left :i/placeholder
|
||||
:alignment :flex-start}
|
||||
:left-icon :i/derivated-path
|
||||
:description :text
|
||||
:description-props {:text derivation-path}}])
|
||||
:description-props {:text (string/replace derivation-path #"/" " / ")}}])
|
||||
|
||||
(defn- view-internal
|
||||
[]
|
||||
(let [top (safe-area/get-top)
|
||||
bottom (safe-area/get-bottom)
|
||||
account-color (reagent/atom :blue)
|
||||
account-color (reagent/atom (rand-nth colors/account-colors))
|
||||
emoji (reagent/atom (emoji-picker.utils/random-emoji))
|
||||
number-of-accounts (count (rf/sub [:wallet/accounts]))
|
||||
account-name (reagent/atom (i18n/label :t/default-account-name
|
||||
@@ -106,8 +113,8 @@
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:label (i18n/label :t/origin)
|
||||
:data (get-keypair-data primary-name @derivation-path)}]
|
||||
[standard-auth/view
|
||||
:data (get-keypair-data primary-name @derivation-path @account-color)}]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-create-account)
|
||||
:customization-color @account-color
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
:accessibility-label :add-a-contact
|
||||
:label (i18n/label :t/add-address)
|
||||
:sub-label (i18n/label :t/add-address-description)
|
||||
:on-press #(rf/dispatch [:navigate-to :wallet-address-watch])
|
||||
:on-press #(rf/dispatch [:navigate-to :add-address-to-watch])
|
||||
:add-divider? true}]]])
|
||||
|
||||
(defn- add-account-placeholder
|
||||
|
||||
@@ -39,14 +39,15 @@
|
||||
[status-im2.contexts.syncing.syncing-devices-list.view :as settings-syncing]
|
||||
[status-im2.contexts.wallet.account.bridge.view :as bridge]
|
||||
[status-im2.contexts.wallet.account.view :as wallet-accounts]
|
||||
[status-im2.contexts.wallet.add-watch-only-account.views :as address-add-edit]
|
||||
[status-im2.contexts.wallet.add-address-to-watch.confirm-address.view :as confirm-address-to-watch]
|
||||
[status-im2.contexts.wallet.add-address-to-watch.view :as add-address-to-watch]
|
||||
[status-im2.contexts.wallet.collectible.view :as wallet-collectible]
|
||||
[status-im2.contexts.wallet.create-account.edit-derivation-path.view :as wallet-edit-derivation-path]
|
||||
[status-im2.contexts.wallet.create-account.select-keypair.view :as wallet-select-keypair]
|
||||
[status-im2.contexts.wallet.create-account.view :as wallet-create-account]
|
||||
[status-im2.contexts.wallet.edit-account.view :as wallet-edit-account]
|
||||
[status-im2.contexts.wallet.saved-address.view :as wallet-saved-address]
|
||||
[status-im2.contexts.wallet.scan-account.view :as scan-address]
|
||||
[status-im2.contexts.wallet.select-address-to-watch.view :as wallet-address-watch]
|
||||
[status-im2.contexts.wallet.send.select-address.view :as wallet-select-address]
|
||||
[status-im2.navigation.options :as options]
|
||||
[status-im2.navigation.transitions :as transitions]))
|
||||
@@ -160,11 +161,15 @@
|
||||
:component create-password/create-password}
|
||||
|
||||
{:name :enable-biometrics
|
||||
:options {:theme :dark
|
||||
:layout options/onboarding-transparent-layout
|
||||
:animations transitions/push-animations-for-transparent-background
|
||||
:popGesture false}
|
||||
:component enable-biometrics/enable-biometrics}
|
||||
:options {:theme :dark
|
||||
:layout options/onboarding-transparent-layout
|
||||
:animations (merge transitions/new-to-status-modal-animations
|
||||
transitions/push-animations-for-transparent-background)
|
||||
:popGesture false
|
||||
:modalPresentationStyle :overCurrentContext
|
||||
:hardwareBackButton {:dismissModalOnPress false
|
||||
:popStackOnPress false}}
|
||||
:component enable-biometrics/view}
|
||||
|
||||
{:name :generating-keys
|
||||
:options {:theme :dark
|
||||
@@ -248,16 +253,16 @@
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-accounts/view}
|
||||
|
||||
{:name :address-to-watch-edit
|
||||
:component address-add-edit/address-add-edit}
|
||||
|
||||
{:name :wallet-edit-account
|
||||
:component wallet-edit-account/view}
|
||||
|
||||
{:name :wallet-address-watch
|
||||
{:name :add-address-to-watch
|
||||
:options {:insets {:top? true
|
||||
:bottom? true}}
|
||||
:component wallet-address-watch/view}
|
||||
:component add-address-to-watch/view}
|
||||
|
||||
{:name :confirm-address-to-watch
|
||||
:component confirm-address-to-watch/view}
|
||||
|
||||
{:name :wallet-bridge
|
||||
:options {:insets {:top? true}
|
||||
@@ -270,6 +275,10 @@
|
||||
{:name :wallet-collectible
|
||||
:component wallet-collectible/view}
|
||||
|
||||
{:name :wallet-select-keypair
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-select-keypair/view}
|
||||
|
||||
{:name :wallet-create-account
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-create-account/view}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
(let [first-part-of-public-key (subs public-key 0 3)
|
||||
ellipsis "..."
|
||||
public-key-size (count public-key)
|
||||
last-part-of-public-key (subs public-key (- public-key-size 6) public-key-size)
|
||||
last-part-of-public-key (subs public-key (- public-key-size 5) public-key-size)
|
||||
abbreviated-public-key (str first-part-of-public-key ellipsis last-part-of-public-key)]
|
||||
abbreviated-public-key)
|
||||
nil))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
(deftest get-shortened-compressed-key
|
||||
(testing "Ensure the function correctly abbreviates a valid public key"
|
||||
(is (= "zQ3...1sgt5N"
|
||||
(is (= "zQ3...sgt5N"
|
||||
(utils.address/get-shortened-compressed-key
|
||||
"zQ3ssgRy5TtB47MMiMKMKaGyaawkCgMqqbrnAUYrZJ1sgt5N"))))
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.171.11",
|
||||
"commit-sha1": "8a4c2d8d2f17117aa0a00338e83b0f753ebf1328",
|
||||
"src-sha256": "160qnl9dsl1ypvqg9w6z8wps4fvgq3qxi16piymhrlzgssdwkz8h"
|
||||
"version": "debug/resend-edits",
|
||||
"commit-sha1": "f1d1726a4e12159013d72008c949fee77e48627c",
|
||||
"src-sha256": "0yl33bsq7x59mp8s029qw00h0m5wfg28zk3r1w7zp3m6w4j34p3d"
|
||||
}
|
||||
|
||||
@@ -2374,12 +2374,15 @@
|
||||
"reset": "Reset",
|
||||
"reveal-address": "Reveal address",
|
||||
"derive-addresses": "Derive addresses",
|
||||
"address-activity": "This address has activity",
|
||||
"sign transactions": "sign transactions",
|
||||
"search-assets": "Search assets",
|
||||
"account-created": "{{name}} created",
|
||||
"update-account-name": "Update account name",
|
||||
"edit-wallet-account-emoji-updated-message": "Account emoji has been updated",
|
||||
"edit-wallet-account-name-updated-message": "Account name has been updated",
|
||||
"edit-wallet-account-colour-updated-message": "Account colour has been updated"
|
||||
"edit-wallet-account-colour-updated-message": "Account colour has been updated",
|
||||
"search-assets": "Search assets",
|
||||
"address-activity": "This address has activity",
|
||||
"keypairs": "Keypairs",
|
||||
"keypairs-description": "Select keypair to derive your new account from",
|
||||
"confirm-account-origin": "Confirm account origin"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user