Compare commits

...
Author SHA1 Message Date
Sean Hagstrom 0699cf846b pass use-callback function 2024-03-27 14:17:50 +00:00
Sean Hagstrom 7780fa0b20 tweak: pass anonymous function 2024-03-27 14:17:32 +00:00
Sean Hagstrom 42b1444e0c tweak: add some props to example component 2024-03-27 14:08:23 +00:00
Sean Hagstrom a7c17685fe tweak: add extra debug component 2024-03-27 14:06:57 +00:00
Sean Hagstrom e5d10f5585 tweak: debug renders 2024-03-27 13:56:16 +00:00
Sean Hagstrom 423a6f7521 tweak: remove extra ideas 2024-03-27 13:49:10 +00:00
Sean Hagstrom 1c78004b08 tweak: use debug labels for buttons 2024-03-27 13:16:20 +00:00
Sean Hagstrom f99d1bbaed tweak: only debug buttons with string children 2024-03-27 13:16:11 +00:00
Sean Hagstrom ec38cb3d72 tidy: rename functions to be more descriptive 2024-03-27 12:47:16 +00:00
Sean Hagstrom e9c15373e5 fix: subscription leak during hot reload by using use-memo 2024-03-27 12:46:37 +00:00
Sean Hagstrom 395ea5d507 tweak: log when button component renders 2024-03-27 11:57:05 +00:00
Sean Hagstrom 1b3c8c1e54 tweak: refactor example to use reagent.ratom/track and reagent.ratom/track! functions with message state 2024-03-26 11:32:35 +00:00
Sean Hagstrom e76434edab wip: add small experiment for ui callback with state and memoization 2024-03-26 09:45:52 +00:00
Sean Hagstrom 31a22cd339 tweak: forward on-press events 2024-03-26 09:45:17 +00:00
Parvesh Monu 6a88a34d34 add empty check for keychain credentials server (#19242) 2024-03-26 12:15:35 +05:30
Ibrahem Khalil 3be1532b32 All addresses text is not updated when changing accounts (#19379) 2024-03-25 22:14:40 +02:00
Ibrahem Khalil 44846c80c8 Error when marking a community notification as read in the activity center #19388 (#19390) 2024-03-25 21:36:24 +02:00
Ulises Manuel a405de62e6 [#18833] Confirm button disappearing while editing address (#19186)
* Fix button disappearing when keyboard is hidden

* Improve keyboard scrolling
2024-03-25 09:00:10 -06:00
flexsurfer 06dc9ea1d3 Unable to enter/clear smoothly the data into contacts field #19384 (#19385) 2024-03-25 15:17:08 +01:00
Ajay Sivan 32a4bb1153 fix: very small token values are being displayed in scientific format (#19349) 2024-03-25 06:05:53 -07:00
Sean Hagstrom 418053b21e Tweak UI for contact request notifications (#19337)
* fix: ensure contact-request notifications are displayed as notifications

* fix: provide context-theme for notification sub-components

* fix: adjust font weight for notification text

* fix: adjust alignment of user-avatar inside a notification with a header and body

* tidy: rename override-theme to theme inside notifications

* fix: update notifications component to use `user` prop instead of `avatar`

* tweak: adapt notification to avatar to vertically center when only displaying header or title

* fix: use title font-size for contact-request-accepted notification

* fix: allow for custom avatar component prop in quo notification component

* fix: ensure we use the correct font-weight for contact-request-accepted notification

* tidy: fix formatting
2024-03-25 10:17:47 +00:00
flexsurfer 2528efb538 fix input issues (#19341) 2024-03-25 10:42:20 +01:00
27 changed files with 419 additions and 358 deletions
+4 -1
View File
@@ -62,7 +62,10 @@
(defn <-color
[value]
(if (string/starts-with? value "#") value (keyword value)))
(if (and (some? value)
(string/starts-with? value "#"))
value
(keyword value)))
(defn <-rpc
[chat]
@@ -35,6 +35,7 @@
size 40
customization-color (if (= type :primary) :blue nil)}}
children]
(when (string? children) (js/console.log "button - " children))
(let [[pressed-state? set-pressed-state] (rn/use-state false)
theme (theme/use-theme-value)
{:keys [icon-color background-color label-color border-color blur-type
@@ -61,7 +61,7 @@
(h/fire-event :on-blur (h/get-by-label-text :address-text-input))
(h/has-prop (h/get-by-label-text :address-text-input)
:placeholder-text-color
colors/neutral-30))))))
colors/neutral-40))))))
(h/test "on blur with text blur? true"
(with-redefs [clipboard/get-string #(% "")]
@@ -75,7 +75,7 @@
(h/fire-event :on-blur (h/get-by-label-text :address-text-input))
(h/has-prop (h/get-by-label-text :address-text-input)
:placeholder-text-color
colors/neutral-80-opa-20))))))
colors/neutral-80-opa-40))))))
(h/test "on blur with no text and blur? false"
(with-redefs [clipboard/get-string #(% "")]
@@ -58,78 +58,64 @@
[{:keys [default-value blur? on-change-text on-blur on-focus on-clear on-scan
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
valid-ens-or-address? container-style]}]
(let [theme (quo.theme/use-theme-value)
[status set-status] (rn/use-state :default)
value (rn/use-ref-atom nil)
[_ trigger-render-value] (rn/use-state @value)
[focused? set-focused] (rn/use-state false)
on-change (rn/use-callback
(fn [text]
(let [address? (when address-regex
(boolean (re-matches address-regex text)))
ens? (when ens-regex
(boolean (re-matches ens-regex text)))]
(reset! value text)
(if (> (count text) 0)
(set-status :typing)
(set-status :active))
(when on-change-text
(on-change-text text))
(when (and on-detect-ens ens?)
(set-status :loading)
(on-detect-ens text #(set-status :typing)))
(when (and address? on-detect-address)
(set-status :loading)
(on-detect-address text))
(when (and (not address?)
(not ens?)
on-detect-unclassified)
(on-detect-unclassified text)))))
set-value (rn/use-callback
(fn [new-value]
(reset! value new-value)
(on-change new-value)
(trigger-render-value new-value)))
on-paste (rn/use-callback
(fn []
(clipboard/get-string
(fn [clipboard]
(when-not (empty? clipboard)
(set-value clipboard))))))
on-clear (rn/use-callback
(fn []
(set-value "")
(set-status (if focused? :active :default))
(when on-change-text
(on-change-text ""))
(when on-clear
(on-clear)))
[focused?])
on-clear (rn/use-callback
(fn []
(set-value "")
(set-status (if focused? :active :default))
(when on-change-text
(on-change-text ""))
(when on-clear
(on-clear)))
[focused?])
on-scan (when on-scan (rn/use-callback #(on-scan set-value)))
on-focus (rn/use-callback
(fn []
(when (= (count @value) 0)
(let [theme (quo.theme/use-theme-value)
[status set-status] (rn/use-state :default)
[value set-value] (rn/use-state nil)
[focused? set-focused] (rn/use-state false)
on-change (rn/use-callback
(fn [text]
(let [address? (when address-regex
(boolean (re-matches address-regex text)))
ens? (when ens-regex
(boolean (re-matches ens-regex text)))]
(set-value text)
(if (> (count text) 0)
(set-status :typing)
(set-status :active))
(set-focused true)
(when on-focus (on-focus))))
on-blur (rn/use-callback
(fn []
(when (= status :active)
(set-status :default))
(set-focused false)
(when on-blur (on-blur)))
[status])
placeholder-text-color (rn/use-memo #(get-placeholder-text-color status theme blur?)
[status theme blur?])]
(when on-change-text
(on-change-text text))
(when (and on-detect-ens ens?)
(set-status :loading)
(on-detect-ens text #(set-status :typing)))
(when (and address? on-detect-address)
(set-status :loading)
(on-detect-address text))
(when (and (not address?)
(not ens?)
on-detect-unclassified)
(on-detect-unclassified text)))))
on-paste (rn/use-callback
(fn []
(clipboard/get-string
(fn [clipboard]
(when-not (empty? clipboard)
(on-change clipboard))))))
on-clear (rn/use-callback
(fn []
(on-change "")
(set-status (if focused? :active :default))
(when on-change-text
(on-change-text ""))
(when on-clear
(on-clear)))
[focused?])
on-scan (rn/use-callback #(when on-scan (on-scan on-change))
[on-scan])
on-focus (rn/use-callback
(fn []
(when (= (count value) 0)
(set-status :active))
(set-focused true)
(when on-focus (on-focus))))
on-blur (rn/use-callback
(fn []
(when (= status :active)
(set-status :default))
(set-focused false)
(when on-blur (on-blur)))
[status])
placeholder-text-color (rn/use-memo #(get-placeholder-text-color status theme blur?)
[status theme blur?])]
(rn/use-mount #(on-change (or default-value "")))
[rn/view {:style (style/container container-style)}
[rn/text-input
@@ -137,7 +123,7 @@
:style (style/input-text theme)
:placeholder (i18n/label :t/name-ens-or-address)
:placeholder-text-color placeholder-text-color
:value @value
:value value
:auto-complete (when platform/ios? :off)
:auto-capitalize :none
:auto-correct false
+25 -11
View File
@@ -57,14 +57,19 @@
"Custom properties that must be removed from properties map passed to InputText."
[:type :blur? :error? :right-icon :left-icon :disabled? :small? :button
:label :char-limit :on-char-limit-reach :icon-name :multiline? :on-focus :on-blur
:container-style])
:container-style :ref])
(defn- base-input
[{:keys [blur? error? right-icon left-icon disabled? small? button
label char-limit multiline? clearable? on-focus on-blur container-style
on-change-text on-char-limit-reach weight default-value]
on-change-text on-char-limit-reach weight default-value on-clear]
:as props}]
(let [theme (quo.theme/use-theme-value)
ref (rn/use-ref-atom nil)
on-ref (rn/use-callback (fn [value]
(when (:ref props)
((:ref props) value))
(reset! ref value)))
[status set-status] (rn/use-state :default)
internal-on-focus (rn/use-callback #(set-status :focus))
internal-on-blur (rn/use-callback #(set-status :default))
@@ -93,6 +98,15 @@
:else status)
colors-by-status (style/status-colors status-kw blur? theme)
variant-colors (style/variants-colors blur? theme)
clear-on-press (rn/use-callback (fn []
(.clear ^js @ref)
(when on-clear (on-clear)))
[on-clear])
right-icon (or right-icon
(when clearable?
{:style-fn style/clear-icon
:icon-name :i/clear
:on-press clear-on-press}))
clean-props (apply dissoc props custom-props)]
[rn/view {:style container-style}
(when (or label char-limit)
@@ -108,7 +122,8 @@
:small? small?
:icon-name icon-name}])
[rn/text-input
(cond-> {:style (style/input colors-by-status small? multiple-lines? weight)
(cond-> {:ref on-ref
:style (style/input colors-by-status small? multiple-lines? weight)
:accessibility-label :input
:placeholder-text-color (:placeholder colors-by-status)
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
@@ -147,7 +162,10 @@
[{:keys [default-shown?]
:or {default-shown? false}
:as props}]
(let [[password-shown? set-password-shown] (rn/use-state default-shown?)]
(let [[password-shown?
set-password-shown] (rn/use-state default-shown?)
on-press (rn/use-callback #(set-password-shown (not password-shown?))
[password-shown?])]
[base-input
(assoc props
:accessibility-label :password-input
@@ -156,7 +174,7 @@
:secure-text-entry (not password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if password-shown? :i/hide-password :i/reveal)
:on-press #(set-password-shown (not password-shown?))})]))
:on-press on-press})]))
(defn input
"This input supports the following properties:
@@ -182,15 +200,11 @@
- :on-change-text
...
"
[{:keys [type clearable? on-clear icon-name]
[{:keys [type icon-name]
:or {type :text}
:as props}]
(let [base-props (cond-> props
icon-name (assoc-in [:left-icon :icon-name] icon-name)
clearable? (assoc :right-icon
{:style-fn style/clear-icon
:icon-name :i/clear
:on-press #(when on-clear (on-clear))}))]
icon-name (assoc-in [:left-icon :icon-name] icon-name))]
(if (= type :password)
[password-input base-props]
[base-input base-props])))
@@ -26,14 +26,20 @@
:padding-vertical 8
:padding-horizontal 12}))
(def right-side-container {:flex 1})
(def right-side-container
{:flex 1
:justify-content :center})
(defn title
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
[theme]
{:color (colors/theme-colors colors/white colors/neutral-100 theme)})
(defn text
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
[theme]
{:color (colors/theme-colors colors/white colors/neutral-100 theme)})
(def avatar-container {:margin-right 8 :margin-top 4})
(defn avatar-container
[{:keys [multiline?]}]
{:margin-right 8
:align-self (when-not multiline? :center)
:margin-top (if multiline? 4 0)})
@@ -1,7 +1,9 @@
(ns quo.components.notifications.notification.view
(:require
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.markdown.text :as text]
[quo.components.notifications.notification.style :as style]
[quo.theme]
[react-native.blur :as blur]
[react-native.core :as rn]))
@@ -15,33 +17,33 @@
[into [rn/view {:accessibility-label :notification-body}] children])
(defn avatar-container
[& children]
[{:keys [multiline?]} & children]
[into
[rn/view
{:style style/avatar-container
{:style (style/avatar-container {:multiline? multiline?})
:accessibility-label :notification-avatar}]
children])
(defn title
([text weight] (title text weight nil))
([text weight override-theme]
([{:keys [text weight theme multiline?]}]
[text/text
{:size :paragraph-1
:weight (or weight :semi-bold)
:style (style/title override-theme)
:weight (or weight (if multiline? :semi-bold :medium))
:style (style/title theme)
:accessibility-label :notification-title}
text]))
(defn message
[text override-theme]
[text theme]
[text/text
{:size :paragraph-2
:style (style/text override-theme)
:weight :medium
:style (style/text theme)
:accessibility-label :notification-content}
text])
(defn- notification-container
[{:keys [avatar header body container-style override-theme]}]
[{:keys [avatar header body container-style theme]}]
[rn/view
{:style (merge style/box-container container-style)}
[blur/view
@@ -51,7 +53,7 @@
:blur-type :transparent
:overlay-color :transparent}]
[rn/view
{:style (style/content-container override-theme)}
{:style (style/content-container theme)}
avatar
[rn/view
{:style style/right-side-container}
@@ -59,17 +61,27 @@
body]]])
(defn notification
[{title-text :title :keys [avatar header title-weight text body container-style override-theme]}]
(let [header (or header
(when title-text
[title title-text title-weight override-theme]))
header (when header [header-container header])
body (or body (when text [message text override-theme]))
body (when body [body-container body])
avatar (when avatar [avatar-container avatar])]
[notification-container
{:avatar avatar
:header header
:body body
:container-style container-style
:override-theme override-theme}]))
[{title-text :title :keys [avatar user header title-weight text body container-style theme]}]
(let [theme (or theme (quo.theme/get-theme))
body (or body (when text [message text theme]))
header (or header
(when title-text
[title
{:text title-text
:weight title-weight
:theme theme
:multiline? (some? body)}]))
header (when header [header-container header])
body (when body [body-container body])
user-avatar (or avatar (when user (user-avatar/user-avatar user)))
avatar (when user-avatar
[avatar-container
{:multiline? (and header body)}
user-avatar])]
[quo.theme/provider {:theme theme}
[notification-container
{:avatar avatar
:header header
:body body
:container-style container-style
:theme theme}]]))
+14 -11
View File
@@ -62,23 +62,26 @@
([server username password]
(save-credentials server username password identity))
([server username password callback]
(-> (.setInternetCredentials ^js react-native-keychain
(string/lower-case server)
username
password
keychain-secure-hardware
keychain-restricted-availability)
(.then callback))))
(when-not (empty? server)
(-> (.setInternetCredentials ^js react-native-keychain
(string/lower-case server)
username
password
keychain-secure-hardware
keychain-restricted-availability)
(.then callback)))))
(defn get-credentials
"Gets the credentials for a specified server from the Keychain"
([server]
(get-credentials server identity))
([server callback]
(-> (.getInternetCredentials ^js react-native-keychain (string/lower-case server))
(.then callback))))
(when-not (empty? server)
(-> (.getInternetCredentials ^js react-native-keychain (string/lower-case server))
(.then callback)))))
(defn reset-credentials
[server]
(-> (.resetInternetCredentials ^js react-native-keychain (string/lower-case server))
(.then #(when-not % (log/error (str "Error while clearing saved password."))))))
(when-not (empty? server)
(-> (.resetInternetCredentials ^js react-native-keychain (string/lower-case server))
(.then #(when-not % (log/error (str "Error while clearing saved password.")))))))
+2 -2
View File
@@ -14,11 +14,11 @@
[{:keys [on-press allow-multiple-presses? throttle-duration]} throttle-id]
(if allow-multiple-presses?
on-press
(fn []
(fn [event]
(let [id @throttle-id]
(when (and id (not (get @throttle id)))
(swap! throttle assoc id true)
(on-press)
(on-press event)
(js/setTimeout
#(swap! throttle dissoc id)
(or throttle-duration 500)))))))
+20 -22
View File
@@ -148,28 +148,26 @@
(reset! search-text ""))
(defn f-view
[{:keys [search-text on-change-text clear-states active-category scroll-ref theme]
[{:keys [search-active? on-change-text clear-states active-category scroll-ref theme]
:as sheet-opts}]
(let [search-active? (pos? (count @search-text))]
[rn/keyboard-avoiding-view
{:style style/flex-spacer
:keyboard-vertical-offset 8}
[rn/view {:style style/flex-spacer}
[rn/view {:style style/search-input-container}
[quo/input
{:small? true
:placeholder (i18n/label :t/emoji-search-placeholder)
:icon-name :i/search
:value @search-text
:on-change-text on-change-text
:clearable? search-active?
:on-clear clear-states}]]
[render-list sheet-opts]
(when-not search-active?
[footer
{:theme theme
:active-category active-category
:scroll-ref scroll-ref}])]]))
[rn/keyboard-avoiding-view
{:style style/flex-spacer
:keyboard-vertical-offset 8}
[rn/view {:style style/flex-spacer}
[rn/view {:style style/search-input-container}
[quo/input
{:small? true
:placeholder (i18n/label :t/emoji-search-placeholder)
:icon-name :i/search
:on-change-text on-change-text
:clearable? search-active?
:on-clear clear-states}]]
[render-list sheet-opts]
(when-not search-active?
[footer
{:theme theme
:active-category active-category
:scroll-ref scroll-ref}])]])
(defn- view-internal
[_]
@@ -202,7 +200,7 @@
(fn [sheet-opts]
[:f> f-view
(assoc sheet-opts
:search-text search-text
:search-active? (pos? (count @search-text))
:on-change-text on-change-text
:clear-states clear-states
:filtered-data @filtered-data
@@ -29,7 +29,7 @@
(reset! ratom height))))
(defn- init-keyboard-listeners
[{:keys [on-did-show]}]
[{:keys [on-did-show scroll-view-ref]}]
(let [keyboard-will-show? (reagent/atom false)
keyboard-did-show? (reagent/atom false)
add-listener (fn [listener callback]
@@ -41,7 +41,10 @@
(reset! keyboard-did-show? true)
(when on-did-show (on-did-show e))))
will-hide-listener (add-listener "keyboardWillHide"
#(reset! keyboard-will-show? false))
(fn []
(reset! keyboard-will-show? false)
(reagent/flush)
(.scrollTo @scroll-view-ref #js {:x 0 :y 0 :animated true})))
did-hide-listener (add-listener "keyboardDidHide"
#(reset! keyboard-did-show? false))
remove-listeners (fn []
@@ -55,9 +58,11 @@
(defn view
[{:keys [header footer customization-color footer-container-padding header-container-style
gradient-cover?]
:or {footer-container-padding (safe-area/get-top)}} &
children]
(reagent/with-let [window-height (:height (rn/get-window))
:or {footer-container-padding (safe-area/get-top)}}
& children]
(reagent/with-let [scroll-view-ref (atom nil)
set-scroll-ref #(reset! scroll-view-ref %)
window-height (:height (rn/get-window))
footer-container-height (reagent/atom 0)
header-height (reagent/atom 0)
content-container-height (reagent/atom 0)
@@ -66,7 +71,8 @@
{:keys [keyboard-will-show?
keyboard-did-show?
remove-listeners]} (init-keyboard-listeners
{:on-did-show
{:scroll-view-ref scroll-view-ref
:on-did-show
(fn [e]
(reset! keyboard-height
(oops/oget e "endCoordinates.height")))})
@@ -85,16 +91,22 @@
:header-height @header-height
:keyboard-shown? keyboard-shown?})]
[:<>
(when gradient-cover? [quo/gradient-cover {:customization-color customization-color}])
(when gradient-cover?
[quo/gradient-cover {:customization-color customization-color}])
[rn/view {:style style/page-container}
[rn/view
{:on-layout set-header-height
:style header-container-style}
header]
[gesture/scroll-view
{:on-scroll set-content-y-scroll
:scroll-event-throttle 64
:content-container-style {:flex-grow 1}}
{:ref set-scroll-ref
:on-scroll set-content-y-scroll
:scroll-event-throttle 64
:content-container-style {:flex-grow 1
:padding-bottom (when @keyboard-did-show?
@footer-container-height)}
:always-bounce-vertical @keyboard-did-show?
:shows-vertical-scroll-indicator false}
(into [rn/view {:on-layout set-content-container-height}]
children)]
[rn/keyboard-avoiding-view
@@ -3,7 +3,6 @@
[quo.core :as quo]
[react-native.clipboard :as clipboard]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.chat.home.add-new-contact.style :as style]
[utils.address :as address]
[utils.debounce :as debounce]
@@ -51,57 +50,66 @@
(defn- search-input
[]
(reagent/with-let [input-value (reagent/atom nil)
input-ref (atom nil)
clear-input (fn []
(reset! input-value nil)
(rf/dispatch [:contacts/clear-new-identity]))
paste-on-input #(clipboard/get-string
(fn [clipboard-text]
(reset! input-value clipboard-text)
(rf/dispatch [:contacts/set-new-identity
{:input clipboard-text}])))]
(let [{:keys [scanned] contact-public-key :id} (rf/sub [:contacts/new-identity])
contact-public-key-or-scanned (or contact-public-key scanned)
empty-input? (and (string/blank? @input-value)
(string/blank? contact-public-key-or-scanned))]
[rn/view {:style style/input-and-scan-container}
[quo/input
{:accessibility-label :enter-contact-code-input
:ref #(reset! input-ref %)
:container-style {:flex 1}
:auto-capitalize :none
:multiline? true
:blur-on-submit true
:return-key-type :done
:label (i18n/label :t/ens-or-chat-key)
:placeholder (i18n/label :t/type-some-chat-key)
:clearable? (not empty-input?)
:on-clear clear-input
:button (when empty-input?
{:on-press paste-on-input
:text (i18n/label :t/paste)})
;; NOTE: `contact-public-key-or-scanned` has priority over `@input-value`,
;; we clean it when the input is updated so that it's `nil` and
;; `@input-value`is shown. To fastly clean it, we use `dispatch-sync`.
;; This call could be avoided if `::qr-scanner/scan-code` were able to
;; receive a callback function, not only a re-frame event as callback.
:value (or contact-public-key-or-scanned @input-value)
:on-change-text (fn [new-text]
(reset! input-value new-text)
(as-> [:contacts/set-new-identity {:input new-text}] $
(if (string/blank? contact-public-key-or-scanned)
(debounce/debounce-and-dispatch $ 600)
(rf/dispatch-sync $))))}]
[rn/view {:style style/scan-button-container}
[quo/button
{:type :outline
:icon-only? true
:size 40
:on-press #(rf/dispatch [:open-modal :scan-profile-qr-code])}
:i/scan]]])
(finally
(rf/dispatch [:contacts/clear-new-identity]))))
(let [[input-value set-input-value] (rn/use-state nil)
input-ref (rn/use-ref-atom nil)
on-ref (rn/use-callback #(reset! input-ref %))
{:keys [scanned]
contact-public-key :id} (rf/sub [:contacts/new-identity])
contact-public-key-or-scanned (or contact-public-key scanned)
empty-input? (and (string/blank? input-value)
(string/blank? contact-public-key-or-scanned))
clear-input (rn/use-callback
(fn []
(set-input-value nil)
(rf/dispatch [:contacts/clear-new-identity])))
paste-on-input (rn/use-callback
(fn []
(clipboard/get-string
(fn [clipboard-text]
(set-input-value clipboard-text)
(rf/dispatch [:contacts/set-new-identity
{:input clipboard-text}])))))
on-change-text (rn/use-callback
(fn [new-text]
(set-input-value new-text)
(if (string/blank? contact-public-key-or-scanned)
(debounce/debounce-and-dispatch [:contacts/set-new-identity
{:input new-text}]
600)
(rf/dispatch-sync [:contacts/set-new-identity
{:input new-text}])))
[contact-public-key-or-scanned])]
(rn/use-unmount #(rf/dispatch [:contacts/clear-new-identity]))
[rn/view {:style style/input-and-scan-container}
[quo/input
{:accessibility-label :enter-contact-code-input
:ref on-ref
:container-style {:flex 1}
:auto-capitalize :none
:multiline? true
:blur-on-submit true
:return-key-type :done
:label (i18n/label :t/ens-or-chat-key)
:placeholder (i18n/label :t/type-some-chat-key)
:clearable? (not empty-input?)
:on-clear clear-input
:button (when empty-input?
{:on-press paste-on-input
:text (i18n/label :t/paste)})
;; NOTE: `contact-public-key-or-scanned` has priority over `input-value`,
;; we clean it when the input is updated so that it's `nil` and
;; `input-value`is shown. To fastly clean it, we use `dispatch-sync`.
;; This call could be avoided if `::qr-scanner/scan-code` were able to
;; receive a callback function, not only a re-frame event as callback.
:value (or contact-public-key-or-scanned input-value)
:on-change-text on-change-text}]
[rn/view {:style style/scan-button-container}
[quo/button
{:type :outline
:icon-only? true
:size 40
:on-press #(rf/dispatch [:open-modal :scan-profile-qr-code])}
:i/scan]]]))
(defn- invalid-text
[message]
@@ -20,6 +20,13 @@
has-permissions? (rf/sub [:communities/has-permissions? id])
airdrop-account (rf/sub [:communities/airdrop-account id])
revealed-accounts (rf/sub [:communities/accounts-to-reveal id])
revealed-accounts-count (count revealed-accounts)
wallet-accounts-count (count (rf/sub [:wallet/accounts-without-watched-accounts]))
addresses-shared-text (if (= revealed-accounts-count wallet-accounts-count)
(i18n/label :t/all-addresses)
(i18n/label-pluralize
revealed-accounts-count
:t/address-count))
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
@@ -108,7 +115,7 @@
:label :preview
:label-props {:type :accounts
:data revealed-accounts}
:description-props {:text (i18n/label :t/all-addresses)}}
:description-props {:text addresses-shared-text}}
{:title (i18n/label :t/for-airdrops)
:on-press show-airdrop-addresses
:description :text
@@ -153,7 +153,7 @@
@full-name
(i18n/label :t/your-name))
:customization-color @custom-color}
:title-input-props {:default-value @full-name
:title-input-props {:default-value display-name
:auto-focus true
:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
@@ -30,12 +30,11 @@
[]
[notification-button
"Notification: with title(header)"
{:avatar [quo/user-avatar
{:full-name "A Y"
:status-indicator? true
:online? true
:size :small
:customization-color :blue}]
{:user {:full-name "A Y"
:status-indicator? true
:online? true
:size :small
:customization-color :blue}
:title "Alisher Yakupov accepted your contact request"
:duration 4000
:title-weight :medium
@@ -45,12 +44,11 @@
[]
[notification-button
"with title and body"
{:avatar [quo/user-avatar
{:full-name "A Y"
:status-indicator? true
:online? true
:size :small
:customization-color :blue}]
{:user {:full-name "A Y"
:status-indicator? true
:online? true
:size :small
:customization-color :blue}
:title "Default to semibold title"
:text "The quick brown fox jumped over the lazy dog and ate a potatoe."
:duration 4000
@@ -60,12 +58,11 @@
[]
[notification-button
"with anything as header & body"
{:avatar [quo/user-avatar
{:full-name "A Y"
:status-indicator? true
:online? true
:size :small
:customization-color :blue}]
{:user {:full-name "A Y"
:status-indicator? true
:online? true
:size :small
:customization-color :blue}
:header [rn/view
[quo/info-message
{:type :success
@@ -2,12 +2,17 @@
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[reagent.ratom]
[status-im.constants :as constants]
[status-im.contexts.profile.contact.contact-request.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn example-component [props]
(js/console.log "example component render" (clj->js props))
[rn/text "Hello"])
(defn view
[]
(let [{:keys [public-key customization-color]
@@ -17,7 +22,9 @@
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
[message set-message] (rn/use-state "")
on-message-change (rn/use-callback #(set-message %))
on-message-change (rn/use-callback #(do
(set-message %)))
on-press-test (rn/use-callback #(rf/dispatch [:contacts/update-nickname public-key "Example nickname"]))
on-message-submit (rn/use-callback (fn []
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:contact.ui/send-contact-request
@@ -28,7 +35,10 @@
:text (i18n/label
:t/contact-request-was-sent)}]))
[public-key message])]
(js/console.log "contact request view render")
[:<>
[quo/button {} "Example static button"]
[example-component {:on-test on-press-test}]
[quo/drawer-top
{:type :context-tag
:context-tag-type :default
@@ -50,10 +60,14 @@
:label (i18n/label :t/message)
:on-change-text on-message-change}]]
[quo/bottom-actions
{:actions :one-action
{:actions :two-actions
:button-one-props {:disabled? (string/blank? message)
:accessibility-label :send-contact-request
:customization-color customization-color
:on-press on-message-submit}
:button-one-label (i18n/label :t/send-contact-request)}]]))
:button-one-label "Test Button One"
:button-two-props {:accessibility-label :test-button
:customization-color :danger
:on-press on-press-test}
:button-two-label "Test Button Two"}]]))
@@ -2,7 +2,6 @@
(:require
[legacy.status-im.data-store.activities :as activities]
[legacy.status-im.data-store.chats :as data-store.chats]
[quo.foundations.colors :as colors]
[re-frame.core :as re-frame]
[status-im.common.json-rpc.events :as json-rpc]
[status-im.common.toasts.events :as toasts]
@@ -544,9 +543,9 @@
(not accepted)
(not dismissed))
(toasts/upsert cofx
{:user user-avatar
{:type :notification
:user user-avatar
:user-public-key author
:icon-color colors/primary-50-opa-40
:title (i18n/label :t/contact-request-sent-toast
{:name name})
:text (get-in message [:content :text])})
@@ -556,10 +555,10 @@
accepted
(not dismissed))
(toasts/upsert cofx
{:user user-avatar
{:type :notification
:user user-avatar
;; user public key who accepted the request
:user-public-key chat-id
:icon-color colors/success-50-opa-40
:title (i18n/label :t/contact-request-accepted-toast
{:name (or name (:alias message))})})
:else
@@ -14,24 +14,19 @@
(defn view
[]
(let [{:keys [address]} (rf/sub [:get-screen-params])
number-of-accounts (count (rf/sub [:wallet/watch-only-accounts]))
account-name (reagent/atom "")
placeholder (i18n/label :t/default-watched-address-placeholder
{:number (inc number-of-accounts)})
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 %)
on-change-emoji #(reset! account-emoji %)]
(let [{:keys [address]} (rf/sub [:get-screen-params])
placeholder (i18n/label :t/default-watched-address-placeholder)
account-name (reagent/atom "")
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 %)
on-change-emoji #(reset! account-emoji %)]
(fn []
[rn/view {:style style/container}
[create-or-edit-account/view
{:page-nav-right-side [{:icon-name :i/info
:on-press
#(js/alert
"Get info (to be
implemented)")}]
:on-press #(js/alert "Get info (to be implemented)")}]
:placeholder placeholder
:account-name @account-name
:account-emoji @account-emoji
@@ -14,19 +14,16 @@
on-change-name
on-change-color
on-change-emoji section-label
hide-bottom-action?
bottom-action-label bottom-action-props
custom-bottom-action watch-only?]} & children]
(let [{window-width :width} (rn/get-window)
footer (when-not hide-bottom-action?
(if custom-bottom-action
custom-bottom-action
[quo/button
(merge
{:size 40
:type :primary}
bottom-action-props)
(i18n/label bottom-action-label)]))]
footer (if custom-bottom-action
custom-bottom-action
[quo/button
(merge {:size 40
:type :primary}
bottom-action-props)
(i18n/label bottom-action-label)])]
[floating-button-page/view
{:header [quo/page-nav
{:type :no-title
@@ -29,9 +29,4 @@
{:margin-top 12
:margin-bottom 8})
(defn slide-button-container
[bottom]
{:position :absolute
:bottom (+ bottom 12)
:left 20
:right 20})
(def slide-button-container {:z-index 1})
@@ -8,6 +8,7 @@
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.common.floating-button-page.view :as floating-button-page]
[status-im.common.standard-authentication.core :as standard-auth]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as utils]
@@ -20,7 +21,6 @@
[utils.security.core :as security]
[utils.string]))
(defn- get-keypair-data
[{:keys [title primary-keypair? new-keypair? derivation-path customization-color]}]
[{:title title
@@ -48,22 +48,24 @@
:description-props {:text (string/replace derivation-path #"/" " / ")}}])
(defn- f-view
[{:keys [theme]}]
(let [account-name (reagent/atom "")
account-color (reagent/atom (rand-nth colors/account-colors))
emoji (reagent/atom (emoji-picker.utils/random-emoji))]
(fn []
(let [top (safe-area/get-top)
bottom (safe-area/get-bottom)
{window-width :width} (rn/get-window)
number-of-accounts (count (rf/sub
[_]
(let [top (safe-area/get-top)
bottom (safe-area/get-bottom)
{window-width :width} (rn/get-window)
account-color (reagent/atom (rand-nth colors/account-colors))
emoji (reagent/atom (emoji-picker.utils/random-emoji))
account-name (reagent/atom "")
on-change-text #(reset! account-name %)
show-account-origin #(rf/dispatch [:show-bottom-sheet
{:content account-origin/view}])]
(fn [{:keys [theme]}]
(let [number-of-accounts (count (rf/sub
[:wallet/accounts-without-watched-accounts]))
{:keys [address customization-color]} (rf/sub [:profile/profile])
{:keys [new-keypair]} (rf/sub [:wallet/create-account])
keypairs (rf/sub [:wallet/keypairs])
selected-keypair-uid (rf/sub [:wallet/selected-keypair-uid])
placeholder (i18n/label :t/default-account-placeholder
{:number (inc number-of-accounts)})
placeholder (i18n/label :t/default-account-placeholder)
derivation-path (utils/get-derivation-path
number-of-accounts)
keypair (some #(when (= (:key-uid %) selected-keypair-uid)
@@ -94,20 +96,32 @@
{:name (:name keypair)})
(:name keypair)))]
(rn/use-unmount #(rf/dispatch [:wallet/clear-new-keypair]))
[rn/view {:style {:flex 1}}
[quo/page-nav
{:type :no-title
:background :blur
:right-side [{:icon-name :i/info
:on-press #(rf/dispatch [:show-bottom-sheet
{:content account-origin/view}])}]
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
[quo/gradient-cover
{:customization-color @account-color
:container-style {:top (- top)}}]
[rn/view
{:style style/account-avatar-container}
[floating-button-page/view
{:gradient-cover? true
:footer-container-padding 0
:header-container-style {:padding-top top}
:customization-color @account-color
:header [quo/page-nav
{:type :no-title
:background :blur
:right-side [{:icon-name :i/info
:on-press show-account-origin}]
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
:footer [standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color
:on-auth-success (fn [password]
(if new-keypair
(create-new-keypair-account password)
(create-existing-keypair-account
password)))
:auth-button-label (i18n/label :t/confirm)
:disabled? (empty? @account-name)
:container-style (style/slide-button-container bottom)
:dependencies [new-keypair]}]}
[rn/view {:style style/account-avatar-container}
[quo/account-avatar
{:customization-color @account-color
:size 80
@@ -121,19 +135,19 @@
:on-press #(rf/dispatch [:emoji-picker/open
{:on-select (fn [selected-emoji]
(reset! emoji selected-emoji))}])
:container-style style/reaction-button-container} :i/reaction]]
:container-style style/reaction-button-container}
:i/reaction]]
[quo/title-input
{:customization-color @account-color
:placeholder placeholder
:on-change-text #(reset! account-name %)
:on-change-text on-change-text
:max-length constants/wallet-account-name-max-length
:blur? true
:disabled? false
:default-value @account-name
:container-style style/title-input-container}]
[quo/divider-line]
[rn/view
{:style style/color-picker-container}
[rn/view {:style style/color-picker-container}
[quo/text
{:size :paragraph-2
:weight :medium
@@ -153,19 +167,7 @@
:primary-keypair? primary-keypair?
:new-keypair? (boolean new-keypair)
:derivation-path derivation-path
:customization-color customization-color})}]
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color
:on-auth-success (fn [password]
(if new-keypair
(create-new-keypair-account password)
(create-existing-keypair-account password)))
:auth-button-label (i18n/label :t/confirm)
:disabled? (empty? @account-name)
:container-style (style/slide-button-container bottom)
:dependencies [new-keypair]}]]))))
:customization-color customization-color})}]]))))
(defn- view-internal
[]
@@ -1,7 +1,6 @@
(ns status-im.contexts.wallet.edit-account.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[reagent.core :as reagent]
[status-im.contexts.wallet.common.screen-base.create-or-edit-account.view
:as create-or-edit-account]
@@ -53,16 +52,15 @@
:new-value @edited-account-name}))]
(fn []
(let [{:keys [name emoji address color watch-only? default-account?]
:as account} (rf/sub [:wallet/current-viewing-account])
network-details (rf/sub [:wallet/network-preference-details])
test-networks-enabled? (rf/sub [:profile/test-networks-enabled?])
network-preferences-key (if test-networks-enabled?
:test-preferred-chain-ids
:prod-preferred-chain-ids)
account-name (or @edited-account-name name)
button-disabled? (or (nil? @edited-account-name)
(= name @edited-account-name))
{:keys [keyboard-shown]} (hooks/use-keyboard)]
:as account} (rf/sub [:wallet/current-viewing-account])
network-details (rf/sub [:wallet/network-preference-details])
test-networks-enabled? (rf/sub [:profile/test-networks-enabled?])
network-preferences-key (if test-networks-enabled?
:test-preferred-chain-ids
:prod-preferred-chain-ids)
account-name (or @edited-account-name name)
button-disabled? (or (nil? @edited-account-name)
(= name @edited-account-name))]
[create-or-edit-account/view
{:page-nav-right-side [(when-not default-account?
{:icon-name :i/delete
@@ -77,7 +75,6 @@
:on-change-color #(on-change-color % account)
:on-change-emoji #(on-change-emoji % account)
:section-label :t/account-info
:hide-bottom-action? (and button-disabled? (not keyboard-shown))
:bottom-action-label :t/confirm
:bottom-action-props {:customization-color color
:disabled? button-disabled?
@@ -2,7 +2,8 @@
(:require [status-im.common.scan-qr-code.view :as scan-qr-code]
[status-im.constants :as constants]
[utils.debounce :as debounce]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- contains-address?
[s]
@@ -14,11 +15,15 @@
(defn view
[]
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:subtitle (i18n/label :t/scan-an-account-qr-code)
:error-message (i18n/label :t/oops-this-qr-does-not-contain-an-address)
:validate-fn #(contains-address? %)
:on-success-scan #(debounce/debounce-and-dispatch [:wallet/scan-address-success
(extract-address %)]
300)}])
(let [{:keys [on-result]} (rf/sub [:get-screen-params])]
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:subtitle (i18n/label :t/scan-an-account-qr-code)
:error-message (i18n/label :t/oops-this-qr-does-not-contain-an-address)
:validate-fn #(contains-address? %)
:on-success-scan (fn [result]
(let [address (extract-address result)]
(when on-result (on-result address))
(debounce/debounce-and-dispatch
[:wallet/scan-address-success address]
300)))}]))
@@ -35,10 +35,11 @@
[quo/address-input
{:on-focus #(reset! input-focused? true)
:on-blur #(reset! input-focused? false)
:on-scan (fn []
:on-scan (fn [on-result]
(rn/dismiss-keyboard!)
(rf/dispatch [:wallet/clean-scanned-address])
(rf/dispatch [:open-modal :screen/wallet.scan-address]))
(rf/dispatch [:open-modal :screen/wallet.scan-address
{:on-result on-result}]))
:ens-regex constants/regx-ens
:scanned-value (or (when recipient-plain-address? send-address) scanned-address)
:address-regex constants/regx-multichain-address
+6 -5
View File
@@ -4,8 +4,8 @@
[legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.utils :as wallet.utils]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.money :as money]))
(re-frame/reg-sub
:communities/fetching-community
@@ -306,12 +306,13 @@
[checking-permissions?
token-images
{:keys [satisfied criteria]}]
(let [sym (:symbol criteria)
amount (:amount criteria)]
(let [sym (:symbol criteria)
amount-in-wei (:amountInWei criteria)
decimals (:decimals criteria)]
{:symbol sym
:sufficient? satisfied
:loading? checking-permissions?
:amount (wallet.utils/remove-trailing-zeroes amount)
:amount (money/to-fixed (money/token->unit amount-in-wei decimals))
:img-src (get token-images sym)}))
(re-frame/reg-sub
+17 -13
View File
@@ -289,19 +289,23 @@
checks {:checking? checking-permissions?
:check
{:satisfied true
:highestRole {:type constants/community-token-permission-become-admin
:criteria [{:tokenRequirement [{:satisfied true
:criteria {:contract_addresses
{:5 "0x0"}
:type 1
:symbol "DAI"
:amount "5.0"
:decimals 18}}]}
{:tokenRequirement [{:satisfied false
:criteria {:type 1
:symbol "ETH"
:amount "0.002"
:decimals 18}}]}]}
:highestRole
{:type constants/community-token-permission-become-admin
:criteria [{:tokenRequirement [{:satisfied true
:criteria {:contract_addresses
{:5 "0x0"}
:type 1
:symbol "DAI"
:amountInWei
"5000000000000000000"
:amount "5.0"
:decimals 18}}]}
{:tokenRequirement [{:satisfied false
:criteria {:type 1
:symbol "ETH"
:amountInWei "2000000000000000"
:amount "0.002"
:decimals 18}}]}]}
:permissions
{:a3dd5b6b-d93b-452c-b22a-09a8f42ec566 {:criteria [true false
+7 -3
View File
@@ -450,8 +450,8 @@
"decline": "Decline",
"decryption-failed-content": "An error occured decrypting your data. You might need to erase your old data and generate a new account. Tap “Apply” to erase or “Cancel” to try again",
"default": "Default",
"default-account-placeholder": "Account {{number}}",
"default-watched-address-placeholder": "Watched address {{number}}",
"default-account-placeholder": "Account Name",
"default-watched-address-placeholder": "Watched address",
"delete": "Delete",
"delete-and-leave-group": "Delete and leave group",
"delete-bootnode": "Delete bootnode",
@@ -2558,5 +2558,9 @@
"ledger-live": "Ledger live",
"keep-key": "KeepKey",
"type-your-path": "Type your own derivation path",
"default-format": "Default format"
"default-format": "Default format",
"address-count": {
"one": "1 address",
"other": "{{count}} addresses"
}
}