chore: merge branch 'develop' into status-go/filter-improvements

This commit is contained in:
Prem Chaitanya Prathi 2024-06-13 18:46:09 +05:30
commit 59896858d0
60 changed files with 810 additions and 482 deletions

View File

@ -10,7 +10,7 @@
(reagent/as-element (reagent/as-element
(into [react/keyboard-avoiding-view (into [react/keyboard-avoiding-view
(update props (update props
:keyboardVerticalOffset :keyboard-vertical-offset
+ +
20 20
(if (:ignore-offset props) 44 0))] (if (:ignore-offset props) 44 0))]

View File

@ -275,7 +275,7 @@
(merge (when platform/ios? {:behavior :padding}) (merge (when platform/ios? {:behavior :padding})
(if (:ignore-offset props) (if (:ignore-offset props)
props props
(update props :keyboardVerticalOffset + 44 (:status-bar-height @navigation-const))))] (update props :keyboard-vertical-offset + 44 (:status-bar-height @navigation-const))))]
children)) children))
(defn keyboard-avoiding-view-new (defn keyboard-avoiding-view-new
@ -284,7 +284,7 @@
(merge (when platform/ios? {:behavior :padding}) (merge (when platform/ios? {:behavior :padding})
(if (:ignore-offset props) (if (:ignore-offset props)
props props
(update props :keyboardVerticalOffset + 44)))] (update props :keyboard-vertical-offset + 44)))]
children)) children))
(defn scroll-view (defn scroll-view

View File

@ -30,10 +30,7 @@
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)) (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))
:container-style style/title-icon-container :container-style style/title-icon-container
:accessibility-label :title-icon}])] :accessibility-label :title-icon}])]
[address-text/view [address-text/view (assoc account-props :format :short)]]])
{:networks (:networks account-props)
:address (:address account-props)
:format :short}]]])
(defn- balance-view (defn- balance-view
[{:keys [balance-props type theme]}] [{:keys [balance-props type theme]}]

View File

@ -25,12 +25,12 @@
:blur :grey}) :blur :grey})
(defn- page-nav-base (defn- page-nav-base
[{:keys [margin-top background on-press accessibility-label icon-name behind-overlay?] [{:keys [margin-top background on-press accessibility-label icon-name behind-overlay? align-center?]
:or {background :white}} :or {background :white}}
& children] & children]
(into [rn/view {:style (style/container margin-top)} (into [rn/view {:style (style/container margin-top)}
(when icon-name (when icon-name
[rn/view {:style style/icon-container} [rn/view (when align-center? {:style style/icon-container})
[button/button [button/button
{:type (button-type background) {:type (button-type background)
:icon-only? true :icon-only? true

View File

@ -0,0 +1,32 @@
(ns quo.components.tabs.tabs.schema)
(def ^:private ?data
[:sequential
[:maybe
[:map
[:id [:or :int :keyword [:set :int]]]
[:label [:maybe :string]]
[:accessibility-label {:optional true} [:maybe [:or :keyword :string]]]
[:notification-dot? {:optional true} [:maybe :boolean]]]]])
(def ?schema
[:=>
[:catn
[:props
[:map
[:default-active {:optional true} [:maybe [:or :int :keyword]]]
[:active-tab-id {:optional true} [:maybe [:or :int :keyword]]]
[:data ?data]
[:fade-end-percentage {:optional true} [:or :double :string]]
[:fade-end? {:optional true} [:maybe :boolean]]
[:blur? {:optional true} [:maybe :boolean]]
[:on-change {:optional true} [:maybe fn?]]
[:on-scroll {:optional true} [:maybe fn?]]
[:scroll-on-press? {:optional true} [:maybe :boolean]]
[:scrollable? {:optional true} [:maybe :boolean]]
[:style {:optional true} [:maybe :map]]
[:container-style {:optional true} [:maybe :map]]
[:size {:optional true} [:maybe [:or :keyword :int]]]
[:in-scroll-view? {:optional true} [:maybe :boolean]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]]]]
:any])

View File

@ -2,12 +2,14 @@
(:require (:require
[oops.core :refer [oget]] [oops.core :refer [oget]]
[quo.components.tabs.tab.view :as tab] [quo.components.tabs.tab.view :as tab]
[quo.components.tabs.tabs.schema :as component-schema]
[quo.components.tabs.tabs.style :as style] [quo.components.tabs.tabs.style :as style]
[react-native.core :as rn] [react-native.core :as rn]
[react-native.gesture :as gesture] [react-native.gesture :as gesture]
[react-native.linear-gradient :as linear-gradient] [react-native.linear-gradient :as linear-gradient]
[react-native.masked-view :as masked-view] [react-native.masked-view :as masked-view]
[reagent.core :as reagent] [reagent.core :as reagent]
[schema.core :as schema]
[utils.collection :as utils.collection] [utils.collection :as utils.collection]
[utils.number])) [utils.number]))
@ -84,36 +86,20 @@
:on-press #(on-press % index)} :on-press #(on-press % index)}
label]]) label]])
(defn view (defn- view-internal
" Common options (for scrollable and non-scrollable tabs):
- `blur?` Boolean passed down to `quo.components.tabs.tab/tab`.
- `data` Vector of tab items.
- `on-change` Callback called after a tab is selected.
- `size` 32/24
- `style` Style map passed to View wrapping tabs or to the FlatList when tabs
are scrollable.
Options for scrollable tabs:
- `fade-end-percentage` Percentage where fading starts relative to the total
layout width of the `flat-list` data.
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
- `on-scroll` Callback called on the on-scroll event of the FlatList. Only
used when `scrollable?` is non-nil.
- `scrollable?` When non-nil, use a scrollable flat-list to render tabs.
- `scroll-on-press?` When non-nil, clicking on a tag centers it the middle
(with animation enabled).
"
[{:keys [default-active data fade-end-percentage fade-end? on-change on-scroll scroll-on-press? [{:keys [default-active data fade-end-percentage fade-end? on-change on-scroll scroll-on-press?
scrollable? style container-style size blur? in-scroll-view? customization-color] scrollable? style container-style size blur? in-scroll-view? customization-color
active-tab-id]
:or {fade-end-percentage 0.8 :or {fade-end-percentage 0.8
fade-end? false fade-end? false
scrollable? false scrollable? false
scroll-on-press? false scroll-on-press? false
size default-tab-size} size default-tab-size}
:as props}] :as props}]
(let [[active-tab-id (let [[active-tab-internal-id
set-active-tab-id] (rn/use-state default-active) set-active-tab-internal-id] (rn/use-state default-active)
tab-id (or active-tab-id active-tab-internal-id)
[fading set-fading] (rn/use-state fade-end-percentage) [fading set-fading] (rn/use-state fade-end-percentage)
flat-list-ref (rn/use-ref-atom nil) flat-list-ref (rn/use-ref-atom nil)
tabs-data (rn/use-memo (fn [] (filterv some? data)) tabs-data (rn/use-memo (fn [] (filterv some? data))
@ -143,11 +129,11 @@
{:animated false {:animated false
:index :index
(utils.collection/first-index (utils.collection/first-index
#(= active-tab-id (:id %)) #(= tab-id (:id %))
tabs-data)})))) tabs-data)}))))
[active-tab-id tabs-data]) [tab-id tabs-data])
on-tab-press (rn/use-callback (fn [id index] on-tab-press (rn/use-callback (fn [id index]
(set-active-tab-id id) (set-active-tab-internal-id id)
(when (and scroll-on-press? @flat-list-ref) (when (and scroll-on-press? @flat-list-ref)
(.scrollToIndex ^js @flat-list-ref (.scrollToIndex ^js @flat-list-ref
#js #js
@ -156,7 +142,8 @@
:viewPosition 0.5})) :viewPosition 0.5}))
(when on-change (when on-change
(on-change id))) (on-change id)))
[set-active-tab-id scroll-on-press? on-change])] [set-active-tab-internal-id scroll-on-press?
on-change])]
(if scrollable? (if scrollable?
[rn/view {:style {:margin-top (- (dec unread-count-offset))}} [rn/view {:style {:margin-top (- (dec unread-count-offset))}}
[masked-view-wrapper [masked-view-wrapper
@ -183,7 +170,7 @@
:on-scroll on-scroll :on-scroll on-scroll
:on-layout set-initial-scroll-poisition :on-layout set-initial-scroll-poisition
:render-fn tab-view :render-fn tab-view
:render-data {:active-tab-id active-tab-id :render-data {:active-tab-id tab-id
:blur? blur? :blur? blur?
:customization-color customization-color :customization-color customization-color
:number-of-items (count tabs-data) :number-of-items (count tabs-data)
@ -194,7 +181,7 @@
(map-indexed (fn [index item] (map-indexed (fn [index item]
^{:key (:id item)} ^{:key (:id item)}
[tab-view item index nil [tab-view item index nil
{:active-tab-id active-tab-id {:active-tab-id tab-id
:blur? blur? :blur? blur?
:customization-color customization-color :customization-color customization-color
:number-of-items (count tabs-data) :number-of-items (count tabs-data)
@ -202,3 +189,5 @@
:on-press on-tab-press :on-press on-tab-press
:style style}]) :style style}])
tabs-data)]))) tabs-data)])))
(def view (schema/instrument #'view-internal component-schema/?schema))

View File

@ -59,26 +59,36 @@
:height 32 :height 32
:margin-top 8}) :margin-top 8})
(def content-container (def container
{:margin-left 8}) {:flex-direction :row
:column-gap 8})
(def content-line (def content-line
{:flex-direction :row {:flex-direction :row
:margin-top 2 :margin-top 2
:align-items :center}) :align-items :center})
(defn icon-hole-view (def icon-hole-view
[theme blur?]
{:width 32 {:width 32
:height 32 :height 32
:border-width 1
:border-color (if-not blur?
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
colors/white-opa-5)
:border-radius 16
:align-items :center :align-items :center
:justify-content :center}) :justify-content :center})
(defn icon-circle-border
[theme blur?]
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0
:width 32
:height 32
:border-width 1
:border-radius 16
:border-color (if-not blur?
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
colors/white-opa-5)})
(defn icon-color (defn icon-color
[theme] [theme]
(colors/theme-colors colors/neutral-100 colors/white theme)) (colors/theme-colors colors/neutral-100 colors/white theme))

View File

@ -70,20 +70,21 @@
status :pending}} status :pending}}
theme] theme]
[rn/view {:style style/icon-container} [rn/view {:style style/icon-container}
[rn/view {:style style/icon-status-container}
[icon/icon (status-icon status)
{:size 12
:no-color :true}]]
[hole-view/hole-view [hole-view/hole-view
{:style (style/icon-hole-view theme blur?) {:style style/icon-hole-view
:holes [{:x 20 :holes [{:x 20
:y 20 :y 20
:right 0 :right 0
:width 12 :width 12
:height 12 :height 12
:borderRadius 6}]} :borderRadius 6}]}
[icon/icon (transaction-icon transaction) [icon/icon (transaction-icon transaction :i/placeholder)
{:color (style/icon-color theme)}]] {:color (style/icon-color theme)}]
[rn/view {:style style/icon-status-container} [rn/view {:style (style/icon-circle-border theme blur?)}]]])
[icon/icon (status-icon status)
{:size 12
:no-color :true}]]])
(defn prop-text (defn prop-text
[label theme] [label theme]
@ -116,11 +117,9 @@
:on-press on-press :on-press on-press
:on-press-in on-press-in :on-press-in on-press-in
:on-press-out on-press-out} :on-press-out on-press-out}
[rn/view [rn/view {:style style/container}
{:style {:flex-direction :row}}
[transaction-icon-view props theme] [transaction-icon-view props theme]
[rn/view [rn/view
{:style style/content-container}
[transaction-header props theme] [transaction-header props theme]
[rn/view {:style style/content-line} [rn/view {:style style/content-line}
(when first-tag [prop-tag first-tag blur?]) (when first-tag [prop-tag first-tag blur?])

View File

@ -41,13 +41,13 @@
[message] [message]
(let [cause (if platform/android? (let [cause (if platform/android?
(condp = message (condp = message
android-not-enrolled-error-message :biometrics/not-enrolled-error android-not-enrolled-error-message :biometrics/fingerprints-not-enrolled-error
android-not-available-error-message :biometrics/not-available-error android-not-available-error-message :biometrics/not-available-error
android-too-many-attempts-error-message :biometric/too-many-attempts android-too-many-attempts-error-message :biometric/too-many-attempts
:biometrics/unknown-error) :biometrics/unknown-error)
(condp #(string/includes? %2 %1) message (condp #(string/includes? %2 %1) message
ios-not-enrolled-error-message :biometrics/not-enrolled-error ios-not-enrolled-error-message :biometrics/ios-not-enrolled-error
:biometrics/unknown-error))] :biometrics/unknown-error))]
(ex-info "Failed to authenticate with biometrics" (ex-info "Failed to authenticate with biometrics"
{:orig-error-message message} {:orig-error-message message}

View File

@ -14,8 +14,11 @@
(defn show-message (defn show-message
[_ [code]] [_ [code]]
(let [content (case code (let [content (case code
(:biometrics/not-enrolled-error (:biometrics/fingerprints-not-enrolled-error
:biometrics/not-available-error) :biometrics/not-available-error)
(i18n/label :t/grant-fingerprints-permissions)
:biometrics/ios-not-enrolled-error
(i18n/label :t/grant-face-id-permissions) (i18n/label :t/grant-face-id-permissions)
:biometric/too-many-attempts :biometric/too-many-attempts

View File

@ -18,7 +18,7 @@
(let [cofx {:db {}} (let [cofx {:db {}}
expected {:fx [[:effects.utils/show-popup expected {:fx [[:effects.utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title) {:title (i18n/label :t/biometric-auth-login-error-title)
:content (i18n/label :t/grant-face-id-permissions)}]]}] :content (i18n/label :t/grant-fingerprints-permissions)}]]}]
(is (match? expected (is (match? expected
(sut/show-message cofx (sut/show-message cofx
[:biometrics/not-available-error]))))) [:biometrics/not-available-error])))))

View File

@ -2,6 +2,7 @@
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[legacy.status-im.ethereum.mnemonic :as mnemonic] [legacy.status-im.ethereum.mnemonic :as mnemonic]
[oops.core :as oops]
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
@ -96,35 +97,36 @@
(defn recovery-phrase-screen (defn recovery-phrase-screen
[{:keys [keypair title recovering-keypair? render-controls]}] [{:keys [keypair title recovering-keypair? render-controls]}]
(reagent/with-let [keyboard-shown? (reagent/atom false) (reagent/with-let [keyboard-shown? (reagent/atom false)
keyboard-show-listener (.addListener rn/keyboard keyboard-show-listener (.addListener rn/keyboard
"keyboardDidShow" "keyboardDidShow"
#(reset! keyboard-shown? true)) #(reset! keyboard-shown? true))
keyboard-hide-listener (.addListener rn/keyboard keyboard-hide-listener (.addListener rn/keyboard
"keyboardDidHide" "keyboardDidHide"
#(reset! keyboard-shown? false)) #(reset! keyboard-shown? false))
invalid-seed-phrase? (reagent/atom false) invalid-seed-phrase? (reagent/atom false)
input-ref (reagent/atom nil) incorrect-seed-phrase? (reagent/atom false)
focus-input (fn [] input-ref (reagent/atom nil)
(let [ref @input-ref] focus-input #(some-> @input-ref
(when ref (oops/ocall "focus"))
(.focus ref)))) set-incorrect-seed-phrase #(reset! incorrect-seed-phrase? true)
set-invalid-seed-phrase #(reset! invalid-seed-phrase? true) set-invalid-seed-phrase #(reset! invalid-seed-phrase? true)
seed-phrase (reagent/atom "") seed-phrase (reagent/atom "")
on-change-seed-phrase (fn [new-phrase] on-change-seed-phrase (fn [new-phrase]
(when @invalid-seed-phrase? (when @invalid-seed-phrase?
(reset! invalid-seed-phrase? false)) (reset! invalid-seed-phrase? false)
(reset! seed-phrase new-phrase)) (reset! incorrect-seed-phrase? false))
on-submit (fn [] (reset! seed-phrase new-phrase))
(swap! seed-phrase clean-seed-phrase) on-submit (fn []
(if recovering-keypair? (swap! seed-phrase clean-seed-phrase)
(rf/dispatch [:wallet/seed-phrase-entered (if recovering-keypair?
(security/mask-data (rf/dispatch [:wallet/seed-phrase-entered
@seed-phrase) (security/mask-data
set-invalid-seed-phrase]) @seed-phrase)
(rf/dispatch [:onboarding/seed-phrase-entered set-invalid-seed-phrase])
(security/mask-data @seed-phrase) (rf/dispatch [:onboarding/seed-phrase-entered
set-invalid-seed-phrase])))] (security/mask-data @seed-phrase)
set-invalid-seed-phrase])))]
(let [words-coll (mnemonic/passphrase->words @seed-phrase) (let [words-coll (mnemonic/passphrase->words @seed-phrase)
last-word (peek words-coll) last-word (peek words-coll)
pick-suggested-word (fn [pressed-word] pick-suggested-word (fn [pressed-word]
@ -143,16 +145,18 @@
suggestions-state (cond suggestions-state (cond
(or error-in-words? (or error-in-words?
words-exceeded? words-exceeded?
@invalid-seed-phrase?) :error @invalid-seed-phrase?
@incorrect-seed-phrase?) :error
(string/blank? @seed-phrase) :info (string/blank? @seed-phrase) :info
(string/ends-with? @seed-phrase " ") :empty (string/ends-with? @seed-phrase " ") :empty
:else :words) :else :words)
suggestions-text (cond suggestions-text (cond
upper-case? (i18n/label :t/seed-phrase-words-uppercase) upper-case? (i18n/label :t/seed-phrase-words-uppercase)
words-exceeded? (i18n/label :t/seed-phrase-words-exceeded) words-exceeded? (i18n/label :t/seed-phrase-words-exceeded)
error-in-words? (i18n/label :t/seed-phrase-error) error-in-words? (i18n/label :t/seed-phrase-error)
@invalid-seed-phrase? (i18n/label :t/seed-phrase-invalid) @invalid-seed-phrase? (i18n/label :t/seed-phrase-invalid)
:else (i18n/label :t/seed-phrase-info)) @incorrect-seed-phrase? (i18n/label :t/seed-phrase-incorrect)
:else (i18n/label :t/seed-phrase-info))
error-state? (= suggestions-state :error) error-state? (= suggestions-state :error)
button-disabled? (or error-state? button-disabled? (or error-state?
(not (constants/seed-phrase-valid-length word-count)) (not (constants/seed-phrase-valid-length word-count))
@ -166,13 +170,13 @@
:word-count word-count :word-count word-count
:ref #(reset! input-ref %)} :ref #(reset! input-ref %)}
(if (fn? render-controls) (if (fn? render-controls)
(render-controls {:submit-disabled? button-disabled? (render-controls {:submit-disabled? button-disabled?
:keyboard-shown? @keyboard-shown? :keyboard-shown? @keyboard-shown?
:container-style (style/continue-button @keyboard-shown?) :container-style (style/continue-button @keyboard-shown?)
:prepare-seed-phrase secure-clean-seed-phrase :prepare-seed-phrase secure-clean-seed-phrase
:focus-input focus-input :focus-input focus-input
:seed-phrase (security/mask-data @seed-phrase) :seed-phrase (security/mask-data @seed-phrase)
:set-invalid-seed-phrase set-invalid-seed-phrase}) :set-incorrect-seed-phrase set-incorrect-seed-phrase})
[quo/button [quo/button
{:container-style (style/continue-button @keyboard-shown?) {:container-style (style/continue-button @keyboard-shown?)
:type :primary :type :primary

View File

@ -12,7 +12,7 @@
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn edit-message (defn edit-message
[{:keys [text-value input-ref]}] [{:keys [text-value input-ref input-height]}]
(let [theme (quo.theme/use-theme)] (let [theme (quo.theme/use-theme)]
[rn/view [rn/view
{:style style/container {:style style/container
@ -32,7 +32,7 @@
{:size 24 {:size 24
:icon-only? true :icon-only? true
:accessibility-label :edit-cancel-button :accessibility-label :edit-cancel-button
:on-press #(utils/cancel-edit-message text-value input-ref) :on-press #(utils/cancel-edit-message text-value input-ref input-height)
:type :outline} :type :outline}
:i/close]])) :i/close]]))

View File

@ -101,12 +101,16 @@
(rf/dispatch [:chat.ui/cancel-message-reply])) (rf/dispatch [:chat.ui/cancel-message-reply]))
(defn cancel-edit-message (defn cancel-edit-message
[text-value input-ref] [text-value input-ref input-height]
(reset! text-value "") (reset! text-value "")
;; NOTE: adding a timeout to assure the input is blurred on the next tick ;; 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 ;; after the `text-value` was cleared. Otherwise the height will be calculated
;; with the old `text-value`, leading to wrong composer height after blur. ;; with the old `text-value`, leading to wrong composer height after blur.
(js/setTimeout #(blur-input input-ref) 100) (js/setTimeout
(fn []
(blur-input input-ref)
(reanimated/set-shared-value input-height constants/input-height))
100)
(.setNativeProps ^js @input-ref (clj->js {:text ""})) (.setNativeProps ^js @input-ref (clj->js {:text ""}))
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]) (rf/dispatch [:chat.ui/set-input-content-height constants/input-height])
(rf/dispatch [:chat.ui/cancel-message-edit])) (rf/dispatch [:chat.ui/cancel-message-edit]))

View File

@ -105,8 +105,9 @@
[:<> [:<>
[reply/view state (:input-ref props)] [reply/view state (:input-ref props)]
[edit/view [edit/view
{:text-value (:text-value state) {:text-value (:text-value state)
:input-ref (:input-ref props)}]] :input-height (:height animations)
:input-ref (:input-ref props)}]]
[reanimated/touchable-opacity [reanimated/touchable-opacity
{:active-opacity 1 {:active-opacity 1
:on-press (fn [] :on-press (fn []

View File

@ -102,18 +102,43 @@
;; https://github.com/status-im/status-mobile/issues/17426 ;; https://github.com/status-im/status-mobile/issues/17426
[quo/skeleton-list (skeleton-list-props :messages parent-height platform/ios?)]])) [quo/skeleton-list (skeleton-list-props :messages parent-height platform/ios?)]]))
(defn header-height
[{:keys [insets able-to-send-message? images reply edit link-previews? input-content-height]}]
(if able-to-send-message?
(cond-> composer.constants/composer-default-height
(ff/enabled? ::ff/shell.jump-to)
(+ jump-to.constants/floating-shell-button-height)
(seq images)
(+ composer.constants/images-container-height)
reply
(+ composer.constants/reply-container-height)
edit
(+ composer.constants/edit-container-height)
link-previews?
(+ composer.constants/links-container-height)
(and input-content-height (not= input-content-height composer.constants/input-height))
(+ composer.constants/input-height)
true
(+ (:bottom insets)))
(- 70 (:bottom insets))))
(defn list-header (defn list-header
[insets able-to-send-message?] [insets able-to-send-message?]
(let [images (rf/sub [:chats/sending-image]) (let [header-data {:insets insets
height (if able-to-send-message? :able-to-send-message? able-to-send-message?
(+ composer.constants/composer-default-height :input-content-height (:input-content-height (rf/sub [:chats/current-chat-input]))
(if (ff/enabled? ::ff/shell.jump-to) :images (rf/sub [:chats/sending-image])
jump-to.constants/floating-shell-button-height :reply (rf/sub [:chats/reply-message])
0) :edit (rf/sub [:chats/edit-message])
(if (seq images) composer.constants/images-container-height 0) :link-previews? (or (rf/sub [:chats/link-previews?])
(:bottom insets)) (rf/sub [:chats/status-link-previews?]))}]
(- 70 (:bottom insets)))] [rn/view {:style {:height (header-height header-data)}}]))
[rn/view {:style {:height height}}]))
(defn list-footer-avatar (defn list-footer-avatar
[{:keys [distance-from-list-top display-name online? profile-picture theme group-chat color [{:keys [distance-from-list-top display-name online? profile-picture theme group-chat color

View File

@ -4,7 +4,6 @@
[react-native.core :as rn] [react-native.core :as rn]
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.validation.profile :as profile-validator] [status-im.common.validation.profile :as profile-validator]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.profile.edit.bio.style :as style] [status-im.contexts.profile.edit.bio.style :as style]
@ -14,63 +13,63 @@
(defn view (defn view
[] []
(let [insets (safe-area/get-insets) (let [insets (safe-area/get-insets)
profile (rf/sub [:profile/profile-with-image]) profile (rf/sub [:profile/profile-with-image])
customization-color (rf/sub [:profile/customization-color]) customization-color (rf/sub [:profile/customization-color])
alert-banners-top-margin (rf/sub [:alert-banners/top-margin]) alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
profile-bio (:bio profile) current-bio (:bio profile)
unsaved-bio (reagent/atom profile-bio) [bio set-bio] (rn/use-state current-bio)
error-msg (reagent/atom nil) [error-msg set-error-msg] (rn/use-state nil)
typing? (reagent/atom false) [typing? set-typing] (rn/use-state false)
validate-bio (debounce/debounce (fn [bio] validate-bio (debounce/debounce (fn [bio]
(reset! error-msg (set-error-msg (profile-validator/validation-bio
(profile-validator/validation-bio bio)) bio))
(reset! typing? false)) (set-typing false))
300) 300)
on-change-text (fn [s] on-change-text (fn [s]
(reset! typing? true) (set-typing true)
(reset! unsaved-bio s) (set-bio s)
(validate-bio s))] (validate-bio s))]
(fn [] [quo/overlay
[quo/overlay {:type :shell
{:type :shell :container-style (style/page-wrapper insets)}
:container-style (style/page-wrapper insets)} [quo/page-nav
[quo/page-nav {:key :header
{:key :header :background :blur
:background :blur :icon-name :i/arrow-left
:icon-name :i/arrow-left :on-press #(rf/dispatch [:navigate-back])}]
:on-press #(rf/dispatch [:navigate-back])}] [rn/keyboard-avoiding-view
[rn/keyboard-avoiding-view {:key :content
{:key :content :keyboard-vertical-offset (if platform/ios? alert-banners-top-margin 0)
:keyboard-vertical-offset (if platform/ios? alert-banners-top-margin 0) :style style/screen-container}
:style style/screen-container} [rn/view {:style {:gap 22}}
[rn/view {:style {:gap 22}} [quo/text-combinations {:title (i18n/label :t/bio)}]
[quo/text-combinations {:title (i18n/label :t/bio)}] [quo/input
[quo/input {:blur? true
{:blur? true :multiline? true
:multiline? true :error? (not (string/blank? error-msg))
:error? (not (string/blank? @error-msg)) :container-style {:margin-bottom -11}
:container-style {:margin-bottom -11} :default-value bio
:default-value @unsaved-bio :auto-focus true
:auto-focus true :max-height 200
:char-limit constants/profile-bio-max-length :char-limit constants/profile-bio-max-length
:label (i18n/label :t/profile-bio) :label (i18n/label :t/profile-bio)
:placeholder (i18n/label :t/something-about-you) :placeholder (i18n/label :t/something-about-you)
:on-change-text on-change-text}] :on-change-text on-change-text}]
(when-not (string/blank? @error-msg) (when-not (string/blank? error-msg)
[quo/info-message [quo/info-message
{:type :error {:type :error
:size :default :size :default
:icon :i/info} :icon :i/info}
@error-msg])] error-msg])]
[rn/view {:style style/button-wrapper} [rn/view {:style style/button-wrapper}
[quo/button [quo/button
{:type :primary {:type :primary
:customization-color customization-color :customization-color customization-color
:on-press (fn [] :on-press (fn []
(rf/dispatch [:profile/edit-bio @unsaved-bio])) (rf/dispatch [:profile/edit-bio bio]))
:disabled? (boolean (or @typing? :disabled? (boolean (or typing?
(and (string/blank? profile-bio) (and (string/blank? current-bio)
(string/blank? @unsaved-bio)) (string/blank? bio))
(not (string/blank? @error-msg))))} (not (string/blank? error-msg))))}
(i18n/label :t/save-bio)]]]]))) (i18n/label :t/save-bio)]]]]))

View File

@ -195,8 +195,8 @@
profile-picture (rf/sub [:profile/login-profiles-picture key-uid]) profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
login-multiaccount (rn/use-callback #(rf/dispatch [:profile.login/login]))] login-multiaccount (rn/use-callback #(rf/dispatch [:profile.login/login]))]
[rn/keyboard-avoiding-view [rn/keyboard-avoiding-view
{:style style/login-container {:style style/login-container
:keyboardVerticalOffset (- (safe-area/get-bottom))} :keyboard-vertical-offset (- (safe-area/get-bottom))}
[rn/view {:style style/multi-profile-button-container} [rn/view {:style style/multi-profile-button-container}
(when config/quo-preview-enabled? (when config/quo-preview-enabled?
[quo/button [quo/button

View File

@ -35,7 +35,7 @@
:blur? true :blur? true
:action :arrow} :action :arrow}
{:title (i18n/label :t/wallet) {:title (i18n/label :t/wallet)
:on-press #(rf/dispatch [:navigate-to-within-stack [:screen/settings.wallet :settings]]) :on-press #(rf/dispatch [:open-modal :screen/settings.wallet])
:image-props :i/wallet :image-props :i/wallet
:image :icon :image :icon
:blur? true :blur? true

View File

@ -1,6 +1,7 @@
(ns status-im.contexts.profile.settings.screens.password.change-password.style (ns status-im.contexts.profile.settings.screens.password.change-password.style
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area])) [react-native.safe-area :as safe-area]))
(def form-container (def form-container
@ -48,7 +49,7 @@
:justify-content :space-between}) :justify-content :space-between})
(def bottom-part (def bottom-part
{:margin-bottom (- (safe-area/get-bottom) 12) {:margin-bottom (if platform/ios? (safe-area/get-bottom) 12)
:justify-content :flex-end}) :justify-content :flex-end})
(def disclaimer-container (def disclaimer-container

View File

@ -17,7 +17,7 @@
(defn view (defn view
[] []
(let [{:keys [top]} (safe-area/get-insets) (let [{:keys [top bottom]} (safe-area/get-insets)
alert-banners-top-margin (rf/sub [:alert-banners/top-margin]) alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
current-step (rf/sub [:settings/change-password-current-step])] current-step (rf/sub [:settings/change-password-current-step])]
(rn/use-unmount #(rf/dispatch [:change-password/reset])) (rn/use-unmount #(rf/dispatch [:change-password/reset]))
@ -33,8 +33,12 @@
:icon-name :i/arrow-left :icon-name :i/arrow-left
:on-press navigate-back}] :on-press navigate-back}]
[rn/keyboard-avoiding-view [rn/keyboard-avoiding-view
{:style {:flex 1} {:style {:flex 1}
:keyboardVerticalOffset (if platform/ios? alert-banners-top-margin 0)} :keyboard-vertical-offset (if platform/ios?
(-> 12
(+ alert-banners-top-margin)
(- bottom))
0)}
(condp = current-step (condp = current-step
:old-password [old-password-form/view] :old-password [old-password-form/view]
:new-password [new-password-form/view])]]])) :new-password [new-password-form/view])]]]))

View File

@ -30,18 +30,18 @@
supported? (boolean biometric-type) supported? (boolean biometric-type)
enabled? (= auth-method constants/auth-method-biometric) enabled? (= auth-method constants/auth-method-biometric)
biometric-on? (and supported? enabled?) biometric-on? (and supported? enabled?)
press-handler (if biometric-on? press-handler (when supported?
(fn [] (rf/dispatch [:biometric/disable])) (if biometric-on?
(on-press-biometric-enable label theme))] (fn [] (rf/dispatch [:biometric/disable]))
(on-press-biometric-enable label theme)))]
{:title label {:title label
:image-props icon :image-props icon
:image :icon :image :icon
:blur? true :blur? true
:action :selector :action :selector
:action-props {:disabled? (not supported?) :action-props {:on-change press-handler
:on-change press-handler
:checked? biometric-on?} :checked? biometric-on?}
:on-press (when supported? press-handler)})) :on-press press-handler}))
(defn- get-change-password-item (defn- get-change-password-item
[] []

View File

@ -167,9 +167,9 @@
(rf/reg-event-fx :wallet/verify-private-key-for-keypair verify-private-key-for-keypair) (rf/reg-event-fx :wallet/verify-private-key-for-keypair verify-private-key-for-keypair)
(defn import-keypair-by-seed-phrase (defn import-missing-keypair-by-seed-phrase
[_ [{:keys [keypair-key-uid seed-phrase password on-success on-error]}]] [_ [{:keys [keypair-key-uid seed-phrase password on-success on-error]}]]
{:fx [[:import-keypair-by-seed-phrase {:fx [[:effects.wallet/import-missing-keypair-by-seed-phrase
{:keypair-key-uid keypair-key-uid {:keypair-key-uid keypair-key-uid
:seed-phrase seed-phrase :seed-phrase seed-phrase
:password password :password password
@ -178,24 +178,26 @@
#{keypair-key-uid}]) #{keypair-key-uid}])
(rf/call-continuation on-success)) (rf/call-continuation on-success))
:on-error (fn [error] :on-error (fn [error]
(rf/dispatch [:wallet/import-keypair-by-seed-phrase-failed error]) (rf/dispatch [:wallet/import-missing-keypair-by-seed-phrase-failed error])
(log/error "failed to import missing keypair with seed phrase"
{:error error})
(rf/call-continuation on-error error))}]]}) (rf/call-continuation on-error error))}]]})
(rf/reg-event-fx :wallet/import-keypair-by-seed-phrase import-keypair-by-seed-phrase) (rf/reg-event-fx :wallet/import-missing-keypair-by-seed-phrase import-missing-keypair-by-seed-phrase)
(defn import-keypair-by-seed-phrase-failed (defn import-missing-keypair-by-seed-phrase-failed
[_ [error]] [_ [error]]
(let [error-type (-> error ex-message keyword) (let [error-type (-> error ex-message keyword)
error-data (ex-data error)] error-data (ex-data error)]
(when-not (and (= error-type :import-keypair-by-seed-phrase/import-error) (when-not (= error-type :import-missing-keypair-by-seed-phrase/import-error)
(= (:hint error-data) :incorrect-seed-phrase-for-keypair))
{:fx [[:dispatch {:fx [[:dispatch
[:toasts/upsert [:toasts/upsert
{:type :negative {:type :negative
:theme :dark :theme :dark
:text (:error error-data)}]]]}))) :text (:error error-data)}]]]})))
(rf/reg-event-fx :wallet/import-keypair-by-seed-phrase-failed import-keypair-by-seed-phrase-failed) (rf/reg-event-fx :wallet/import-missing-keypair-by-seed-phrase-failed
import-missing-keypair-by-seed-phrase-failed)
(defn import-missing-keypair-by-private-key (defn import-missing-keypair-by-private-key
[_ [{:keys [keypair-key-uid private-key password on-success on-error]}]] [_ [{:keys [keypair-key-uid private-key password on-success on-error]}]]

View File

@ -1,7 +1,7 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.actions.view (ns status-im.contexts.settings.wallet.keypairs-and-accounts.actions.view
(:require [quo.core :as quo] (:require [quo.core :as quo]
[react-native.core :as rn] [react-native.core :as rn]
[status-im.contexts.settings.wallet.keypairs-and-accounts.remove.view :as remove-key-pair] [status-im.contexts.settings.wallet.keypairs-and-accounts.remove.view :as remove-keypair]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -14,20 +14,22 @@
[(:key-uid keypair)]]) [(:key-uid keypair)]])
[keypair]) [keypair])
on-show-qr (rn/use-callback #(rf/dispatch [:open-modal on-show-qr (rn/use-callback #(rf/dispatch [:open-modal
:screen/settings.encrypted-key-pair-qr :screen/settings.encrypted-keypair-qr
keypair]) keypair])
[keypair]) [keypair])
on-remove-keypair (rn/use-callback #(rf/dispatch on-remove-keypair (rn/use-callback #(rf/dispatch
[:show-bottom-sheet [:show-bottom-sheet
{:theme :dark {:theme :dark
:content (fn [] :content (fn []
[remove-key-pair/view keypair])}]) [remove-keypair/view keypair])}])
[keypair]) [keypair])
on-rename-keypair (rn/use-callback #(rf/dispatch [:open-modal :screen/settings.rename-keypair on-rename-keypair (rn/use-callback #(rf/dispatch [:open-modal :screen/settings.rename-keypair
keypair]) keypair])
[keypair]) [keypair])
on-import-seed-phrase (rn/use-callback on-import-seed-phrase (rn/use-callback
#(rf/dispatch [:open-modal :screen/settings.import-seed-phrase keypair]) #(rf/dispatch [:open-modal
:screen/settings.missing-keypair.import-seed-phrase
keypair])
[keypair]) [keypair])
on-import-private-key (rn/use-callback on-import-private-key (rn/use-callback
#(rf/dispatch [:open-modal #(rf/dispatch [:open-modal

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.countdown.view (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.countdown.view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.style (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.style
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.safe-area :as safe-area])) [react-native.safe-area :as safe-area]))

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.view (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
@ -7,8 +7,10 @@
[status-im.common.qr-codes.view :as qr-codes] [status-im.common.qr-codes.view :as qr-codes]
[status-im.common.resources :as resources] [status-im.common.resources :as resources]
[status-im.common.standard-authentication.core :as standard-auth] [status-im.common.standard-authentication.core :as standard-auth]
[status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.countdown.view :as countdown] [status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.countdown.view
[status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.style :as style] :as countdown]
[status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.style
:as style]
[status-im.contexts.syncing.utils :as sync-utils] [status-im.contexts.syncing.utils :as sync-utils]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.import-private-key.style) (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-private-key.style)
(def form-container (def form-container
{:row-gap 8 {:row-gap 8

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.import-private-key.view (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-private-key.view
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[quo.core :as quo] [quo.core :as quo]
@ -7,7 +7,8 @@
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[status-im.common.floating-button-page.view :as floating-button-page] [status-im.common.floating-button-page.view :as floating-button-page]
[status-im.common.standard-authentication.core :as standard-auth] [status-im.common.standard-authentication.core :as standard-auth]
[status-im.contexts.settings.wallet.keypairs-and-accounts.import-private-key.style :as style] [status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-private-key.style
:as style]
[status-im.contexts.wallet.common.validation :as validation] [status-im.contexts.wallet.common.validation :as validation]
[utils.debounce :as debounce] [utils.debounce :as debounce]
[utils.i18n :as i18n] [utils.i18n :as i18n]
@ -68,8 +69,7 @@
[on-change]) [on-change])
on-import-error (rn/use-callback on-import-error (rn/use-callback
(fn [_error] (fn [_error]
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])))
(show-invalid)))
on-import-success (rn/use-callback on-import-success (rn/use-callback
(fn [] (fn []
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
@ -134,5 +134,5 @@
(case flow-state (case flow-state
:correct-private-key (i18n/label :t/correct-private-key) :correct-private-key (i18n/label :t/correct-private-key)
:invalid-private-key (i18n/label :t/invalid-private-key) :invalid-private-key (i18n/label :t/invalid-private-key)
:incorrect-private-key (i18n/label :t/incorrect-private-key {:name (:name keypair)}) :incorrect-private-key (i18n/label :t/incorrect-private-key)
nil)])]]])) nil)])]]]))

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.import-seed-phrase.view (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-seed-phrase.view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[react-native.core :as rn] [react-native.core :as rn]
@ -14,16 +14,17 @@
container-style container-style
prepare-seed-phrase prepare-seed-phrase
seed-phrase seed-phrase
set-invalid-seed-phrase set-incorrect-seed-phrase
focus-input]}] focus-input]}]
(let [keypair (rf/sub [:get-screen-params]) (let [keypair (rf/sub [:get-screen-params])
customization-color (rf/sub [:profile/customization-color]) customization-color (rf/sub [:profile/customization-color])
show-errors (rn/use-callback show-errors (rn/use-callback
#(js/setTimeout (fn [_error]
(fn [] (js/setTimeout
(focus-input) (fn []
(reagent/next-tick set-invalid-seed-phrase)) (focus-input)
600)) (reagent/next-tick set-incorrect-seed-phrase))
600)))
on-import-error (rn/use-callback on-import-error (rn/use-callback
(fn [_error] (fn [_error]
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
@ -34,7 +35,7 @@
(rf/dispatch [:navigate-back]))) (rf/dispatch [:navigate-back])))
on-auth-success (rn/use-callback on-auth-success (rn/use-callback
(fn [password] (fn [password]
(rf/dispatch [:wallet/import-keypair-by-seed-phrase (rf/dispatch [:wallet/import-missing-keypair-by-seed-phrase
{:keypair-key-uid (:key-uid keypair) {:keypair-key-uid (:key-uid keypair)
:seed-phrase (prepare-seed-phrase seed-phrase) :seed-phrase (prepare-seed-phrase seed-phrase)
:password password :password password

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.scan-qr.view (ns status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.scan-qr.view
(:require (:require
[react-native.core :as rn] [react-native.core :as rn]
[status-im.common.scan-qr-code.view :as scan-qr-code] [status-im.common.scan-qr-code.view :as scan-qr-code]

View File

@ -159,9 +159,7 @@
:ens address-or-ens :ens address-or-ens
:ens? ens-name?}]) :ens? ens-name?}])
(rf/dispatch (rf/dispatch
[:navigate-to-within-stack [:open-modal :screen/settings.save-address]))
[:screen/settings.save-address
:screen/settings.add-address-to-save]]))
[address ens-name? address-or-ens])] [address ens-name? address-or-ens])]
(rn/use-unmount #(rf/dispatch [:wallet/clear-address-to-save])) (rn/use-unmount #(rf/dispatch [:wallet/clear-address-to-save]))
[quo/overlay {:type :shell} [quo/overlay {:type :shell}

View File

@ -66,8 +66,7 @@
(defn- add-address-to-save (defn- add-address-to-save
[] []
(rf/dispatch [:navigate-to-within-stack (rf/dispatch [:open-modal :screen/settings.add-address-to-save]))
[:screen/settings.add-address-to-save :screen/settings.saved-addresses]]))
(defn view (defn view
[] []

View File

@ -8,11 +8,11 @@
(defn open-saved-addresses-settings-modal (defn open-saved-addresses-settings-modal
[] []
(rf/dispatch [:navigate-to-within-stack [:screen/settings.saved-addresses :settings]])) (rf/dispatch [:open-modal :screen/settings.saved-addresses]))
(defn open-keypairs-and-accounts-settings-modal (defn open-keypairs-and-accounts-settings-modal
[] []
(rf/dispatch [:navigate-to-within-stack [:screen/settings.keypairs-and-accounts :settings]])) (rf/dispatch [:open-modal :screen/settings.keypairs-and-accounts]))
(defn basic-settings-options (defn basic-settings-options
[] []
@ -38,7 +38,7 @@
(defn open-network-settings-modal (defn open-network-settings-modal
[] []
(rf/dispatch [:navigate-to-within-stack [:screen/settings.network-settings :settings]])) (rf/dispatch [:open-modal :screen/settings.network-settings]))
(defn advanced-settings-options (defn advanced-settings-options
[] []

View File

@ -2,7 +2,6 @@
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[react-native.core :as rn] [react-native.core :as rn]
[reagent.core :as reagent]
[status-im.contexts.wallet.account.style :as style] [status-im.contexts.wallet.account.style :as style]
[status-im.contexts.wallet.account.tabs.view :as tabs] [status-im.contexts.wallet.account.tabs.view :as tabs]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher] [status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
@ -21,57 +20,59 @@
(not watch-only?) (conj {:id :dapps :label (i18n/label :t/dapps) :accessibility-label :dapps}) (not watch-only?) (conj {:id :dapps :label (i18n/label :t/dapps) :accessibility-label :dapps})
true (conj {:id :about :label (i18n/label :t/about) :accessibility-label :about}))) true (conj {:id :about :label (i18n/label :t/about) :accessibility-label :about})))
(defn- change-tab [id] (rf/dispatch [:wallet/select-account-tab id]))
(defn view (defn view
[] []
(let [selected-tab (reagent/atom first-tab-id)] (let [selected-tab (or (rf/sub [:wallet/account-tab]) first-tab-id)
(fn [] {:keys [name color formatted-balance watch-only?
(let [{:keys [name color formatted-balance address]} (rf/sub [:wallet/current-viewing-account])
watch-only?]} (rf/sub [:wallet/current-viewing-account]) customization-color (rf/sub [:profile/customization-color])]
customization-color (rf/sub [:profile/customization-color])] (rn/use-mount
(rn/use-unmount #(rf/dispatch [:wallet/close-account-page])) #(rf/dispatch [:wallet/fetch-activities-for-current-account address]))
[rn/view {:style {:flex 1}} [rn/view {:style {:flex 1}}
[account-switcher/view [account-switcher/view
{:type :wallet-networks {:type :wallet-networks
:on-press #(rf/dispatch [:wallet/close-account-page])}] :on-press #(rf/dispatch [:wallet/close-account-page])}]
[quo/account-overview [quo/account-overview
{:container-style style/account-overview {:container-style style/account-overview
:current-value formatted-balance :current-value formatted-balance
:account-name name :account-name name
:account (if watch-only? :watched-address :default) :account (if watch-only? :watched-address :default)
:customization-color color}] :customization-color color}]
(when (ff/enabled? ::ff/wallet.graph) [quo/wallet-graph {:time-frame :empty}]) (when (ff/enabled? ::ff/wallet.graph) [quo/wallet-graph {:time-frame :empty}])
(when (not watch-only?) (when (not watch-only?)
[quo/wallet-ctas [quo/wallet-ctas
{:container-style style/cta-buttons {:container-style style/cta-buttons
:send-action (fn [] :send-action (fn []
(rf/dispatch [:wallet/clean-send-data]) (rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/wizard-navigate-forward (rf/dispatch [:wallet/wizard-navigate-forward
{:start-flow? true {:start-flow? true
:flow-id :wallet-send-flow}])) :flow-id :wallet-send-flow}]))
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address :receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
{:status :receive}]) {:status :receive}])
:buy-action #(rf/dispatch [:show-bottom-sheet :buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-token/view}]) {:content buy-token/view}])
:bridge-action (fn [] :bridge-action (fn []
(rf/dispatch [:wallet/clean-send-data]) (rf/dispatch [:wallet/clean-send-data])
(rf/dispatch [:wallet/wizard-navigate-forward (rf/dispatch [:wallet/wizard-navigate-forward
{:start-flow? true {:start-flow? true
:flow-id :wallet-bridge-flow}])) :flow-id :wallet-bridge-flow}]))
:swap-action (when (ff/enabled? ::ff/wallet.swap) :swap-action (when (ff/enabled? ::ff/wallet.swap)
#(rf/dispatch [:wallet.swap/start]))}]) #(rf/dispatch [:wallet.swap/start]))}])
[quo/tabs [quo/tabs
{:style style/tabs {:style style/tabs
:size 32 :size 32
:default-active @selected-tab :active-tab-id selected-tab
:data (tabs-data watch-only?) :data (tabs-data watch-only?)
:on-change (rn/use-callback (fn [tab] (reset! selected-tab tab))) :on-change change-tab
:scrollable? true :scrollable? true
:scroll-on-press? true}] :scroll-on-press? true}]
[tabs/view {:selected-tab @selected-tab}] [tabs/view {:selected-tab selected-tab}]
(when (ff/enabled? ::ff/shell.jump-to) (when (ff/enabled? ::ff/shell.jump-to)
[quo/floating-shell-button [quo/floating-shell-button
{:jump-to {:jump-to
{:on-press #(rf/dispatch [:shell/navigate-to-jump-to]) {:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:customization-color customization-color :customization-color customization-color
:label (i18n/label :t/jump-to)}} :label (i18n/label :t/jump-to)}}
style/shell-button])])))) style/shell-button])]))

View File

@ -7,5 +7,4 @@
:skip-step? (fn [db] (some? (get-in db [:wallet :ui :send :bridge-to-chain-id])))} :skip-step? (fn [db] (some? (get-in db [:wallet :ui :send :bridge-to-chain-id])))}
{:screen-id :screen/wallet.bridge-input-amount {:screen-id :screen/wallet.bridge-input-amount
:skip-step? (fn [db] (some? (get-in db [:wallet :ui :send :amount])))} :skip-step? (fn [db] (some? (get-in db [:wallet :ui :send :amount])))}
{:screen-id :screen/wallet.transaction-confirmation} {:screen-id :screen/wallet.transaction-confirmation}])
{:screen-id :screen/wallet.transaction-progress}])

View File

@ -49,6 +49,7 @@
:on-press #(rf/dispatch :on-press #(rf/dispatch
[:wallet/set-collectible-to-send [:wallet/set-collectible-to-send
{:collectible collectible {:collectible collectible
:start-flow? true
:current-screen :screen/wallet.collectible}])} :current-screen :screen/wallet.collectible}])}
(i18n/label :t/send)]) (i18n/label :t/send)])
[quo/button [quo/button

View File

@ -35,6 +35,7 @@
:on-press on-press :on-press on-press
:accessibility-label accessibility-label :accessibility-label accessibility-label
:networks networks :networks networks
:align-center? true
:networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}]) :networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}])
:right-side [(when (and (ff/enabled? ::ff/wallet.wallet-connect) :right-side [(when (and (ff/enabled? ::ff/wallet.wallet-connect)
(not watch-only?)) (not watch-only?))

View File

@ -0,0 +1,44 @@
(ns status-im.contexts.wallet.common.activity-tab.events
(:require [camel-snake-kebab.extras :as cske]
[utils.ethereum.chain :as chain]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
(rf/reg-event-fx
:wallet/fetch-activities-for-current-account
(fn [{:keys [db]}]
(let [address (-> db :wallet :current-viewing-account-address)
chain-ids (chain/chain-ids db)
request-id 0
filters {:period {:startTimestamp 0
:endTimestamp 0}
:types []
:statuses []
:counterpartyAddresses []
:assets []
:collectibles []
:filterOutAssets false
:filterOutCollectibles false}
offset 0
limit 35
request-params [request-id [address] chain-ids filters offset limit]]
{:fx [[:json-rpc/call
[{;; This method is deprecated and will be replaced by
;; "wallet_startActivityFilterSession"
;; https://github.com/status-im/status-mobile/issues/19864
:method "wallet_filterActivityAsync"
:params request-params
:on-error [:wallet/log-rpc-error
{:event :wallet/fetch-activities-for-current-account
:params request-params}]}]]]})))
(rf/reg-event-fx
:wallet/activity-filtering-for-current-account-done
(fn [{:keys [db]} [{:keys [message]}]]
(let [address (-> db :wallet :current-viewing-account-address)
activities (->> message
(transforms/json->clj)
(:activities)
(cske/transform-keys transforms/->kebab-case-keyword))
sorted-activities (sort :timestamp activities)]
{:db (assoc-in db [:wallet :activities address] sorted-activities)})))

View File

@ -1,61 +1,42 @@
(ns status-im.contexts.wallet.common.activity-tab.view (ns status-im.contexts.wallet.common.activity-tab.view
(:require (:require
[legacy.status-im.utils.hex :as utils.hex]
[native-module.core :as native-module]
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme] [quo.theme]
[react-native.core :as rn] [react-native.core :as rn]
[status-im.common.resources :as resources] [status-im.common.resources :as resources]
[status-im.contexts.shell.jump-to.constants :as jump-to.constants] [status-im.contexts.shell.jump-to.constants :as jump-to.constants]
[status-im.contexts.wallet.common.activity-tab.constants :as constants]
[status-im.contexts.wallet.common.empty-tab.view :as empty-tab] [status-im.contexts.wallet.common.empty-tab.view :as empty-tab]
[utils.datetime :as datetime]
[utils.ethereum.chain :as chain]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.money :as money]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(def precision 6) (defn send-and-receive-activity
[{:keys [transaction relative-date status sender recipient token amount network-name
network-logo]}]
[quo/wallet-activity
{:transaction transaction
:timestamp relative-date
:status status
:counter 1
:first-tag {:size 24
:type :token
:token token
:amount amount}
:second-tag-prefix :t/from
:second-tag {:type :address :address sender}
:third-tag-prefix :t/to
:third-tag {:type :address :address recipient}
:fourth-tag-prefix :t/via
:fourth-tag {:size 24
:type :network
:network-name network-name
:network-logo network-logo}
:blur? false}])
(defn activity-item (defn activity-item
[{:keys [activity-type activity-status timestamp symbol-out symbol-in token-in token-out amount-in [{:keys [transaction] :as activity}]
amount-out sender recipient]}] (case transaction
(let [chain-id (or (:chain-id token-in) (:chain-id token-out)) (:send :receive) [send-and-receive-activity activity]
amount-in-units (native-module/hex-to-number nil))
(utils.hex/normalize-hex amount-in))
amount-in-value (str (money/with-precision
(money/wei->ether amount-in-units)
precision))
amount-out-units (native-module/hex-to-number
(utils.hex/normalize-hex amount-out))
amount-out-value (str (money/with-precision
(money/wei->ether amount-out-units)
precision))
relative-date (datetime/timestamp->relative (* timestamp 1000))
receiving-activity? (= activity-type constants/wallet-activity-type-receive)]
[quo/wallet-activity
{:transaction (constants/wallet-activity-id->name activity-type)
:timestamp relative-date
:status (constants/wallet-activity-status->name activity-status)
:counter 1
:first-tag {:size 24
:type :token
:token (or symbol-out symbol-in)
:amount (if receiving-activity? amount-in-value amount-out-value)}
:second-tag-prefix (constants/second-tag-prefix activity-type)
:second-tag {:type :address
:address (if receiving-activity? recipient sender)}
:third-tag-prefix (constants/third-tag-prefix activity-type)
:third-tag {:type :address
:address (if receiving-activity? sender recipient)}
:fourth-tag-prefix (constants/fourth-tag-prefix activity-type)
:fourth-tag {:size 24
:type :network
:network-logo (quo.resources/get-network (chain/chain-id->chain-keyword
chain-id))
:network-name (chain/chain-id->chain-name chain-id)}
:blur? false}]))
(defn view (defn view
[] []
@ -69,7 +50,8 @@
[rn/section-list [rn/section-list
{:sections activity-list {:sections activity-list
:sticky-section-headers-enabled false :sticky-section-headers-enabled false
:style {:flex 1} :style {:flex 1
:padding-horizontal 8}
:content-container-style {:padding-bottom jump-to.constants/floating-shell-button-height} :content-container-style {:padding-bottom jump-to.constants/floating-shell-button-height}
:render-fn activity-item :render-fn activity-item
:render-section-header-fn (fn [{:keys [title]}] [quo/divider-date title])}]))) :render-section-header-fn (fn [{:keys [title]}] [quo/divider-date title])}])))

View File

@ -72,8 +72,10 @@
selected-account? (rf/sub [:wallet/current-viewing-account-address]) selected-account? (rf/sub [:wallet/current-viewing-account-address])
send-params (if selected-account? send-params (if selected-account?
{:token token-data {:token token-data
:stack-id :screen/wallet.accounts
:start-flow? true} :start-flow? true}
{:token-symbol token-symbol {:token-symbol token-symbol
:stack-id :wallet-stack
:start-flow? true})] :start-flow? true})]
[quo/action-drawer [quo/action-drawer
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens) [(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)

View File

@ -79,7 +79,7 @@
:on-success (fn [value] :on-success (fn [value]
(resolver {:value value}))})))) (resolver {:value value}))}))))
(defn import-keypair-by-seed-phrase (defn import-missing-keypair-by-seed-phrase
[keypair-key-uid seed-phrase password] [keypair-key-uid seed-phrase password]
(-> (validate-mnemonic seed-phrase) (-> (validate-mnemonic seed-phrase)
(promesa/then (promesa/then
@ -87,20 +87,20 @@
(if (not= keypair-key-uid key-uid) (if (not= keypair-key-uid key-uid)
(promesa/rejected (promesa/rejected
(ex-info (ex-info
(error-message :import-keypair-by-seed-phrase/import-error) (error-message :import-missing-keypair-by-seed-phrase/import-error)
{:hint :incorrect-seed-phrase-for-keypair})) {:hint :incorrect-seed-phrase-for-keypair}))
(make-seed-phrase-fully-operable seed-phrase password)))) (make-seed-phrase-fully-operable seed-phrase password))))
(promesa/catch (promesa/catch
(fn [error] (fn [error]
(promesa/rejected (promesa/rejected
(ex-info (ex-info
(error-message :import-keypair-by-seed-phrase/import-error) (error-message :import-missing-keypair-by-seed-phrase/import-error)
(ex-data error))))))) (ex-data error)))))))
(rf/reg-fx (rf/reg-fx
:import-keypair-by-seed-phrase :effects.wallet/import-missing-keypair-by-seed-phrase
(fn [{:keys [keypair-key-uid seed-phrase password on-success on-error]}] (fn [{:keys [keypair-key-uid seed-phrase password on-success on-error]}]
(-> (import-keypair-by-seed-phrase keypair-key-uid seed-phrase password) (-> (import-missing-keypair-by-seed-phrase keypair-key-uid seed-phrase password)
(promesa/then (partial rf/call-continuation on-success)) (promesa/then (partial rf/call-continuation on-success))
(promesa/catch (partial rf/call-continuation on-error))))) (promesa/catch (partial rf/call-continuation on-error)))))

View File

@ -6,6 +6,7 @@
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.settings.wallet.effects] [status-im.contexts.settings.wallet.effects]
[status-im.contexts.settings.wallet.events] [status-im.contexts.settings.wallet.events]
[status-im.contexts.wallet.common.activity-tab.events]
[status-im.contexts.wallet.common.utils.external-links :as external-links] [status-im.contexts.wallet.common.utils.external-links :as external-links]
[status-im.contexts.wallet.common.utils.networks :as network-utils] [status-im.contexts.wallet.common.utils.networks :as network-utils]
[status-im.contexts.wallet.data-store :as data-store] [status-im.contexts.wallet.data-store :as data-store]
@ -35,6 +36,12 @@
(fn [{:keys [db]} [address]] (fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :current-viewing-account-address] address) {:db (assoc-in db [:wallet :current-viewing-account-address] address)
:fx [[:dispatch [:navigate-to :screen/wallet.accounts address]] :fx [[:dispatch [:navigate-to :screen/wallet.accounts address]]
[:dispatch [:wallet/fetch-activities-for-current-account]]]}))
(rf/reg-event-fx :wallet/navigate-to-account-within-stack
(fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack] address]]
[:dispatch [:wallet/fetch-activities]]]})) [:dispatch [:wallet/fetch-activities]]]}))
(rf/reg-event-fx :wallet/navigate-to-new-account (rf/reg-event-fx :wallet/navigate-to-new-account
@ -44,6 +51,14 @@
[:dispatch [:navigate-to :screen/wallet.accounts address]] [:dispatch [:navigate-to :screen/wallet.accounts address]]
[:dispatch [:wallet/show-account-created-toast address]]]})) [:dispatch [:wallet/show-account-created-toast address]]]}))
(rf/reg-event-fx :wallet/select-account-tab
(fn [{:keys [db]} [tab]]
{:db (assoc-in db [:wallet :ui :account-page :active-tab] tab)}))
(rf/reg-event-fx :wallet/clear-account-tab
(fn [{:keys [db]}]
{:db (assoc-in db [:wallet :ui :account-page :active-tab] nil)}))
(rf/reg-event-fx :wallet/switch-current-viewing-account (rf/reg-event-fx :wallet/switch-current-viewing-account
(fn [{:keys [db]} [address]] (fn [{:keys [db]} [address]]
{:db (assoc-in db [:wallet :current-viewing-account-address] address)})) {:db (assoc-in db [:wallet :current-viewing-account-address] address)}))
@ -55,6 +70,7 @@
(rf/reg-event-fx :wallet/close-account-page (rf/reg-event-fx :wallet/close-account-page
(fn [_] (fn [_]
{:fx [[:dispatch [:wallet/clean-current-viewing-account]] {:fx [[:dispatch [:wallet/clean-current-viewing-account]]
[:dispatch [:wallet/clear-account-tab]]
[:dispatch [:pop-to-root :shell-stack]]]})) [:dispatch [:pop-to-root :shell-stack]]]}))
(defn log-rpc-error (defn log-rpc-error
@ -491,49 +507,6 @@
(rf/reg-event-fx :wallet/update-selected-networks update-selected-networks) (rf/reg-event-fx :wallet/update-selected-networks update-selected-networks)
(rf/reg-event-fx
:wallet/fetch-activities
(fn [{:keys [db]}]
(let [addresses (->> (get-in db [:wallet :accounts])
vals
(map :address))
chain-ids (chain/chain-ids db)
request-id 0
filters {:period {:startTimestamp 0
:endTimestamp 0}
:types []
:statuses []
:counterpartyAddresses []
:assets []
:collectibles []
:filterOutAssets false
:filterOutCollectibles false}
offset 0
limit 20
request-params [request-id
addresses
chain-ids
filters
offset
limit]]
{:fx [[:json-rpc/call
[{;; This method is deprecated and will be replaced by
;; "wallet_startActivityFilterSession"
;; https://github.com/status-im/status-mobile/issues/19864
:method "wallet_filterActivityAsync"
:params request-params
:on-error [:wallet/log-rpc-error
{:event :wallet/fetch-activities
:params request-params}]}]]]})))
(rf/reg-event-fx
:wallet/activity-filtering-done
(fn [{:keys [db]} [{:keys [message]}]]
(let [{:keys [activities]} (transforms/json->clj message)
activities (cske/transform-keys transforms/->kebab-case-keyword activities)
sorted-activities (sort :timestamp activities)]
{:db (assoc-in db [:wallet :activities] sorted-activities)})))
(rf/reg-event-fx (rf/reg-event-fx
:wallet/get-crypto-on-ramps-success :wallet/get-crypto-on-ramps-success
(fn [{:keys [db]} [data]] (fn [{:keys [db]} [data]]

View File

@ -253,7 +253,7 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet/set-collectible-to-send :wallet/set-collectible-to-send
(fn [{db :db} [{:keys [collectible current-screen]}]] (fn [{db :db} [{:keys [collectible current-screen start-flow?]}]]
(let [collection-data (:collection-data collectible) (let [collection-data (:collection-data collectible)
collectible-data (:collectible-data collectible) collectible-data (:collectible-data collectible)
contract-type (:contract-type collectible) contract-type (:contract-type collectible)
@ -282,6 +282,7 @@
[:dispatch [:dispatch
[:wallet/wizard-navigate-forward [:wallet/wizard-navigate-forward
{:current-screen current-screen {:current-screen current-screen
:start-flow? start-flow?
:flow-id :wallet-send-flow}]]]}))) :flow-id :wallet-send-flow}]]]})))
(rf/reg-event-fx (rf/reg-event-fx
@ -447,18 +448,26 @@
(assoc-in [:wallet :transactions] transaction-details) (assoc-in [:wallet :transactions] transaction-details)
(assoc-in [:wallet :ui :send :transaction-ids] transaction-ids)) (assoc-in [:wallet :ui :send :transaction-ids] transaction-ids))
:fx [[:dispatch :fx [[:dispatch
[:wallet/wizard-navigate-forward [:wallet/end-transaction-flow]]]})))
{:current-screen :screen/wallet.transaction-confirmation
:flow-id :wallet-send-flow}]]]})))
(rf/reg-event-fx :wallet/close-transaction-progress-page (rf/reg-event-fx :wallet/clean-up-transaction-flow
(fn [_] (fn [_]
{:fx [[:dispatch [:wallet/clean-scanned-address]] {:fx [[:dispatch [:dismiss-modal :screen/wallet.transaction-confirmation]]
[:dispatch [:wallet/clean-scanned-address]]
[:dispatch [:wallet/clean-local-suggestions]] [:dispatch [:wallet/clean-local-suggestions]]
[:dispatch [:wallet/clean-send-address]] [:dispatch [:wallet/clean-send-address]]
[:dispatch [:wallet/clean-disabled-from-networks]] [:dispatch [:wallet/clean-disabled-from-networks]]
[:dispatch [:wallet/select-address-tab nil]] [:dispatch [:wallet/select-address-tab nil]]]}))
[:dispatch [:dismiss-modal :screen/wallet.transaction-progress]]]}))
(rf/reg-event-fx :wallet/end-transaction-flow
(fn [{:keys [db]}]
(let [address (get-in db [:wallet :current-viewing-account-address])]
{:fx [[:dispatch [:wallet/navigate-to-account-within-stack address]]
[:dispatch [:wallet/fetch-activities]]
[:dispatch [:wallet/select-account-tab :activity]]
[:dispatch-later
[{:ms 20
:dispatch [:wallet/clean-up-transaction-flow]}]]]})))
(defn- transaction-data (defn- transaction-data
[{:keys [from-address to-address token-address route data eth-transfer?]}] [{:keys [from-address to-address token-address route data eth-transfer?]}]

View File

@ -27,5 +27,4 @@
:skip-step? (fn [db] :skip-step? (fn [db]
(or (not (collectible-selected? db)) (or (not (collectible-selected? db))
(some? (get-in db [:wallet :ui :send :amount]))))} (some? (get-in db [:wallet :ui :send :amount]))))}
{:screen-id :screen/wallet.transaction-confirmation} {:screen-id :screen/wallet.transaction-confirmation}])
{:screen-id :screen/wallet.transaction-progress}])

View File

@ -9,7 +9,7 @@
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- on-press (defn- on-account-press
[address network-details] [address network-details]
(rf/dispatch [:wallet/select-from-account (rf/dispatch [:wallet/select-from-account
{:address address {:address address
@ -22,15 +22,19 @@
(rf/dispatch [:navigate-back])) (rf/dispatch [:navigate-back]))
(defn- render-fn (defn- render-fn
[item] [item _ _ {:keys [network-details]}]
(let [network-details (rf/sub [:wallet/network-details])] (let [transformed-address (rf/sub [:wallet/account-address (:address item)
(:network-preferences-names item)])]
[quo/account-item [quo/account-item
{:on-press #(on-press (:address item) network-details) {:on-press #(on-account-press (:address item) network-details)
:account-props item}])) :account-props (assoc item
:address transformed-address
:full-address? true)}]))
(defn view (defn view
[] []
(let [accounts (rf/sub [:wallet/accounts-with-current-asset])] (let [accounts (rf/sub [:wallet/accounts-with-current-asset])
network-details (rf/sub [:wallet/network-details])]
[floating-button-page/view [floating-button-page/view
{:footer-container-padding 0 {:footer-container-padding 0
:header [account-switcher/view :header [account-switcher/view
@ -45,5 +49,6 @@
{:style style/accounts-list {:style style/accounts-list
:content-container-style style/accounts-list-container :content-container-style style/accounts-list-container
:data accounts :data accounts
:render-data {:network-details network-details}
:render-fn render-fn :render-fn render-fn
:shows-horizontal-scroll-indicator false}]])) :shows-horizontal-scroll-indicator false}]]))

View File

@ -7,11 +7,13 @@
[react-native.core :as rn] [react-native.core :as rn]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[status-im.common.controlled-input.utils :as controlled-input] [status-im.common.controlled-input.utils :as controlled-input]
[status-im.constants :as constants]
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher] [status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
[status-im.contexts.wallet.common.asset-list.view :as asset-list] [status-im.contexts.wallet.common.asset-list.view :as asset-list]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.send.input-amount.style :as style] [status-im.contexts.wallet.send.input-amount.style :as style]
[status-im.contexts.wallet.send.routes.view :as routes] [status-im.contexts.wallet.send.routes.view :as routes]
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
[status-im.contexts.wallet.sheets.unpreferred-networks-alert.view :as unpreferred-networks-alert] [status-im.contexts.wallet.sheets.unpreferred-networks-alert.view :as unpreferred-networks-alert]
[utils.debounce :as debounce] [utils.debounce :as debounce]
[utils.i18n :as i18n] [utils.i18n :as i18n]
@ -125,6 +127,15 @@
:style {:margin-top 15}} :style {:margin-top 15}}
(i18n/label :t/no-routes-found)]]) (i18n/label :t/no-routes-found)]])
(defn- not-enough-asset
[]
[quo/alert-banner
{:action? true
:text (i18n/label :t/not-enough-assets)
:button-text (i18n/label :t/buy-eth)
:on-button-press #(rf/dispatch [:show-bottom-sheet
{:content buy-token/view}])}])
(defn view (defn view
;; crypto-decimals, limit-crypto and initial-crypto-currency? args are needed ;; crypto-decimals, limit-crypto and initial-crypto-currency? args are needed
;; for component tests only ;; for component tests only
@ -264,7 +275,25 @@
limit-insufficient? (> (controlled-input/numeric-value input-state) limit-insufficient? (> (controlled-input/numeric-value input-state)
current-limit) current-limit)
should-try-again? (and (not limit-insufficient?) no-routes-found?) should-try-again? (and (not limit-insufficient?) no-routes-found?)
current-address (rf/sub [:wallet/current-viewing-account-address])] current-address (rf/sub [:wallet/current-viewing-account-address])
owned-eth-token (rf/sub [:wallet/token-by-symbol
(string/upper-case
constants/mainnet-short-name)
enabled-from-chain-ids])
not-enough-asset? (and
(or no-routes-found? limit-insufficient?)
(not-empty sender-network-values)
(if (= token-symbol
(string/upper-case
constants/mainnet-short-name))
(= current-limit input-amount)
(money/equal-to (:total-balance
owned-eth-token)
0)))
show-no-routes? (and
(or no-routes-found? limit-insufficient?)
(not-empty sender-network-values)
(not not-enough-asset?))]
(rn/use-mount (rn/use-mount
(fn [] (fn []
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!)) (let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
@ -339,8 +368,9 @@
{:loading-routes? loading-routes? {:loading-routes? loading-routes?
:fees fee-formatted :fees fee-formatted
:amount amount-text}]) :amount amount-text}])
(when (and (or no-routes-found? limit-insufficient?) (not-empty sender-network-values)) (cond
[no-routes-found]) show-no-routes? [no-routes-found]
not-enough-asset? [not-enough-asset])
[quo/bottom-actions [quo/bottom-actions
{:actions :one-action {:actions :one-action
:button-one-label (if should-try-again? :button-one-label (if should-try-again?

View File

@ -17,15 +17,21 @@
:description (i18n/label :t/here-is-a-cat-in-a-box-instead) :description (i18n/label :t/here-is-a-cat-in-a-box-instead)
:image (resources/get-themed-image :cat-in-box theme) :image (resources/get-themed-image :cat-in-box theme)
:container-style style/empty-container-style}] :container-style style/empty-container-style}]
(into [rn/view {:style style/my-accounts-container}] [rn/view {:style style/my-accounts-container}
(map (fn [{:keys [color address] :as account}] (doall
[quo/account-item (for [{:keys [color address] :as account} other-accounts]
{:account-props (assoc account :customization-color color) ^{:key (str address)}
:on-press #(rf/dispatch [:wallet/select-send-address (let [transformed-address (rf/sub [:wallet/account-address address
{:address address (:network-preferences-names account)])]
:recipient account [quo/account-item
:stack-id :screen/wallet.select-address}])}])) {:account-props (assoc account
other-accounts)))) :customization-color color
:address transformed-address
:full-address? true)
:on-press #(rf/dispatch [:wallet/select-send-address
{:address address
:recipient account
:stack-id :screen/wallet.select-address}])}])))])))
(defn- recent-transactions (defn- recent-transactions
[theme] [theme]
@ -46,16 +52,56 @@
:stack-id :screen/wallet.select-address}])}])) :stack-id :screen/wallet.select-address}])}]))
recent-recipients)))) recent-recipients))))
(defn- saved-address
[{:keys [name address chain-short-names customization-color ens? ens]}]
(let [full-address (str chain-short-names address)
on-press-saved-address (rn/use-callback
#(rf/dispatch
[:wallet/select-send-address
{:address full-address
:recipient full-address
:stack-id :screen/wallet.select-address}])
[full-address])]
[quo/saved-address
{:user-props {:name name
:address full-address
:ens (when ens? ens)
:customization-color customization-color}
:container-style {:margin-horizontal 8}
:on-press on-press-saved-address}]))
(defn- saved-addresses
[theme]
(let [group-saved-addresses (rf/sub [:wallet/grouped-saved-addresses])
section-header (rn/use-callback
(fn [{:keys [title index]}]
[quo/divider-label
{:tight? true
:container-style (when (pos? index) {:margin-top 8})}
title]))
empty-state-component (rn/use-memo
(fn []
[quo/empty-state
{:title (i18n/label :t/no-saved-addresses)
:description (i18n/label
:t/you-like-to-type-43-characters)
:image (resources/get-themed-image :sweating-man
theme)}])
[theme])]
[rn/section-list
{:key-fn :title
:shows-vertical-scroll-indicator false
:render-section-header-fn section-header
:sections group-saved-addresses
:render-fn saved-address
:empty-component empty-state-component}]))
(defn view (defn view
[{:keys [selected-tab]}] [{:keys [selected-tab]}]
(let [theme (quo.theme/use-theme)] (let [theme (quo.theme/use-theme)]
(case selected-tab (case selected-tab
:tab/recent [recent-transactions theme] :tab/recent [recent-transactions theme]
:tab/saved [quo/empty-state :tab/saved [saved-addresses theme]
{:title (i18n/label :t/no-saved-addresses)
:description (i18n/label :t/you-like-to-type-43-characters)
:image (resources/get-themed-image :sweating-man theme)
:container-style style/empty-container-style}]
:tab/contacts [quo/empty-state :tab/contacts [quo/empty-state
{:title (i18n/label :t/no-contacts) {:title (i18n/label :t/no-contacts)
:description (i18n/label :t/no-contacts-description) :description (i18n/label :t/no-contacts-description)

View File

@ -47,7 +47,7 @@
(defn view (defn view
[] []
(let [leave-page #(rf/dispatch [:wallet/close-transaction-progress-page]) (let [leave-page #(rf/dispatch [:wallet/end-transaction-flow])
{:keys [color]} (rf/sub [:wallet/current-viewing-account])] {:keys [color]} (rf/sub [:wallet/current-viewing-account])]
(fn [] (fn []
(rn/use-effect (rn/use-effect

View File

@ -37,7 +37,8 @@
"wallet-blockchain-status-changed" {:fx [[:dispatch "wallet-blockchain-status-changed" {:fx [[:dispatch
[:wallet/blockchain-status-changed [:wallet/blockchain-status-changed
(transforms/js->clj event-js)]]]} (transforms/js->clj event-js)]]]}
"wallet-activity-filtering-done" {:fx [[:dispatch "wallet-activity-filtering-done" {:fx
[:wallet/activity-filtering-done [[:dispatch
(transforms/js->clj event-js)]]]} [:wallet/activity-filtering-for-current-account-done
(transforms/js->clj event-js)]]]}
(log/debug ::unknown-wallet-event :type event-type))))) (log/debug ::unknown-wallet-event :type event-type)))))

View File

@ -27,8 +27,8 @@
(rf/defn navigate-to-within-stack (rf/defn navigate-to-within-stack
{:events [:navigate-to-within-stack]} {:events [:navigate-to-within-stack]}
[{:keys [db]} comp-id] [{:keys [db]} comp-id screen-params]
{:db (assoc db :view-id (first comp-id)) {:db (all-screens-params db (first comp-id) screen-params)
:fx [[:navigate-to-within-stack comp-id]]}) :fx [[:navigate-to-within-stack comp-id]]})
(re-frame/reg-event-fx :open-modal (re-frame/reg-event-fx :open-modal

View File

@ -57,14 +57,15 @@
[status-im.contexts.profile.settings.screens.password.change-password.view :as change-password] [status-im.contexts.profile.settings.screens.password.change-password.view :as change-password]
[status-im.contexts.profile.settings.screens.password.view :as settings-password] [status-im.contexts.profile.settings.screens.password.view :as settings-password]
[status-im.contexts.profile.settings.view :as settings] [status-im.contexts.profile.settings.view :as settings]
[status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.view :as [status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.view
encrypted-key-pair-qr] :as encrypted-keypair-qr]
[status-im.contexts.settings.wallet.keypairs-and-accounts.import-private-key.view :as [status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-private-key.view
import-private-key] :as missing-keypairs.import-private-key]
[status-im.contexts.settings.wallet.keypairs-and-accounts.import-seed-phrase.view :as [status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-seed-phrase.view
import-seed-phrase] :as missing-keypairs.import-seed-phrase]
[status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.scan-qr.view
:as scan-keypair-qr]
[status-im.contexts.settings.wallet.keypairs-and-accounts.rename.view :as keypair-rename] [status-im.contexts.settings.wallet.keypairs-and-accounts.rename.view :as keypair-rename]
[status-im.contexts.settings.wallet.keypairs-and-accounts.scan-qr.view :as scan-keypair-qr]
[status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts] [status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts]
[status-im.contexts.settings.wallet.network-settings.view :as network-settings] [status-im.contexts.settings.wallet.network-settings.view :as network-settings]
[status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.view :as [status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.view :as
@ -535,9 +536,9 @@
:options (assoc options/dark-screen :sheet? true) :options (assoc options/dark-screen :sheet? true)
:component keypair-rename/view} :component keypair-rename/view}
{:name :screen/settings.encrypted-key-pair-qr {:name :screen/settings.encrypted-keypair-qr
:options options/transparent-screen-options :options options/transparent-screen-options
:component encrypted-key-pair-qr/view} :component encrypted-keypair-qr/view}
{:name :screen/settings.saved-addresses {:name :screen/settings.saved-addresses
:options options/transparent-modal-screen-options :options options/transparent-modal-screen-options
@ -551,13 +552,13 @@
:options options/transparent-modal-screen-options :options options/transparent-modal-screen-options
:component scan-keypair-qr/view} :component scan-keypair-qr/view}
{:name :screen/settings.import-seed-phrase {:name :screen/settings.missing-keypair.import-seed-phrase
:options options/transparent-screen-options :options options/transparent-screen-options
:component import-seed-phrase/view} :component missing-keypairs.import-seed-phrase/view}
{:name :screen/settings.missing-keypair-import-private-key {:name :screen/settings.missing-keypair-import-private-key
:options options/transparent-screen-options :options options/transparent-screen-options
:component import-private-key/view} :component missing-keypairs.import-private-key/view}
{:name :screen/settings.network-settings {:name :screen/settings.network-settings
:options options/transparent-modal-screen-options :options options/transparent-modal-screen-options

View File

@ -1,26 +1,82 @@
(ns status-im.subs.wallet.activities (ns status-im.subs.wallet.activities
(:require (:require
[legacy.status-im.utils.hex :as utils.hex]
[native-module.core :as native-module]
[quo.foundations.resources :as quo.resources]
[quo.foundations.resources]
[re-frame.core :as rf] [re-frame.core :as rf]
[status-im.contexts.wallet.common.activity-tab.constants :as constants] [status-im.contexts.wallet.common.activity-tab.constants :as constants]
[utils.datetime :as datetime])) [utils.datetime :as datetime]
[utils.money :as money]))
(def precision 6)
(rf/reg-sub (rf/reg-sub
:wallet/all-activities :wallet/all-activities
:<- [:wallet] :<- [:wallet]
:-> :activities) :-> :activities)
(rf/reg-sub :wallet/activities-for-current-viewing-account (defn- activity-amount
[amount]
(-> amount
(utils.hex/normalize-hex)
(native-module/hex-to-number)
(money/wei->ether)
(money/with-precision precision)
(str)))
(defn- process-send-activity
[{:keys [symbol-out chain-id-out amount-out]} activity chain-id->network-name]
(let [network-name (chain-id->network-name chain-id-out)]
(assoc activity
:transaction :send
:token symbol-out
:amount (activity-amount amount-out)
:network-name network-name
:network-logo (quo.resources/get-network network-name))))
(defn- process-receive-activity
[{:keys [symbol-in amount-in chain-id-in]} activity chain-id->network-name]
(let [network-name (chain-id->network-name chain-id-in)]
(assoc activity
:transaction :receive
:token symbol-in
:amount (activity-amount amount-in)
:network-name network-name
:network-logo (quo.resources/get-network network-name))))
(defn- process-activity-by-type
[chain-id->network-name
{:keys [activity-type activity-status timestamp sender recipient] :as data}]
(let [activity {:relative-date (datetime/timestamp->relative (* timestamp 1000))
:timestamp timestamp
:status (constants/wallet-activity-status->name activity-status)
:sender sender
:recipient recipient}]
(condp = activity-type
constants/wallet-activity-type-send
(process-send-activity data activity chain-id->network-name)
constants/wallet-activity-type-receive
(process-receive-activity data activity chain-id->network-name)
nil)))
(rf/reg-sub
:wallet/activities-for-current-viewing-account
:<- [:wallet/all-activities] :<- [:wallet/all-activities]
:<- [:wallet/current-viewing-account-address] :<- [:wallet/current-viewing-account-address]
(fn [[activities current-viewing-account-address]] :<- [:wallet/network-details]
(->> activities (fn [[activities current-viewing-account-address network-details]]
(filter (fn [{:keys [sender recipient activity-type]}] (let [chain-id->network-name (update-vals (group-by :chain-id network-details)
(let [receiving-activity? (= activity-type constants/wallet-activity-type-receive) (comp :network-name first))]
relevant-address (if receiving-activity? recipient sender)] (->> current-viewing-account-address
(= relevant-address current-viewing-account-address)))) (get activities)
(distinct) (keep #(process-activity-by-type chain-id->network-name %))
(group-by (fn [{:keys [timestamp]}] (group-by (fn [{:keys [timestamp]}]
(datetime/timestamp->relative-short-date (* timestamp 1000)))) (datetime/timestamp->relative-short-date (* timestamp 1000))))
(map (fn [[date activities]] (map (fn [[date activities]]
{:title date :data activities :timestamp (:timestamp (first activities))})) {:title date
(sort-by (fn [{:keys [timestamp]}] (- timestamp)))))) :data activities
:timestamp (:timestamp (first activities))}))
(sort-by (fn [{:keys [timestamp]}] (- timestamp)))))))

View File

@ -2,8 +2,9 @@
(:require (:require
[cljs.test :refer [is testing]] [cljs.test :refer [is testing]]
[re-frame.db :as rf-db] [re-frame.db :as rf-db]
status-im.subs.root [status-im.contexts.wallet.common.activity-tab.constants :as constants]
status-im.subs.wallet.collectibles [status-im.subs.root]
[status-im.subs.wallet.collectibles]
[test-helpers.unit :as h] [test-helpers.unit :as h]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -14,7 +15,7 @@
[:wallet :activities] [:wallet :activities]
[{:id 1 :name "Transaction1"} [{:id 1 :name "Transaction1"}
{:id 2 :name "Transaction2"}]) {:id 2 :name "Transaction2"}])
(is (= [{:id 1 :name "Transaction1"} {:id 2 :name "Transaction2"}] (rf/sub [sub-name]))))) (is (match? [{:id 1 :name "Transaction1"} {:id 2 :name "Transaction2"}] (rf/sub [sub-name])))))
(h/deftest-sub :wallet/activities-for-current-viewing-account (h/deftest-sub :wallet/activities-for-current-viewing-account
[sub-name] [sub-name]
@ -23,11 +24,62 @@
(fn [db] (fn [db]
(-> db (-> db
(assoc-in [:wallet :activities] (assoc-in [:wallet :activities]
[{:sender "acc1" :recipient "acc2" :timestamp 1588291200} {"acc1" [{:activity-type constants/wallet-activity-type-send
{:sender "acc2" :recipient "acc1" :timestamp 1588377600} :amount-out "0x1"
{:sender "acc3" :recipient "acc4" :timestamp 1588464000}]) :sender "acc1"
:recipient "acc2"
:timestamp 1588291200}
{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc2"
:recipient "acc1"
:timestamp 1588377600}
{:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc4"
:timestamp 1588464000}]
"acc3" [{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc4"
:recipient "acc3"
:timestamp 1588464000}]})
(assoc-in [:wallet :current-viewing-account-address] "acc1")))) (assoc-in [:wallet :current-viewing-account-address] "acc1"))))
(is (= [{:title "May 1, 2020" (is
:data [{:sender "acc1" :recipient "acc2" :timestamp 1588291200}] (match? [{:title "May 3, 2020"
:timestamp 1588291200}] :timestamp 1588464000
(rf/sub [sub-name]))))) :data [{:relative-date "May 3, 2020"
:amount "0"
:network-logo nil
:recipient "acc4"
:transaction :send
:token nil
:network-name nil
:status nil
:sender "acc1"
:timestamp 1588464000}]}
{:title "May 2, 2020"
:timestamp 1588377600
:data [{:relative-date "May 2, 2020"
:amount "0"
:network-logo nil
:recipient "acc1"
:transaction :receive
:token nil
:network-name nil
:status nil
:sender "acc2"
:timestamp 1588377600}]}
{:title "May 1, 2020"
:timestamp 1588291200
:data [{:relative-date "May 1, 2020"
:amount "0"
:network-logo nil
:recipient "acc2"
:transaction :send
:token nil
:network-name nil
:status nil
:sender "acc1"
:timestamp 1588291200}]}]
(rf/sub [sub-name])))))

View File

@ -1,7 +1,10 @@
(ns status-im.subs.wallet.networks (ns status-im.subs.wallet.networks
(:require [quo.foundations.resources :as resources] (:require [quo.foundations.resources :as resources]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[status-im.constants :as constants])) [status-im.constants :as constants]
[status-im.contexts.wallet.common.utils.networks :as network-utils]))
(def max-network-prefixes 2)
(re-frame/reg-sub (re-frame/reg-sub
:wallet/networks :wallet/networks
@ -88,3 +91,13 @@
(filter (filter
#(contains? selected-networks (:network-name %)) #(contains? selected-networks (:network-name %))
network-details))) network-details)))
(re-frame/reg-sub
:wallet/account-address
(fn [_ [_ address network-preferences]]
(let [short-names (map network-utils/network->short-name network-preferences)
prefix (when (<= (count short-names) max-network-prefixes)
(network-utils/short-names->network-preference-prefix
short-names))
transformed-address (str prefix address)]
transformed-address)))

View File

@ -82,3 +82,14 @@
:chain-id 10 :chain-id 10
:layer 2}} :layer 2}}
(rf/sub [sub-name]))))) (rf/sub [sub-name])))))
(h/deftest-sub :wallet/account-address
[sub-name]
(testing
"returns the address with prefixes when an address and less than 3 network preferences are passed"
(is
(match? "eth:0x01" (rf/sub [sub-name "0x01" [:ethereum]]))))
(testing
"returns the address without the prefixes when an address and equal or more than 3 network preferences are passed"
(is
(match? "0x01" (rf/sub [sub-name "0x01" [:ethereum :optimism :arbitrum]])))))

View File

@ -1,6 +1,7 @@
(ns status-im.subs.wallet.send (ns status-im.subs.wallet.send
(:require (:require
[re-frame.core :as rf] [re-frame.core :as rf]
[status-im.contexts.wallet.common.activity-tab.constants :as constants]
[utils.number])) [utils.number]))
(rf/reg-sub (rf/reg-sub
@ -40,14 +41,15 @@
(rf/reg-sub (rf/reg-sub
:wallet/recent-recipients :wallet/recent-recipients
:<- [:wallet/activities-for-current-viewing-account] :<- [:wallet/all-activities]
:<- [:wallet/current-viewing-account-address] :<- [:wallet/current-viewing-account-address]
(fn [[sections current-viewing-account-address]] (fn [[all-activities current-viewing-account-address]]
(let [all-transactions (mapcat :data sections) (let [address-activity (get all-activities current-viewing-account-address)]
users-sent-transactions (filter (fn [{:keys [sender]}] (->> address-activity
(= sender current-viewing-account-address)) (keep (fn [{:keys [activity-type recipient]}]
all-transactions)] (when (= constants/wallet-activity-type-send activity-type)
(set (map :recipient users-sent-transactions))))) recipient)))
(distinct)))))
(rf/reg-sub (rf/reg-sub
:wallet/send-token-not-supported-in-receiver-networks? :wallet/send-token-not-supported-in-receiver-networks?

View File

@ -2,8 +2,9 @@
(:require (:require
[cljs.test :refer [is testing]] [cljs.test :refer [is testing]]
[re-frame.db :as rf-db] [re-frame.db :as rf-db]
status-im.subs.root [status-im.contexts.wallet.common.activity-tab.constants :as constants]
status-im.subs.wallet.send [status-im.subs.root]
[status-im.subs.wallet.send]
[test-helpers.unit :as h] [test-helpers.unit :as h]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
@ -61,8 +62,25 @@
(fn [db] (fn [db]
(-> db (-> db
(assoc-in [:wallet :activities] (assoc-in [:wallet :activities]
[{:sender "acc1" :recipient "acc2" :timestamp 1588291200} {"acc1" [{:activity-type constants/wallet-activity-type-send
{:sender "acc2" :recipient "acc1" :timestamp 1588377600} :amount-out "0x1"
{:sender "acc3" :recipient "acc4" :timestamp 1588464000}]) :sender "acc1"
:recipient "acc2"
:timestamp 1588291200}
{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc2"
:recipient "acc1"
:timestamp 1588377600}
{:activity-type constants/wallet-activity-type-send
:amount-out "0x1"
:sender "acc1"
:recipient "acc4"
:timestamp 1588464000}]
"acc3" [{:activity-type constants/wallet-activity-type-receive
:amount-in "0x1"
:sender "acc4"
:recipient "acc3"
:timestamp 1588464000}]})
(assoc-in [:wallet :current-viewing-account-address] "acc1")))) (assoc-in [:wallet :current-viewing-account-address] "acc1"))))
(is (= #{"acc2"} (rf/sub [sub-name]))))) (is (match? ["acc2" "acc4"] (rf/sub [sub-name])))))

View File

@ -259,22 +259,22 @@
:wallet/settings-keypairs-accounts :wallet/settings-keypairs-accounts
:<- [:wallet/keypairs] :<- [:wallet/keypairs]
(fn [keypairs [_ format-options]] (fn [keypairs [_ format-options]]
(let [grouped-keypairs (group-by :lowest-operability keypairs) (let [grouped-keypairs (group-by :lowest-operability keypairs)
operable-key-pair-ids (->> (concat (:fully grouped-keypairs) operable-keypair-ids (->> (concat (:fully grouped-keypairs)
(:partially grouped-keypairs)) (:partially grouped-keypairs))
(map :key-uid) (map :key-uid)
(into #{})) (into #{}))
missing-key-pair-ids (->> (map :key-uid (:no grouped-keypairs)) missing-keypair-ids (->> (map :key-uid (:no grouped-keypairs))
(into #{}))] (into #{}))]
{:operable (->> keypairs {:operable (->> keypairs
(filter #(contains? operable-key-pair-ids (:key-uid %))) (filter #(contains? operable-keypair-ids (:key-uid %)))
(map (fn [{:keys [accounts name type key-uid]}] (map (fn [{:keys [accounts name type key-uid]}]
{:type (keyword type) {:type (keyword type)
:name name :name name
:key-uid key-uid :key-uid key-uid
:accounts (format-settings-keypair-accounts accounts format-options)}))) :accounts (format-settings-keypair-accounts accounts format-options)})))
:missing (->> keypairs :missing (->> keypairs
(filter #(contains? missing-key-pair-ids (:key-uid %))) (filter #(contains? missing-keypair-ids (:key-uid %)))
(map (fn [{:keys [accounts name type key-uid]}] (map (fn [{:keys [accounts name type key-uid]}]
{:type (keyword type) {:type (keyword type)
:name name :name name
@ -435,6 +435,12 @@
accounts) accounts)
accounts)))) accounts))))
(rf/reg-sub
:wallet/account-tab
:<- [:wallet/ui]
(fn [ui]
(get-in ui [:account-page :active-tab])))
(rf/reg-sub (rf/reg-sub
:wallet/current-viewing-account-token-values :wallet/current-viewing-account-token-values
:<- [:wallet/current-viewing-account] :<- [:wallet/current-viewing-account]

View File

@ -1587,6 +1587,7 @@
"seed-phrase-words-uppercase": "Recovery phrase cannot contain uppercase characters", "seed-phrase-words-uppercase": "Recovery phrase cannot contain uppercase characters",
"seed-phrase-error": "Recovery phrase contains invalid words", "seed-phrase-error": "Recovery phrase contains invalid words",
"seed-phrase-invalid": "Invalid recovery phrase", "seed-phrase-invalid": "Invalid recovery phrase",
"seed-phrase-incorrect": "Recovery phrase does not match key pair",
"seed-phrase-info": "Enter 12, 18 or 24 words separated by spaces", "seed-phrase-info": "Enter 12, 18 or 24 words separated by spaces",
"word-count": "Word count", "word-count": "Word count",
"word-n": "Word #{{number}}", "word-n": "Word #{{number}}",
@ -1629,6 +1630,7 @@
"ok-save-pass": "OK, save password", "ok-save-pass": "OK, save password",
"lock-app-with": "Lock app with", "lock-app-with": "Lock app with",
"grant-face-id-permissions": "To grant the required Face ID permission, please go to your system settings and make sure that Status > Face ID is selected", "grant-face-id-permissions": "To grant the required Face ID permission, please go to your system settings and make sure that Status > Face ID is selected",
"grant-fingerprints-permissions": "To grant the required fingerprints permission, please go to your system settings and make sure that Status > Fingerprints is selected",
"request-feature": "Request a feature", "request-feature": "Request a feature",
"select-account-dapp": "Select the account you wish to use with Dapps", "select-account-dapp": "Select the account you wish to use with Dapps",
"apply": "Apply", "apply": "Apply",
@ -2658,7 +2660,7 @@
"import-private-key-info": "New addresses cannot be derived from an account imported from a private key. Import using a seed phrase if you wish to derive addresses.", "import-private-key-info": "New addresses cannot be derived from an account imported from a private key. Import using a seed phrase if you wish to derive addresses.",
"invalid-private-key": "Its not a valid private key", "invalid-private-key": "Its not a valid private key",
"correct-private-key": "Correct private key", "correct-private-key": "Correct private key",
"incorrect-private-key": "This is not the private key for {{name}}", "incorrect-private-key": "This is not the private key for this key pair",
"private-key-public-address": "Public address of private key", "private-key-public-address": "Public address of private key",
"this-account-has-no-activity": "This account has no activity", "this-account-has-no-activity": "This account has no activity",
"this-address-has-activity": "This address has activity", "this-address-has-activity": "This address has activity",
@ -2699,5 +2701,7 @@
"wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported", "wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported",
"add-network-preferences": "Add network preferences", "add-network-preferences": "Add network preferences",
"saved-address-network-preference-selection-description": "Only change if you know which networks the address owner is happy to to receive funds on", "saved-address-network-preference-selection-description": "Only change if you know which networks the address owner is happy to to receive funds on",
"add-preferences": "Add preferences" "add-preferences": "Add preferences",
"buy-eth": "Buy ETH",
"not-enough-assets": "Not enough assets to pay gas fees"
} }