chore: merge branch 'develop' into status-go/filter-improvements
This commit is contained in:
commit
59896858d0
|
@ -10,7 +10,7 @@
|
|||
(reagent/as-element
|
||||
(into [react/keyboard-avoiding-view
|
||||
(update props
|
||||
:keyboardVerticalOffset
|
||||
:keyboard-vertical-offset
|
||||
+
|
||||
20
|
||||
(if (:ignore-offset props) 44 0))]
|
||||
|
|
|
@ -275,7 +275,7 @@
|
|||
(merge (when platform/ios? {:behavior :padding})
|
||||
(if (:ignore-offset props)
|
||||
props
|
||||
(update props :keyboardVerticalOffset + 44 (:status-bar-height @navigation-const))))]
|
||||
(update props :keyboard-vertical-offset + 44 (:status-bar-height @navigation-const))))]
|
||||
children))
|
||||
|
||||
(defn keyboard-avoiding-view-new
|
||||
|
@ -284,7 +284,7 @@
|
|||
(merge (when platform/ios? {:behavior :padding})
|
||||
(if (:ignore-offset props)
|
||||
props
|
||||
(update props :keyboardVerticalOffset + 44)))]
|
||||
(update props :keyboard-vertical-offset + 44)))]
|
||||
children))
|
||||
|
||||
(defn scroll-view
|
||||
|
|
|
@ -30,10 +30,7 @@
|
|||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))
|
||||
:container-style style/title-icon-container
|
||||
:accessibility-label :title-icon}])]
|
||||
[address-text/view
|
||||
{:networks (:networks account-props)
|
||||
:address (:address account-props)
|
||||
:format :short}]]])
|
||||
[address-text/view (assoc account-props :format :short)]]])
|
||||
|
||||
(defn- balance-view
|
||||
[{:keys [balance-props type theme]}]
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
:blur :grey})
|
||||
|
||||
(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}}
|
||||
& children]
|
||||
(into [rn/view {:style (style/container margin-top)}
|
||||
(when icon-name
|
||||
[rn/view {:style style/icon-container}
|
||||
[rn/view (when align-center? {:style style/icon-container})
|
||||
[button/button
|
||||
{:type (button-type background)
|
||||
:icon-only? true
|
||||
|
|
|
@ -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])
|
|
@ -2,12 +2,14 @@
|
|||
(:require
|
||||
[oops.core :refer [oget]]
|
||||
[quo.components.tabs.tab.view :as tab]
|
||||
[quo.components.tabs.tabs.schema :as component-schema]
|
||||
[quo.components.tabs.tabs.style :as style]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[react-native.masked-view :as masked-view]
|
||||
[reagent.core :as reagent]
|
||||
[schema.core :as schema]
|
||||
[utils.collection :as utils.collection]
|
||||
[utils.number]))
|
||||
|
||||
|
@ -84,36 +86,20 @@
|
|||
:on-press #(on-press % index)}
|
||||
label]])
|
||||
|
||||
(defn view
|
||||
" 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).
|
||||
"
|
||||
(defn- view-internal
|
||||
[{: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
|
||||
fade-end? false
|
||||
scrollable? false
|
||||
scroll-on-press? false
|
||||
size default-tab-size}
|
||||
:as props}]
|
||||
(let [[active-tab-id
|
||||
set-active-tab-id] (rn/use-state default-active)
|
||||
(let [[active-tab-internal-id
|
||||
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)
|
||||
flat-list-ref (rn/use-ref-atom nil)
|
||||
tabs-data (rn/use-memo (fn [] (filterv some? data))
|
||||
|
@ -143,11 +129,11 @@
|
|||
{:animated false
|
||||
:index
|
||||
(utils.collection/first-index
|
||||
#(= active-tab-id (:id %))
|
||||
#(= tab-id (:id %))
|
||||
tabs-data)}))))
|
||||
[active-tab-id tabs-data])
|
||||
[tab-id tabs-data])
|
||||
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)
|
||||
(.scrollToIndex ^js @flat-list-ref
|
||||
#js
|
||||
|
@ -156,7 +142,8 @@
|
|||
:viewPosition 0.5}))
|
||||
(when on-change
|
||||
(on-change id)))
|
||||
[set-active-tab-id scroll-on-press? on-change])]
|
||||
[set-active-tab-internal-id scroll-on-press?
|
||||
on-change])]
|
||||
(if scrollable?
|
||||
[rn/view {:style {:margin-top (- (dec unread-count-offset))}}
|
||||
[masked-view-wrapper
|
||||
|
@ -183,7 +170,7 @@
|
|||
:on-scroll on-scroll
|
||||
:on-layout set-initial-scroll-poisition
|
||||
:render-fn tab-view
|
||||
:render-data {:active-tab-id active-tab-id
|
||||
:render-data {:active-tab-id tab-id
|
||||
:blur? blur?
|
||||
:customization-color customization-color
|
||||
:number-of-items (count tabs-data)
|
||||
|
@ -194,7 +181,7 @@
|
|||
(map-indexed (fn [index item]
|
||||
^{:key (:id item)}
|
||||
[tab-view item index nil
|
||||
{:active-tab-id active-tab-id
|
||||
{:active-tab-id tab-id
|
||||
:blur? blur?
|
||||
:customization-color customization-color
|
||||
:number-of-items (count tabs-data)
|
||||
|
@ -202,3 +189,5 @@
|
|||
:on-press on-tab-press
|
||||
:style style}])
|
||||
tabs-data)])))
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
||||
|
|
|
@ -59,26 +59,36 @@
|
|||
:height 32
|
||||
:margin-top 8})
|
||||
|
||||
(def content-container
|
||||
{:margin-left 8})
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:column-gap 8})
|
||||
|
||||
(def content-line
|
||||
{:flex-direction :row
|
||||
:margin-top 2
|
||||
:align-items :center})
|
||||
|
||||
(defn icon-hole-view
|
||||
[theme blur?]
|
||||
(def icon-hole-view
|
||||
{:width 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
|
||||
: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
|
||||
[theme]
|
||||
(colors/theme-colors colors/neutral-100 colors/white theme))
|
||||
|
|
|
@ -70,20 +70,21 @@
|
|||
status :pending}}
|
||||
theme]
|
||||
[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
|
||||
{:style (style/icon-hole-view theme blur?)
|
||||
{:style style/icon-hole-view
|
||||
:holes [{:x 20
|
||||
:y 20
|
||||
:right 0
|
||||
:width 12
|
||||
:height 12
|
||||
:borderRadius 6}]}
|
||||
[icon/icon (transaction-icon transaction)
|
||||
{:color (style/icon-color theme)}]]
|
||||
[rn/view {:style style/icon-status-container}
|
||||
[icon/icon (status-icon status)
|
||||
{:size 12
|
||||
:no-color :true}]]])
|
||||
[icon/icon (transaction-icon transaction :i/placeholder)
|
||||
{:color (style/icon-color theme)}]
|
||||
[rn/view {:style (style/icon-circle-border theme blur?)}]]])
|
||||
|
||||
(defn prop-text
|
||||
[label theme]
|
||||
|
@ -116,11 +117,9 @@
|
|||
:on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out}
|
||||
[rn/view
|
||||
{:style {:flex-direction :row}}
|
||||
[rn/view {:style style/container}
|
||||
[transaction-icon-view props theme]
|
||||
[rn/view
|
||||
{:style style/content-container}
|
||||
[transaction-header props theme]
|
||||
[rn/view {:style style/content-line}
|
||||
(when first-tag [prop-tag first-tag blur?])
|
||||
|
|
|
@ -41,13 +41,13 @@
|
|||
[message]
|
||||
(let [cause (if platform/android?
|
||||
(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-too-many-attempts-error-message :biometric/too-many-attempts
|
||||
:biometrics/unknown-error)
|
||||
|
||||
(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))]
|
||||
(ex-info "Failed to authenticate with biometrics"
|
||||
{:orig-error-message message}
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
(defn show-message
|
||||
[_ [code]]
|
||||
(let [content (case code
|
||||
(:biometrics/not-enrolled-error
|
||||
(:biometrics/fingerprints-not-enrolled-error
|
||||
:biometrics/not-available-error)
|
||||
(i18n/label :t/grant-fingerprints-permissions)
|
||||
|
||||
:biometrics/ios-not-enrolled-error
|
||||
(i18n/label :t/grant-face-id-permissions)
|
||||
|
||||
:biometric/too-many-attempts
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
(let [cofx {:db {}}
|
||||
expected {:fx [[:effects.utils/show-popup
|
||||
{: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
|
||||
(sut/show-message cofx
|
||||
[:biometrics/not-available-error])))))
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.mnemonic :as mnemonic]
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
|
@ -96,35 +97,36 @@
|
|||
|
||||
(defn recovery-phrase-screen
|
||||
[{:keys [keypair title recovering-keypair? render-controls]}]
|
||||
(reagent/with-let [keyboard-shown? (reagent/atom false)
|
||||
keyboard-show-listener (.addListener rn/keyboard
|
||||
"keyboardDidShow"
|
||||
#(reset! keyboard-shown? true))
|
||||
keyboard-hide-listener (.addListener rn/keyboard
|
||||
"keyboardDidHide"
|
||||
#(reset! keyboard-shown? false))
|
||||
invalid-seed-phrase? (reagent/atom false)
|
||||
input-ref (reagent/atom nil)
|
||||
focus-input (fn []
|
||||
(let [ref @input-ref]
|
||||
(when ref
|
||||
(.focus ref))))
|
||||
set-invalid-seed-phrase #(reset! invalid-seed-phrase? true)
|
||||
seed-phrase (reagent/atom "")
|
||||
on-change-seed-phrase (fn [new-phrase]
|
||||
(when @invalid-seed-phrase?
|
||||
(reset! invalid-seed-phrase? false))
|
||||
(reset! seed-phrase new-phrase))
|
||||
on-submit (fn []
|
||||
(swap! seed-phrase clean-seed-phrase)
|
||||
(if recovering-keypair?
|
||||
(rf/dispatch [:wallet/seed-phrase-entered
|
||||
(security/mask-data
|
||||
@seed-phrase)
|
||||
set-invalid-seed-phrase])
|
||||
(rf/dispatch [:onboarding/seed-phrase-entered
|
||||
(security/mask-data @seed-phrase)
|
||||
set-invalid-seed-phrase])))]
|
||||
(reagent/with-let [keyboard-shown? (reagent/atom false)
|
||||
keyboard-show-listener (.addListener rn/keyboard
|
||||
"keyboardDidShow"
|
||||
#(reset! keyboard-shown? true))
|
||||
keyboard-hide-listener (.addListener rn/keyboard
|
||||
"keyboardDidHide"
|
||||
#(reset! keyboard-shown? false))
|
||||
invalid-seed-phrase? (reagent/atom false)
|
||||
incorrect-seed-phrase? (reagent/atom false)
|
||||
input-ref (reagent/atom nil)
|
||||
focus-input #(some-> @input-ref
|
||||
(oops/ocall "focus"))
|
||||
set-incorrect-seed-phrase #(reset! incorrect-seed-phrase? true)
|
||||
set-invalid-seed-phrase #(reset! invalid-seed-phrase? true)
|
||||
seed-phrase (reagent/atom "")
|
||||
on-change-seed-phrase (fn [new-phrase]
|
||||
(when @invalid-seed-phrase?
|
||||
(reset! invalid-seed-phrase? false)
|
||||
(reset! incorrect-seed-phrase? false))
|
||||
(reset! seed-phrase new-phrase))
|
||||
on-submit (fn []
|
||||
(swap! seed-phrase clean-seed-phrase)
|
||||
(if recovering-keypair?
|
||||
(rf/dispatch [:wallet/seed-phrase-entered
|
||||
(security/mask-data
|
||||
@seed-phrase)
|
||||
set-invalid-seed-phrase])
|
||||
(rf/dispatch [:onboarding/seed-phrase-entered
|
||||
(security/mask-data @seed-phrase)
|
||||
set-invalid-seed-phrase])))]
|
||||
(let [words-coll (mnemonic/passphrase->words @seed-phrase)
|
||||
last-word (peek words-coll)
|
||||
pick-suggested-word (fn [pressed-word]
|
||||
|
@ -143,16 +145,18 @@
|
|||
suggestions-state (cond
|
||||
(or error-in-words?
|
||||
words-exceeded?
|
||||
@invalid-seed-phrase?) :error
|
||||
@invalid-seed-phrase?
|
||||
@incorrect-seed-phrase?) :error
|
||||
(string/blank? @seed-phrase) :info
|
||||
(string/ends-with? @seed-phrase " ") :empty
|
||||
:else :words)
|
||||
suggestions-text (cond
|
||||
upper-case? (i18n/label :t/seed-phrase-words-uppercase)
|
||||
words-exceeded? (i18n/label :t/seed-phrase-words-exceeded)
|
||||
error-in-words? (i18n/label :t/seed-phrase-error)
|
||||
@invalid-seed-phrase? (i18n/label :t/seed-phrase-invalid)
|
||||
:else (i18n/label :t/seed-phrase-info))
|
||||
upper-case? (i18n/label :t/seed-phrase-words-uppercase)
|
||||
words-exceeded? (i18n/label :t/seed-phrase-words-exceeded)
|
||||
error-in-words? (i18n/label :t/seed-phrase-error)
|
||||
@invalid-seed-phrase? (i18n/label :t/seed-phrase-invalid)
|
||||
@incorrect-seed-phrase? (i18n/label :t/seed-phrase-incorrect)
|
||||
:else (i18n/label :t/seed-phrase-info))
|
||||
error-state? (= suggestions-state :error)
|
||||
button-disabled? (or error-state?
|
||||
(not (constants/seed-phrase-valid-length word-count))
|
||||
|
@ -166,13 +170,13 @@
|
|||
:word-count word-count
|
||||
:ref #(reset! input-ref %)}
|
||||
(if (fn? render-controls)
|
||||
(render-controls {:submit-disabled? button-disabled?
|
||||
:keyboard-shown? @keyboard-shown?
|
||||
:container-style (style/continue-button @keyboard-shown?)
|
||||
:prepare-seed-phrase secure-clean-seed-phrase
|
||||
:focus-input focus-input
|
||||
:seed-phrase (security/mask-data @seed-phrase)
|
||||
:set-invalid-seed-phrase set-invalid-seed-phrase})
|
||||
(render-controls {:submit-disabled? button-disabled?
|
||||
:keyboard-shown? @keyboard-shown?
|
||||
:container-style (style/continue-button @keyboard-shown?)
|
||||
:prepare-seed-phrase secure-clean-seed-phrase
|
||||
:focus-input focus-input
|
||||
:seed-phrase (security/mask-data @seed-phrase)
|
||||
:set-incorrect-seed-phrase set-incorrect-seed-phrase})
|
||||
[quo/button
|
||||
{:container-style (style/continue-button @keyboard-shown?)
|
||||
:type :primary
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn edit-message
|
||||
[{:keys [text-value input-ref]}]
|
||||
[{:keys [text-value input-ref input-height]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view
|
||||
{:style style/container
|
||||
|
@ -32,7 +32,7 @@
|
|||
{:size 24
|
||||
:icon-only? true
|
||||
: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}
|
||||
:i/close]]))
|
||||
|
||||
|
|
|
@ -101,12 +101,16 @@
|
|||
(rf/dispatch [:chat.ui/cancel-message-reply]))
|
||||
|
||||
(defn cancel-edit-message
|
||||
[text-value input-ref]
|
||||
[text-value input-ref input-height]
|
||||
(reset! text-value "")
|
||||
;; NOTE: adding a timeout to assure the input is blurred on the next tick
|
||||
;; after the `text-value` was cleared. Otherwise the height will be calculated
|
||||
;; with the old `text-value`, leading to wrong composer height after blur.
|
||||
(js/setTimeout #(blur-input input-ref) 100)
|
||||
(js/setTimeout
|
||||
(fn []
|
||||
(blur-input input-ref)
|
||||
(reanimated/set-shared-value input-height constants/input-height))
|
||||
100)
|
||||
(.setNativeProps ^js @input-ref (clj->js {:text ""}))
|
||||
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height])
|
||||
(rf/dispatch [:chat.ui/cancel-message-edit]))
|
||||
|
|
|
@ -105,8 +105,9 @@
|
|||
[:<>
|
||||
[reply/view state (:input-ref props)]
|
||||
[edit/view
|
||||
{:text-value (:text-value state)
|
||||
:input-ref (:input-ref props)}]]
|
||||
{:text-value (:text-value state)
|
||||
:input-height (:height animations)
|
||||
:input-ref (:input-ref props)}]]
|
||||
[reanimated/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
|
|
|
@ -102,18 +102,43 @@
|
|||
;; https://github.com/status-im/status-mobile/issues/17426
|
||||
[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
|
||||
[insets able-to-send-message?]
|
||||
(let [images (rf/sub [:chats/sending-image])
|
||||
height (if able-to-send-message?
|
||||
(+ composer.constants/composer-default-height
|
||||
(if (ff/enabled? ::ff/shell.jump-to)
|
||||
jump-to.constants/floating-shell-button-height
|
||||
0)
|
||||
(if (seq images) composer.constants/images-container-height 0)
|
||||
(:bottom insets))
|
||||
(- 70 (:bottom insets)))]
|
||||
[rn/view {:style {:height height}}]))
|
||||
(let [header-data {:insets insets
|
||||
:able-to-send-message? able-to-send-message?
|
||||
:input-content-height (:input-content-height (rf/sub [:chats/current-chat-input]))
|
||||
:images (rf/sub [:chats/sending-image])
|
||||
:reply (rf/sub [:chats/reply-message])
|
||||
:edit (rf/sub [:chats/edit-message])
|
||||
:link-previews? (or (rf/sub [:chats/link-previews?])
|
||||
(rf/sub [:chats/status-link-previews?]))}]
|
||||
[rn/view {:style {:height (header-height header-data)}}]))
|
||||
|
||||
(defn list-footer-avatar
|
||||
[{:keys [distance-from-list-top display-name online? profile-picture theme group-chat color
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.validation.profile :as profile-validator]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.profile.edit.bio.style :as style]
|
||||
|
@ -14,63 +13,63 @@
|
|||
|
||||
(defn view
|
||||
[]
|
||||
(let [insets (safe-area/get-insets)
|
||||
profile (rf/sub [:profile/profile-with-image])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
|
||||
profile-bio (:bio profile)
|
||||
unsaved-bio (reagent/atom profile-bio)
|
||||
error-msg (reagent/atom nil)
|
||||
typing? (reagent/atom false)
|
||||
validate-bio (debounce/debounce (fn [bio]
|
||||
(reset! error-msg
|
||||
(profile-validator/validation-bio bio))
|
||||
(reset! typing? false))
|
||||
300)
|
||||
on-change-text (fn [s]
|
||||
(reset! typing? true)
|
||||
(reset! unsaved-bio s)
|
||||
(validate-bio s))]
|
||||
(fn []
|
||||
[quo/overlay
|
||||
{:type :shell
|
||||
:container-style (style/page-wrapper insets)}
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:key :content
|
||||
:keyboard-vertical-offset (if platform/ios? alert-banners-top-margin 0)
|
||||
:style style/screen-container}
|
||||
[rn/view {:style {:gap 22}}
|
||||
[quo/text-combinations {:title (i18n/label :t/bio)}]
|
||||
[quo/input
|
||||
{:blur? true
|
||||
:multiline? true
|
||||
:error? (not (string/blank? @error-msg))
|
||||
:container-style {:margin-bottom -11}
|
||||
:default-value @unsaved-bio
|
||||
:auto-focus true
|
||||
:char-limit constants/profile-bio-max-length
|
||||
:label (i18n/label :t/profile-bio)
|
||||
:placeholder (i18n/label :t/something-about-you)
|
||||
:on-change-text on-change-text}]
|
||||
(when-not (string/blank? @error-msg)
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:size :default
|
||||
:icon :i/info}
|
||||
@error-msg])]
|
||||
[rn/view {:style style/button-wrapper}
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:profile/edit-bio @unsaved-bio]))
|
||||
:disabled? (boolean (or @typing?
|
||||
(and (string/blank? profile-bio)
|
||||
(string/blank? @unsaved-bio))
|
||||
(not (string/blank? @error-msg))))}
|
||||
(i18n/label :t/save-bio)]]]])))
|
||||
(let [insets (safe-area/get-insets)
|
||||
profile (rf/sub [:profile/profile-with-image])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
|
||||
current-bio (:bio profile)
|
||||
[bio set-bio] (rn/use-state current-bio)
|
||||
[error-msg set-error-msg] (rn/use-state nil)
|
||||
[typing? set-typing] (rn/use-state false)
|
||||
validate-bio (debounce/debounce (fn [bio]
|
||||
(set-error-msg (profile-validator/validation-bio
|
||||
bio))
|
||||
(set-typing false))
|
||||
300)
|
||||
on-change-text (fn [s]
|
||||
(set-typing true)
|
||||
(set-bio s)
|
||||
(validate-bio s))]
|
||||
[quo/overlay
|
||||
{:type :shell
|
||||
:container-style (style/page-wrapper insets)}
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:key :content
|
||||
:keyboard-vertical-offset (if platform/ios? alert-banners-top-margin 0)
|
||||
:style style/screen-container}
|
||||
[rn/view {:style {:gap 22}}
|
||||
[quo/text-combinations {:title (i18n/label :t/bio)}]
|
||||
[quo/input
|
||||
{:blur? true
|
||||
:multiline? true
|
||||
:error? (not (string/blank? error-msg))
|
||||
:container-style {:margin-bottom -11}
|
||||
:default-value bio
|
||||
:auto-focus true
|
||||
:max-height 200
|
||||
:char-limit constants/profile-bio-max-length
|
||||
:label (i18n/label :t/profile-bio)
|
||||
:placeholder (i18n/label :t/something-about-you)
|
||||
:on-change-text on-change-text}]
|
||||
(when-not (string/blank? error-msg)
|
||||
[quo/info-message
|
||||
{:type :error
|
||||
:size :default
|
||||
:icon :i/info}
|
||||
error-msg])]
|
||||
[rn/view {:style style/button-wrapper}
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:profile/edit-bio bio]))
|
||||
:disabled? (boolean (or typing?
|
||||
(and (string/blank? current-bio)
|
||||
(string/blank? bio))
|
||||
(not (string/blank? error-msg))))}
|
||||
(i18n/label :t/save-bio)]]]]))
|
||||
|
|
|
@ -195,8 +195,8 @@
|
|||
profile-picture (rf/sub [:profile/login-profiles-picture key-uid])
|
||||
login-multiaccount (rn/use-callback #(rf/dispatch [:profile.login/login]))]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style style/login-container
|
||||
:keyboardVerticalOffset (- (safe-area/get-bottom))}
|
||||
{:style style/login-container
|
||||
:keyboard-vertical-offset (- (safe-area/get-bottom))}
|
||||
[rn/view {:style style/multi-profile-button-container}
|
||||
(when config/quo-preview-enabled?
|
||||
[quo/button
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
:blur? true
|
||||
:action :arrow}
|
||||
{: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 :icon
|
||||
:blur? true
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.contexts.profile.settings.screens.password.change-password.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def form-container
|
||||
|
@ -48,7 +49,7 @@
|
|||
:justify-content :space-between})
|
||||
|
||||
(def bottom-part
|
||||
{:margin-bottom (- (safe-area/get-bottom) 12)
|
||||
{:margin-bottom (if platform/ios? (safe-area/get-bottom) 12)
|
||||
:justify-content :flex-end})
|
||||
|
||||
(def disclaimer-container
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
(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])
|
||||
current-step (rf/sub [:settings/change-password-current-step])]
|
||||
(rn/use-unmount #(rf/dispatch [:change-password/reset]))
|
||||
|
@ -33,8 +33,12 @@
|
|||
:icon-name :i/arrow-left
|
||||
:on-press navigate-back}]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style {:flex 1}
|
||||
:keyboardVerticalOffset (if platform/ios? alert-banners-top-margin 0)}
|
||||
{:style {:flex 1}
|
||||
:keyboard-vertical-offset (if platform/ios?
|
||||
(-> 12
|
||||
(+ alert-banners-top-margin)
|
||||
(- bottom))
|
||||
0)}
|
||||
(condp = current-step
|
||||
:old-password [old-password-form/view]
|
||||
:new-password [new-password-form/view])]]]))
|
||||
|
|
|
@ -30,18 +30,18 @@
|
|||
supported? (boolean biometric-type)
|
||||
enabled? (= auth-method constants/auth-method-biometric)
|
||||
biometric-on? (and supported? enabled?)
|
||||
press-handler (if biometric-on?
|
||||
(fn [] (rf/dispatch [:biometric/disable]))
|
||||
(on-press-biometric-enable label theme))]
|
||||
press-handler (when supported?
|
||||
(if biometric-on?
|
||||
(fn [] (rf/dispatch [:biometric/disable]))
|
||||
(on-press-biometric-enable label theme)))]
|
||||
{:title label
|
||||
:image-props icon
|
||||
:image :icon
|
||||
:blur? true
|
||||
:action :selector
|
||||
:action-props {:disabled? (not supported?)
|
||||
:on-change press-handler
|
||||
:action-props {:on-change press-handler
|
||||
:checked? biometric-on?}
|
||||
:on-press (when supported? press-handler)}))
|
||||
:on-press press-handler}))
|
||||
|
||||
(defn- get-change-password-item
|
||||
[]
|
||||
|
|
|
@ -167,9 +167,9 @@
|
|||
|
||||
(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]}]]
|
||||
{:fx [[:import-keypair-by-seed-phrase
|
||||
{:fx [[:effects.wallet/import-missing-keypair-by-seed-phrase
|
||||
{:keypair-key-uid keypair-key-uid
|
||||
:seed-phrase seed-phrase
|
||||
:password password
|
||||
|
@ -178,24 +178,26 @@
|
|||
#{keypair-key-uid}])
|
||||
(rf/call-continuation on-success))
|
||||
: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/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]]
|
||||
(let [error-type (-> error ex-message keyword)
|
||||
error-data (ex-data error)]
|
||||
(when-not (and (= error-type :import-keypair-by-seed-phrase/import-error)
|
||||
(= (:hint error-data) :incorrect-seed-phrase-for-keypair))
|
||||
(when-not (= error-type :import-missing-keypair-by-seed-phrase/import-error)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme :dark
|
||||
: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
|
||||
[_ [{:keys [keypair-key-uid private-key password on-success on-error]}]]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
(ns status-im.contexts.settings.wallet.keypairs-and-accounts.actions.view
|
||||
(:require [quo.core :as quo]
|
||||
[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.re-frame :as rf]))
|
||||
|
||||
|
@ -14,20 +14,22 @@
|
|||
[(:key-uid keypair)]])
|
||||
[keypair])
|
||||
on-show-qr (rn/use-callback #(rf/dispatch [:open-modal
|
||||
:screen/settings.encrypted-key-pair-qr
|
||||
:screen/settings.encrypted-keypair-qr
|
||||
keypair])
|
||||
[keypair])
|
||||
on-remove-keypair (rn/use-callback #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:theme :dark
|
||||
:content (fn []
|
||||
[remove-key-pair/view keypair])}])
|
||||
[remove-keypair/view keypair])}])
|
||||
[keypair])
|
||||
on-rename-keypair (rn/use-callback #(rf/dispatch [:open-modal :screen/settings.rename-keypair
|
||||
keypair])
|
||||
[keypair])
|
||||
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])
|
||||
on-import-private-key (rn/use-callback
|
||||
#(rf/dispatch [:open-modal
|
||||
|
|
|
@ -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
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
|
@ -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
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.safe-area :as safe-area]))
|
|
@ -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
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
|
@ -7,8 +7,10 @@
|
|||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.common.resources :as resources]
|
||||
[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.encrypted-qr.style :as style]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.countdown.view
|
||||
: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]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
|
@ -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
|
||||
{:row-gap 8
|
|
@ -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
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
|
@ -7,7 +7,8 @@
|
|||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[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]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
|
@ -68,8 +69,7 @@
|
|||
[on-change])
|
||||
on-import-error (rn/use-callback
|
||||
(fn [_error]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(show-invalid)))
|
||||
(rf/dispatch [:hide-bottom-sheet])))
|
||||
on-import-success (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
|
@ -134,5 +134,5 @@
|
|||
(case flow-state
|
||||
:correct-private-key (i18n/label :t/correct-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)])]]]))
|
|
@ -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
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
|
@ -14,16 +14,17 @@
|
|||
container-style
|
||||
prepare-seed-phrase
|
||||
seed-phrase
|
||||
set-invalid-seed-phrase
|
||||
set-incorrect-seed-phrase
|
||||
focus-input]}]
|
||||
(let [keypair (rf/sub [:get-screen-params])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
show-errors (rn/use-callback
|
||||
#(js/setTimeout
|
||||
(fn []
|
||||
(focus-input)
|
||||
(reagent/next-tick set-invalid-seed-phrase))
|
||||
600))
|
||||
(fn [_error]
|
||||
(js/setTimeout
|
||||
(fn []
|
||||
(focus-input)
|
||||
(reagent/next-tick set-incorrect-seed-phrase))
|
||||
600)))
|
||||
on-import-error (rn/use-callback
|
||||
(fn [_error]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
|
@ -34,7 +35,7 @@
|
|||
(rf/dispatch [:navigate-back])))
|
||||
on-auth-success (rn/use-callback
|
||||
(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)
|
||||
:seed-phrase (prepare-seed-phrase seed-phrase)
|
||||
:password password
|
|
@ -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
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.scan-qr-code.view :as scan-qr-code]
|
|
@ -159,9 +159,7 @@
|
|||
:ens address-or-ens
|
||||
:ens? ens-name?}])
|
||||
(rf/dispatch
|
||||
[:navigate-to-within-stack
|
||||
[:screen/settings.save-address
|
||||
:screen/settings.add-address-to-save]]))
|
||||
[:open-modal :screen/settings.save-address]))
|
||||
[address ens-name? address-or-ens])]
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/clear-address-to-save]))
|
||||
[quo/overlay {:type :shell}
|
||||
|
|
|
@ -66,8 +66,7 @@
|
|||
|
||||
(defn- add-address-to-save
|
||||
[]
|
||||
(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/settings.add-address-to-save :screen/settings.saved-addresses]]))
|
||||
(rf/dispatch [:open-modal :screen/settings.add-address-to-save]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
(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
|
||||
[]
|
||||
(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
|
||||
[]
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
(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
|
||||
[]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.account.style :as style]
|
||||
[status-im.contexts.wallet.account.tabs.view :as tabs]
|
||||
[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})
|
||||
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
|
||||
[]
|
||||
(let [selected-tab (reagent/atom first-tab-id)]
|
||||
(fn []
|
||||
(let [{:keys [name color formatted-balance
|
||||
watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/close-account-page]))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[account-switcher/view
|
||||
{:type :wallet-networks
|
||||
:on-press #(rf/dispatch [:wallet/close-account-page])}]
|
||||
[quo/account-overview
|
||||
{:container-style style/account-overview
|
||||
:current-value formatted-balance
|
||||
:account-name name
|
||||
:account (if watch-only? :watched-address :default)
|
||||
:customization-color color}]
|
||||
(when (ff/enabled? ::ff/wallet.graph) [quo/wallet-graph {:time-frame :empty}])
|
||||
(when (not watch-only?)
|
||||
[quo/wallet-ctas
|
||||
{:container-style style/cta-buttons
|
||||
:send-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/wizard-navigate-forward
|
||||
{:start-flow? true
|
||||
:flow-id :wallet-send-flow}]))
|
||||
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
|
||||
{:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:bridge-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/wizard-navigate-forward
|
||||
{:start-flow? true
|
||||
:flow-id :wallet-bridge-flow}]))
|
||||
:swap-action (when (ff/enabled? ::ff/wallet.swap)
|
||||
#(rf/dispatch [:wallet.swap/start]))}])
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:default-active @selected-tab
|
||||
:data (tabs-data watch-only?)
|
||||
:on-change (rn/use-callback (fn [tab] (reset! selected-tab tab)))
|
||||
:scrollable? true
|
||||
:scroll-on-press? true}]
|
||||
[tabs/view {:selected-tab @selected-tab}]
|
||||
(when (ff/enabled? ::ff/shell.jump-to)
|
||||
[quo/floating-shell-button
|
||||
{:jump-to
|
||||
{:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
|
||||
:customization-color customization-color
|
||||
:label (i18n/label :t/jump-to)}}
|
||||
style/shell-button])]))))
|
||||
(let [selected-tab (or (rf/sub [:wallet/account-tab]) first-tab-id)
|
||||
{:keys [name color formatted-balance watch-only?
|
||||
address]} (rf/sub [:wallet/current-viewing-account])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
(rn/use-mount
|
||||
#(rf/dispatch [:wallet/fetch-activities-for-current-account address]))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[account-switcher/view
|
||||
{:type :wallet-networks
|
||||
:on-press #(rf/dispatch [:wallet/close-account-page])}]
|
||||
[quo/account-overview
|
||||
{:container-style style/account-overview
|
||||
:current-value formatted-balance
|
||||
:account-name name
|
||||
:account (if watch-only? :watched-address :default)
|
||||
:customization-color color}]
|
||||
(when (ff/enabled? ::ff/wallet.graph) [quo/wallet-graph {:time-frame :empty}])
|
||||
(when (not watch-only?)
|
||||
[quo/wallet-ctas
|
||||
{:container-style style/cta-buttons
|
||||
:send-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/wizard-navigate-forward
|
||||
{:start-flow? true
|
||||
:flow-id :wallet-send-flow}]))
|
||||
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address
|
||||
{:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:bridge-action (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/wizard-navigate-forward
|
||||
{:start-flow? true
|
||||
:flow-id :wallet-bridge-flow}]))
|
||||
:swap-action (when (ff/enabled? ::ff/wallet.swap)
|
||||
#(rf/dispatch [:wallet.swap/start]))}])
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
:active-tab-id selected-tab
|
||||
:data (tabs-data watch-only?)
|
||||
:on-change change-tab
|
||||
:scrollable? true
|
||||
:scroll-on-press? true}]
|
||||
[tabs/view {:selected-tab selected-tab}]
|
||||
(when (ff/enabled? ::ff/shell.jump-to)
|
||||
[quo/floating-shell-button
|
||||
{:jump-to
|
||||
{:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
|
||||
:customization-color customization-color
|
||||
:label (i18n/label :t/jump-to)}}
|
||||
style/shell-button])]))
|
||||
|
|
|
@ -7,5 +7,4 @@
|
|||
:skip-step? (fn [db] (some? (get-in db [:wallet :ui :send :bridge-to-chain-id])))}
|
||||
{:screen-id :screen/wallet.bridge-input-amount
|
||||
:skip-step? (fn [db] (some? (get-in db [:wallet :ui :send :amount])))}
|
||||
{:screen-id :screen/wallet.transaction-confirmation}
|
||||
{:screen-id :screen/wallet.transaction-progress}])
|
||||
{:screen-id :screen/wallet.transaction-confirmation}])
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
:on-press #(rf/dispatch
|
||||
[:wallet/set-collectible-to-send
|
||||
{:collectible collectible
|
||||
:start-flow? true
|
||||
:current-screen :screen/wallet.collectible}])}
|
||||
(i18n/label :t/send)])
|
||||
[quo/button
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:networks networks
|
||||
:align-center? true
|
||||
:networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}])
|
||||
:right-side [(when (and (ff/enabled? ::ff/wallet.wallet-connect)
|
||||
(not watch-only?))
|
||||
|
|
|
@ -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)})))
|
|
@ -1,61 +1,42 @@
|
|||
(ns status-im.contexts.wallet.common.activity-tab.view
|
||||
(:require
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[native-module.core :as native-module]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.resources :as quo.resources]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[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]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[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
|
||||
[{:keys [activity-type activity-status timestamp symbol-out symbol-in token-in token-out amount-in
|
||||
amount-out sender recipient]}]
|
||||
(let [chain-id (or (:chain-id token-in) (:chain-id token-out))
|
||||
amount-in-units (native-module/hex-to-number
|
||||
(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}]))
|
||||
[{:keys [transaction] :as activity}]
|
||||
(case transaction
|
||||
(:send :receive) [send-and-receive-activity activity]
|
||||
nil))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
@ -69,7 +50,8 @@
|
|||
[rn/section-list
|
||||
{:sections activity-list
|
||||
: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}
|
||||
:render-fn activity-item
|
||||
:render-section-header-fn (fn [{:keys [title]}] [quo/divider-date title])}])))
|
||||
|
|
|
@ -72,8 +72,10 @@
|
|||
selected-account? (rf/sub [:wallet/current-viewing-account-address])
|
||||
send-params (if selected-account?
|
||||
{:token token-data
|
||||
:stack-id :screen/wallet.accounts
|
||||
:start-flow? true}
|
||||
{:token-symbol token-symbol
|
||||
:stack-id :wallet-stack
|
||||
:start-flow? true})]
|
||||
[quo/action-drawer
|
||||
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
:on-success (fn [value]
|
||||
(resolver {:value value}))}))))
|
||||
|
||||
(defn import-keypair-by-seed-phrase
|
||||
(defn import-missing-keypair-by-seed-phrase
|
||||
[keypair-key-uid seed-phrase password]
|
||||
(-> (validate-mnemonic seed-phrase)
|
||||
(promesa/then
|
||||
|
@ -87,20 +87,20 @@
|
|||
(if (not= keypair-key-uid key-uid)
|
||||
(promesa/rejected
|
||||
(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}))
|
||||
(make-seed-phrase-fully-operable seed-phrase password))))
|
||||
(promesa/catch
|
||||
(fn [error]
|
||||
(promesa/rejected
|
||||
(ex-info
|
||||
(error-message :import-keypair-by-seed-phrase/import-error)
|
||||
(error-message :import-missing-keypair-by-seed-phrase/import-error)
|
||||
(ex-data error)))))))
|
||||
|
||||
(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]}]
|
||||
(-> (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/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.wallet.effects]
|
||||
[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.networks :as network-utils]
|
||||
[status-im.contexts.wallet.data-store :as data-store]
|
||||
|
@ -35,6 +36,12 @@
|
|||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] 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]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/navigate-to-new-account
|
||||
|
@ -44,6 +51,14 @@
|
|||
[:dispatch [:navigate-to :screen/wallet.accounts 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
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)}))
|
||||
|
@ -55,6 +70,7 @@
|
|||
(rf/reg-event-fx :wallet/close-account-page
|
||||
(fn [_]
|
||||
{:fx [[:dispatch [:wallet/clean-current-viewing-account]]
|
||||
[:dispatch [:wallet/clear-account-tab]]
|
||||
[:dispatch [:pop-to-root :shell-stack]]]}))
|
||||
|
||||
(defn log-rpc-error
|
||||
|
@ -491,49 +507,6 @@
|
|||
|
||||
(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
|
||||
:wallet/get-crypto-on-ramps-success
|
||||
(fn [{:keys [db]} [data]]
|
||||
|
|
|
@ -253,7 +253,7 @@
|
|||
|
||||
(rf/reg-event-fx
|
||||
: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)
|
||||
collectible-data (:collectible-data collectible)
|
||||
contract-type (:contract-type collectible)
|
||||
|
@ -282,6 +282,7 @@
|
|||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen current-screen
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-send-flow}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
@ -447,18 +448,26 @@
|
|||
(assoc-in [:wallet :transactions] transaction-details)
|
||||
(assoc-in [:wallet :ui :send :transaction-ids] transaction-ids))
|
||||
:fx [[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen :screen/wallet.transaction-confirmation
|
||||
:flow-id :wallet-send-flow}]]]})))
|
||||
[:wallet/end-transaction-flow]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/close-transaction-progress-page
|
||||
(rf/reg-event-fx :wallet/clean-up-transaction-flow
|
||||
(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-send-address]]
|
||||
[:dispatch [:wallet/clean-disabled-from-networks]]
|
||||
[:dispatch [:wallet/select-address-tab nil]]
|
||||
[:dispatch [:dismiss-modal :screen/wallet.transaction-progress]]]}))
|
||||
[:dispatch [:wallet/select-address-tab nil]]]}))
|
||||
|
||||
(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
|
||||
[{:keys [from-address to-address token-address route data eth-transfer?]}]
|
||||
|
|
|
@ -27,5 +27,4 @@
|
|||
:skip-step? (fn [db]
|
||||
(or (not (collectible-selected? db))
|
||||
(some? (get-in db [:wallet :ui :send :amount]))))}
|
||||
{:screen-id :screen/wallet.transaction-confirmation}
|
||||
{:screen-id :screen/wallet.transaction-progress}])
|
||||
{:screen-id :screen/wallet.transaction-confirmation}])
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- on-press
|
||||
(defn- on-account-press
|
||||
[address network-details]
|
||||
(rf/dispatch [:wallet/select-from-account
|
||||
{:address address
|
||||
|
@ -22,15 +22,19 @@
|
|||
(rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn- render-fn
|
||||
[item]
|
||||
(let [network-details (rf/sub [:wallet/network-details])]
|
||||
[item _ _ {:keys [network-details]}]
|
||||
(let [transformed-address (rf/sub [:wallet/account-address (:address item)
|
||||
(:network-preferences-names item)])]
|
||||
[quo/account-item
|
||||
{:on-press #(on-press (:address item) network-details)
|
||||
:account-props item}]))
|
||||
{:on-press #(on-account-press (:address item) network-details)
|
||||
:account-props (assoc item
|
||||
:address transformed-address
|
||||
:full-address? true)}]))
|
||||
|
||||
(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
|
||||
{:footer-container-padding 0
|
||||
:header [account-switcher/view
|
||||
|
@ -45,5 +49,6 @@
|
|||
{:style style/accounts-list
|
||||
:content-container-style style/accounts-list-container
|
||||
:data accounts
|
||||
:render-data {:network-details network-details}
|
||||
:render-fn render-fn
|
||||
:shows-horizontal-scroll-indicator false}]]))
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[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.asset-list.view :as asset-list]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.input-amount.style :as style]
|
||||
[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]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
|
@ -125,6 +127,15 @@
|
|||
:style {:margin-top 15}}
|
||||
(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
|
||||
;; crypto-decimals, limit-crypto and initial-crypto-currency? args are needed
|
||||
;; for component tests only
|
||||
|
@ -264,7 +275,25 @@
|
|||
limit-insufficient? (> (controlled-input/numeric-value input-state)
|
||||
current-limit)
|
||||
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
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
|
@ -339,8 +368,9 @@
|
|||
{:loading-routes? loading-routes?
|
||||
:fees fee-formatted
|
||||
:amount amount-text}])
|
||||
(when (and (or no-routes-found? limit-insufficient?) (not-empty sender-network-values))
|
||||
[no-routes-found])
|
||||
(cond
|
||||
show-no-routes? [no-routes-found]
|
||||
not-enough-asset? [not-enough-asset])
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (if should-try-again?
|
||||
|
|
|
@ -17,15 +17,21 @@
|
|||
:description (i18n/label :t/here-is-a-cat-in-a-box-instead)
|
||||
:image (resources/get-themed-image :cat-in-box theme)
|
||||
:container-style style/empty-container-style}]
|
||||
(into [rn/view {:style style/my-accounts-container}]
|
||||
(map (fn [{:keys [color address] :as account}]
|
||||
[quo/account-item
|
||||
{:account-props (assoc account :customization-color color)
|
||||
:on-press #(rf/dispatch [:wallet/select-send-address
|
||||
{:address address
|
||||
:recipient account
|
||||
:stack-id :screen/wallet.select-address}])}]))
|
||||
other-accounts))))
|
||||
[rn/view {:style style/my-accounts-container}
|
||||
(doall
|
||||
(for [{:keys [color address] :as account} other-accounts]
|
||||
^{:key (str address)}
|
||||
(let [transformed-address (rf/sub [:wallet/account-address address
|
||||
(:network-preferences-names account)])]
|
||||
[quo/account-item
|
||||
{:account-props (assoc account
|
||||
: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
|
||||
[theme]
|
||||
|
@ -46,16 +52,56 @@
|
|||
:stack-id :screen/wallet.select-address}])}]))
|
||||
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
|
||||
[{:keys [selected-tab]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
(case selected-tab
|
||||
:tab/recent [recent-transactions theme]
|
||||
:tab/saved [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)
|
||||
:container-style style/empty-container-style}]
|
||||
:tab/saved [saved-addresses theme]
|
||||
:tab/contacts [quo/empty-state
|
||||
{:title (i18n/label :t/no-contacts)
|
||||
:description (i18n/label :t/no-contacts-description)
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
(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])]
|
||||
(fn []
|
||||
(rn/use-effect
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
"wallet-blockchain-status-changed" {:fx [[:dispatch
|
||||
[:wallet/blockchain-status-changed
|
||||
(transforms/js->clj event-js)]]]}
|
||||
"wallet-activity-filtering-done" {:fx [[:dispatch
|
||||
[:wallet/activity-filtering-done
|
||||
(transforms/js->clj event-js)]]]}
|
||||
"wallet-activity-filtering-done" {:fx
|
||||
[[:dispatch
|
||||
[:wallet/activity-filtering-for-current-account-done
|
||||
(transforms/js->clj event-js)]]]}
|
||||
(log/debug ::unknown-wallet-event :type event-type)))))
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
(rf/defn navigate-to-within-stack
|
||||
{:events [:navigate-to-within-stack]}
|
||||
[{:keys [db]} comp-id]
|
||||
{:db (assoc db :view-id (first comp-id))
|
||||
[{:keys [db]} comp-id screen-params]
|
||||
{:db (all-screens-params db (first comp-id) screen-params)
|
||||
:fx [[:navigate-to-within-stack comp-id]]})
|
||||
|
||||
(re-frame/reg-event-fx :open-modal
|
||||
|
|
|
@ -57,14 +57,15 @@
|
|||
[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.view :as settings]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.encrypted-qr.view :as
|
||||
encrypted-key-pair-qr]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.import-private-key.view :as
|
||||
import-private-key]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.import-seed-phrase.view :as
|
||||
import-seed-phrase]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.encrypted-qr.view
|
||||
:as encrypted-keypair-qr]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-private-key.view
|
||||
:as missing-keypairs.import-private-key]
|
||||
[status-im.contexts.settings.wallet.keypairs-and-accounts.missing-keypairs.import-seed-phrase.view
|
||||
: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.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.network-settings.view :as network-settings]
|
||||
[status-im.contexts.settings.wallet.saved-addresses.add-address-to-save.view :as
|
||||
|
@ -535,9 +536,9 @@
|
|||
:options (assoc options/dark-screen :sheet? true)
|
||||
:component keypair-rename/view}
|
||||
|
||||
{:name :screen/settings.encrypted-key-pair-qr
|
||||
{:name :screen/settings.encrypted-keypair-qr
|
||||
:options options/transparent-screen-options
|
||||
:component encrypted-key-pair-qr/view}
|
||||
:component encrypted-keypair-qr/view}
|
||||
|
||||
{:name :screen/settings.saved-addresses
|
||||
:options options/transparent-modal-screen-options
|
||||
|
@ -551,13 +552,13 @@
|
|||
:options options/transparent-modal-screen-options
|
||||
:component scan-keypair-qr/view}
|
||||
|
||||
{:name :screen/settings.import-seed-phrase
|
||||
{:name :screen/settings.missing-keypair.import-seed-phrase
|
||||
: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
|
||||
:options options/transparent-screen-options
|
||||
:component import-private-key/view}
|
||||
:component missing-keypairs.import-private-key/view}
|
||||
|
||||
{:name :screen/settings.network-settings
|
||||
:options options/transparent-modal-screen-options
|
||||
|
|
|
@ -1,26 +1,82 @@
|
|||
(ns status-im.subs.wallet.activities
|
||||
(: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]
|
||||
[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
|
||||
:wallet/all-activities
|
||||
:<- [:wallet]
|
||||
:-> :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/current-viewing-account-address]
|
||||
(fn [[activities current-viewing-account-address]]
|
||||
(->> activities
|
||||
(filter (fn [{:keys [sender recipient activity-type]}]
|
||||
(let [receiving-activity? (= activity-type constants/wallet-activity-type-receive)
|
||||
relevant-address (if receiving-activity? recipient sender)]
|
||||
(= relevant-address current-viewing-account-address))))
|
||||
(distinct)
|
||||
(group-by (fn [{:keys [timestamp]}]
|
||||
(datetime/timestamp->relative-short-date (* timestamp 1000))))
|
||||
(map (fn [[date activities]]
|
||||
{:title date :data activities :timestamp (:timestamp (first activities))}))
|
||||
(sort-by (fn [{:keys [timestamp]}] (- timestamp))))))
|
||||
:<- [:wallet/network-details]
|
||||
(fn [[activities current-viewing-account-address network-details]]
|
||||
(let [chain-id->network-name (update-vals (group-by :chain-id network-details)
|
||||
(comp :network-name first))]
|
||||
(->> current-viewing-account-address
|
||||
(get activities)
|
||||
(keep #(process-activity-by-type chain-id->network-name %))
|
||||
(group-by (fn [{:keys [timestamp]}]
|
||||
(datetime/timestamp->relative-short-date (* timestamp 1000))))
|
||||
(map (fn [[date activities]]
|
||||
{:title date
|
||||
:data activities
|
||||
:timestamp (:timestamp (first activities))}))
|
||||
(sort-by (fn [{:keys [timestamp]}] (- timestamp)))))))
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
(:require
|
||||
[cljs.test :refer [is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
status-im.subs.root
|
||||
status-im.subs.wallet.collectibles
|
||||
[status-im.contexts.wallet.common.activity-tab.constants :as constants]
|
||||
[status-im.subs.root]
|
||||
[status-im.subs.wallet.collectibles]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -14,7 +15,7 @@
|
|||
[:wallet :activities]
|
||||
[{:id 1 :name "Transaction1"}
|
||||
{: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
|
||||
[sub-name]
|
||||
|
@ -23,11 +24,62 @@
|
|||
(fn [db]
|
||||
(-> db
|
||||
(assoc-in [:wallet :activities]
|
||||
[{:sender "acc1" :recipient "acc2" :timestamp 1588291200}
|
||||
{:sender "acc2" :recipient "acc1" :timestamp 1588377600}
|
||||
{:sender "acc3" :recipient "acc4" :timestamp 1588464000}])
|
||||
{"acc1" [{:activity-type constants/wallet-activity-type-send
|
||||
:amount-out "0x1"
|
||||
: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"))))
|
||||
(is (= [{:title "May 1, 2020"
|
||||
:data [{:sender "acc1" :recipient "acc2" :timestamp 1588291200}]
|
||||
:timestamp 1588291200}]
|
||||
(rf/sub [sub-name])))))
|
||||
(is
|
||||
(match? [{:title "May 3, 2020"
|
||||
:timestamp 1588464000
|
||||
: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])))))
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
(ns status-im.subs.wallet.networks
|
||||
(:require [quo.foundations.resources :as resources]
|
||||
[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
|
||||
:wallet/networks
|
||||
|
@ -88,3 +91,13 @@
|
|||
(filter
|
||||
#(contains? selected-networks (:network-name %))
|
||||
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)))
|
||||
|
|
|
@ -82,3 +82,14 @@
|
|||
:chain-id 10
|
||||
:layer 2}}
|
||||
(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]])))))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.subs.wallet.send
|
||||
(:require
|
||||
[re-frame.core :as rf]
|
||||
[status-im.contexts.wallet.common.activity-tab.constants :as constants]
|
||||
[utils.number]))
|
||||
|
||||
(rf/reg-sub
|
||||
|
@ -40,14 +41,15 @@
|
|||
|
||||
(rf/reg-sub
|
||||
:wallet/recent-recipients
|
||||
:<- [:wallet/activities-for-current-viewing-account]
|
||||
:<- [:wallet/all-activities]
|
||||
:<- [:wallet/current-viewing-account-address]
|
||||
(fn [[sections current-viewing-account-address]]
|
||||
(let [all-transactions (mapcat :data sections)
|
||||
users-sent-transactions (filter (fn [{:keys [sender]}]
|
||||
(= sender current-viewing-account-address))
|
||||
all-transactions)]
|
||||
(set (map :recipient users-sent-transactions)))))
|
||||
(fn [[all-activities current-viewing-account-address]]
|
||||
(let [address-activity (get all-activities current-viewing-account-address)]
|
||||
(->> address-activity
|
||||
(keep (fn [{:keys [activity-type recipient]}]
|
||||
(when (= constants/wallet-activity-type-send activity-type)
|
||||
recipient)))
|
||||
(distinct)))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/send-token-not-supported-in-receiver-networks?
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
(:require
|
||||
[cljs.test :refer [is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
status-im.subs.root
|
||||
status-im.subs.wallet.send
|
||||
[status-im.contexts.wallet.common.activity-tab.constants :as constants]
|
||||
[status-im.subs.root]
|
||||
[status-im.subs.wallet.send]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -61,8 +62,25 @@
|
|||
(fn [db]
|
||||
(-> db
|
||||
(assoc-in [:wallet :activities]
|
||||
[{:sender "acc1" :recipient "acc2" :timestamp 1588291200}
|
||||
{:sender "acc2" :recipient "acc1" :timestamp 1588377600}
|
||||
{:sender "acc3" :recipient "acc4" :timestamp 1588464000}])
|
||||
{"acc1" [{:activity-type constants/wallet-activity-type-send
|
||||
:amount-out "0x1"
|
||||
: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"))))
|
||||
(is (= #{"acc2"} (rf/sub [sub-name])))))
|
||||
(is (match? ["acc2" "acc4"] (rf/sub [sub-name])))))
|
||||
|
|
|
@ -259,22 +259,22 @@
|
|||
:wallet/settings-keypairs-accounts
|
||||
:<- [:wallet/keypairs]
|
||||
(fn [keypairs [_ format-options]]
|
||||
(let [grouped-keypairs (group-by :lowest-operability keypairs)
|
||||
operable-key-pair-ids (->> (concat (:fully grouped-keypairs)
|
||||
(:partially grouped-keypairs))
|
||||
(map :key-uid)
|
||||
(into #{}))
|
||||
missing-key-pair-ids (->> (map :key-uid (:no grouped-keypairs))
|
||||
(into #{}))]
|
||||
(let [grouped-keypairs (group-by :lowest-operability keypairs)
|
||||
operable-keypair-ids (->> (concat (:fully grouped-keypairs)
|
||||
(:partially grouped-keypairs))
|
||||
(map :key-uid)
|
||||
(into #{}))
|
||||
missing-keypair-ids (->> (map :key-uid (:no grouped-keypairs))
|
||||
(into #{}))]
|
||||
{: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]}]
|
||||
{:type (keyword type)
|
||||
:name name
|
||||
:key-uid key-uid
|
||||
:accounts (format-settings-keypair-accounts accounts format-options)})))
|
||||
: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]}]
|
||||
{:type (keyword type)
|
||||
:name name
|
||||
|
@ -435,6 +435,12 @@
|
|||
accounts)
|
||||
accounts))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/account-tab
|
||||
:<- [:wallet/ui]
|
||||
(fn [ui]
|
||||
(get-in ui [:account-page :active-tab])))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/current-viewing-account-token-values
|
||||
:<- [:wallet/current-viewing-account]
|
||||
|
|
|
@ -1587,6 +1587,7 @@
|
|||
"seed-phrase-words-uppercase": "Recovery phrase cannot contain uppercase characters",
|
||||
"seed-phrase-error": "Recovery phrase contains invalid words",
|
||||
"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",
|
||||
"word-count": "Word count",
|
||||
"word-n": "Word #{{number}}",
|
||||
|
@ -1629,6 +1630,7 @@
|
|||
"ok-save-pass": "OK, save password",
|
||||
"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-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",
|
||||
"select-account-dapp": "Select the account you wish to use with Dapps",
|
||||
"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.",
|
||||
"invalid-private-key": "It’s not a valid 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",
|
||||
"this-account-has-no-activity": "This account has no activity",
|
||||
"this-address-has-activity": "This address has activity",
|
||||
|
@ -2699,5 +2701,7 @@
|
|||
"wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported",
|
||||
"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",
|
||||
"add-preferences": "Add preferences"
|
||||
"add-preferences": "Add preferences",
|
||||
"buy-eth": "Buy ETH",
|
||||
"not-enough-assets": "Not enough assets to pay gas fees"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue