Compare commits

..
Author SHA1 Message Date
Andrea Maria Piana 1e3b207c3b test 2023-11-20 15:55:27 +00:00
John Ngei f03671097b enable biometric when user signs in with syncing (#17627) 2023-11-17 15:23:36 +00:00
frank 1db63a9fa1 local pair: check netIPs if empty before find server cert 2023-11-17 11:26:54 +00:00
Lungu CristianandIbrkhalil cd92b41214 Composer collapsing when editing canceled/done (#17785)
* fix: composer height when entering and canceling edit

* fix: blur the composer input when canceling edit

* fix: focusing animation and composer height after blur

* fix: input height when canceling edit while unfocused

* ref: removed arbitrary keyboard check

* fix: moved edit-mentions logic to use-edit to fix unresolved mention

* fix: composer edit should put the cursor at the end

* fix: (potentially) fixing the mention not resolved during edit

* fix: emoji-kb handler changing the height when default kb appears

* Fix text content when editing and reentering chat

* prevent composer when focusing on opening chat with edit/reply

* clean

* Clauxx comments

* Apply for reply

* Lintil soup = yummy

* refactor variable name

* Extract the focusing logic from the data setting logic

* Edge case

* fix: composer mention key & edit re-enter issues

* fix: reply cancel input blur and smooth reply focus

---------

Co-authored-by: Ibrkhalil <vampirekid017@gmail.com>
2023-11-17 11:14:23 +00:00
Andrea Maria Piana 56f7206da7 Restore shards 2023-11-16 19:43:29 +00:00
Andrea Maria Piana eb5de3506a Revert changes in sharded keys 2023-11-16 19:11:20 +00:00
flexsurfer 22005f916e [#17854] [IOS] The tutorial video animation keeps playing after openi… (#17915)
(cherry picked from commit 7153e4da48)
2023-11-16 12:36:13 +01:00
Flavio Fraschetti ff50aacb3a Hide channel list at token-gated communities overview (#17901)
This commit hides the categorized channel list for token-gated communities overview.
2023-11-16 10:57:54 +00:00
Icaro Motta 91300b9ff8 Fix: unable to join token-gated communities (#17894)
Fixes the bug by explicitly passing all available addresses to be revealed
to wakuext_requestToJoinCommunity and picking up the first available address
as the airdrop address. This is a temporary solution while we work on the
feature to allow users to choose which addresses to expose.

Fixes https://github.com/status-im/status-mobile/issues/17861

*Areas that may be impacted*: join community flows.

    ----------------------------------------------------------------------
    Community "Request to join" option is enabled.
    User holds more than X ETH.
    Anyone who holds <X> ETH is allowed to Become member in <COMMUNITY>.
    
    Expected: request to join is received by desktop client and accepted,
    mobile user joins the community.
    ----------------------------------------------------------------------
    
    ----------------------------------------------------------------------
    Community "Request to join" option is enabled.
    User holds less than X ETH.
    Anyone who holds <X> ETH is allowed to View and post in <CHANNEL>.
    
    Expected: request to join is received by desktop client and accepted, mobile
    user joins the community, but can't post in <CHANNEL>.
    ----------------------------------------------------------------------
    
    ----------------------------------------------------------------------
    Community "Request to join" option is enabled.
    No token permissions.
    
    Expected: request to join is received by desktop client and accepted,
    mobile user joins the community.
    ----------------------------------------------------------------------
2023-11-15 06:46:55 -03:00
Andrea Maria Piana d93b20242a Point to shared release branch 2023-11-14 10:54:02 +00:00
Andrea Maria Piana 0a43e5c97a Bump release to 1.26.0 2023-11-14 10:52:00 +00:00
44 changed files with 537 additions and 683 deletions
+5 -6
View File
@@ -311,14 +311,13 @@ endef
lint: export TARGET := clojure
lint: export CLJ_LINTER_PRINT_WARNINGS ?= false
lint: ##@test Run code style checks
@sh scripts/lint/re-frame-in-quo-components.sh && \
sh scripts/lint/direct-require-component-outside-quo.sh && \
sh scripts/lint/require-i18n-resource-first.sh && \
@sh scripts/lint-re-frame-in-quo-components.sh && \
sh scripts/lint-direct-require-component-outside-quo.sh && \
clj-kondo --config .clj-kondo/config.edn --cache false --fail-level error --lint src $(if $(filter $(CLJ_LINTER_PRINT_WARNINGS),true),,| grep -v ': warning: ') && \
ALL_CLOJURE_FILES=$(call find_all_clojure_files) && \
scripts/lint/translations.clj && \
scripts/lint_translations.clj && \
zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILES && \
sh scripts/lint/trailing-newline.sh && \
sh scripts/lint-trailing-newline.sh && \
node_modules/.bin/prettier --write .
# NOTE: We run the linter twice because of https://github.com/kkinnear/zprint/issues/271
@@ -328,7 +327,7 @@ lint-fix: ##@test Run code style checks and fix issues
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILES && \
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILES && \
clojure-lsp --ns-exclude-regex ".*/src/status_im2/core\.cljs$$" clean-ns && \
sh scripts/lint/trailing-newline.sh --fix && \
sh scripts/lint-trailing-newline.sh --fix && \
node_modules/.bin/prettier --write .
shadow-server: export TARGET := clojure
+1 -1
View File
@@ -1 +1 @@
1.25.0
1.26.0
@@ -1,10 +0,0 @@
#!/usr/bin/env sh
if rg --quiet --multiline '^\(ns.*\n^\s*\(:require\n(^\s*(;|#_).*\n)*(^\s*\[status-im2\.setup\.i18n-resources\W)' src/status_im2/core.cljs; then
exit 0
elif [ $? -eq 1 ]; then
echo "status-im2.setup.i18n-resources must be loaded first (be the first one in ns :require form) in status-im2.core"
echo "For more info, check the comment here https://github.com/status-im/status-mobile/pull/17618#discussion_r1361275489"
else
exit $?
fi
@@ -1,53 +0,0 @@
(ns quo.components.tags.summary-tag.component-spec
(:require
[quo.components.tags.summary-tag.view :as summary-tag]
[test-helpers.component :as h]))
(h/describe "Summary tag component tests"
(h/test "Basic render"
(h/render [summary-tag/view])
(h/is-truthy (h/query-by-label-text :container)))
(h/test "Account view render"
(h/render [summary-tag/view
{:type :account
:label "Alice's Account"
:customization-color "#ff0000"
:emoji "🎉"}])
(h/is-truthy (h/get-by-text "Alice's Account")))
(h/test "Network view render"
(h/render [summary-tag/view
{:type :network
:label "Ethereum Network"
:image-source "path/to/ethereum-logo.png"}])
(h/is-truthy (h/get-by-text "Ethereum Network")))
(h/test "Saved address view render"
(h/render [summary-tag/view
{:type :saved-address
:label "Charlie's Wallet"
:customization-color "#00ff00"}])
(h/is-truthy (h/get-by-text "Charlie's Wallet")))
(h/test "Collectible view render"
(h/render [summary-tag/view
{:type :collectible
:label "Rare Artifact"
:image-source "path/to/artifact-image.png"}])
(h/is-truthy (h/get-by-text "Rare Artifact")))
(h/test "User view render"
(h/render [summary-tag/view
{:type :user
:label "Bob Smith"
:image-source "path/to/profile-pic.png"
:customization-color "#0000ff"}])
(h/is-truthy (h/get-by-text "Bob Smith")))
(h/test "Token view render"
(h/render [summary-tag/view
{:type :token
:label "1,000 SNT"
:image-source "path/to/token-image.png"}])
(h/is-truthy (h/get-by-text "1,000 SNT"))))
@@ -1,29 +0,0 @@
(ns quo.components.tags.summary-tag.style
(:require
[quo.foundations.colors :as colors]))
(defn main
[{:keys [type theme customization-color]}]
{:justify-content :center
:align-items :center
:height 32
:padding-left 4
:padding-right 10
:flex-direction :row
:border-radius (if (#{:account :collectible} type) 10 16)
:background-color (colors/resolve-color customization-color theme 10)})
(defn label
[type theme]
{:color (colors/theme-colors colors/neutral-100 colors/white theme)
:margin-left (if (= type :address) 6 4)})
(def collectible-image
{:width 24
:height 24
:border-radius 10})
(def token-image
{:width 24
:height 24
:border-radius 12})
@@ -1,67 +0,0 @@
(ns quo.components.tags.summary-tag.view
(:require
[quo.components.avatars.account-avatar.view :as account-avatar]
[quo.components.avatars.user-avatar.view :as user-avatar]
[quo.components.avatars.wallet-user-avatar.view :as wallet-user-avatar]
[quo.components.markdown.text :as text]
[quo.components.tags.summary-tag.style :as style]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
(defn- left-view
[{:keys [label type customization-color emoji image-source]}]
(case type
:account
[account-avatar/view
{:customization-color customization-color
:size 24
:emoji emoji
:type :default}]
:network
[rn/image
{:source image-source
:style style/token-image}]
:saved-address
[wallet-user-avatar/wallet-user-avatar
{:full-name label
:size :size-24
:customization-color customization-color}]
:collectible
[rn/image
{:source image-source
:style style/collectible-image}]
:user
[user-avatar/user-avatar
{:full-name label
:size :xs
:profile-picture image-source
:customization-color customization-color}]
:token
[rn/image
{:source image-source
:style style/token-image}]
nil))
(defn- view-internal
"Options:
- :label - string - tag label
- :customization-color - color - It will be passed down to components that
should vary based on a custom color.
- :type - :token / :user / :collectible / :saved-address / :network / :account
- :emoji - string - emoji used for displaying account avatar
- :image-source - resource - image to display on :network, :collectible :user and :token
- :theme - :light / :dark"
[{:keys [label customization-color type theme]
:as props
:or {customization-color colors/neutral-80-opa-5}}]
[rn/view
{:accessibility-label :container
:style (style/main (assoc props :customization-color customization-color))}
[left-view props]
[text/text
{:style (style/label type theme)
:weight :semi-bold
:size :heading-1} label]])
(def view (quo.theme/with-theme view-internal))
-2
View File
@@ -131,7 +131,6 @@
quo.components.tags.number-tag.view
quo.components.tags.permission-tag
quo.components.tags.status-tags
quo.components.tags.summary-tag.view
quo.components.tags.tag
quo.components.tags.tags
quo.components.tags.tiny-tag.view
@@ -361,7 +360,6 @@
(def number-tag quo.components.tags.number-tag.view/view)
(def permission-tag quo.components.tags.permission-tag/tag)
(def status-tag quo.components.tags.status-tags/status-tag)
(def summary-tag quo.components.tags.summary-tag.view/view)
(def tag quo.components.tags.tag/tag)
(def tags quo.components.tags.tags/tags)
(def tiny-tag quo.components.tags.tiny-tag.view/view)
-1
View File
@@ -73,7 +73,6 @@
[quo.components.switchers.group-messaging-card.component-spec]
[quo.components.tags.network-tags.component-spec]
[quo.components.tags.status-tags-component-spec]
[quo.components.tags.summary-tag.component-spec]
[quo.components.tags.tiny-tag.component-spec]
[quo.components.wallet.account-card.component-spec]
[quo.components.wallet.account-origin.component-spec]
+4 -8
View File
@@ -15,8 +15,6 @@
(def test-dir (.mkdtempSync fs test-dir-prefix))
(def initialized? (atom false))
(defn signal-received-callback
[a]
(re-frame/dispatch [:signals/signal-received a]))
@@ -24,12 +22,10 @@
;; We poll for signals, could not get callback working
(defn init!
[]
(when-not @initialized?
(.setSignalEventCallback native-status)
(reset! initialized? true)
(js/setInterval (fn []
(.pollSignal native-status signal-received-callback)
100))))
(.setSignalEventCallback native-status)
(js/setInterval (fn []
(.pollSignal native-status signal-received-callback)
100)))
(def status
(clj->js
@@ -0,0 +1,7 @@
(ns status-im2.common.standard-authentication.core
(:require
status-im2.common.standard-authentication.standard-auth.button.view
status-im2.common.standard-authentication.standard-auth.slide-button.view))
(def button status-im2.common.standard-authentication.standard-auth.button.view/view)
(def slide-button status-im2.common.standard-authentication.standard-auth.slide-button.view/view)
@@ -1,10 +1,6 @@
(ns status-im2.common.standard-authentication.standard-auth.view
(ns status-im2.common.standard-authentication.standard-auth.authorize
(:require
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.touch-id :as biometric]
[reagent.core :as reagent]
[status-im2.common.standard-authentication.enter-password.view :as enter-password]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -46,39 +42,3 @@
{:on-enter-password on-enter-password
:button-icon-left auth-button-icon-left
:button-label auth-button-label}])}]))))))
(defn- view-internal
[_]
(let [reset-slider? (reagent/atom false)
on-close #(reset! reset-slider? true)]
(fn [{:keys [biometric-auth?
track-text
customization-color
auth-button-label
on-enter-password
on-auth-success
on-auth-fail
auth-button-icon-left
size
theme
blur?
container-style]}]
[rn/view {:style {:flex 1}}
[quo/slide-button
{:size size
:container-style container-style
:customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:on-enter-password on-enter-password
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label})
:track-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]])))
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,44 @@
(ns status-im2.common.standard-authentication.standard-auth.button.view
(:require
[quo.core :as quo]
[quo.theme :as quo.theme]
[reagent.core :as reagent]
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]))
(defn- view-internal
[_]
(let [reset-slider? (reagent/atom false)
on-close #(reset! reset-slider? true)]
(fn [{:keys [biometric-auth?
customization-color
auth-button-label
on-enter-password
on-auth-success
on-press
on-auth-fail
auth-button-icon-left
size
button-label
theme
blur?
container-style
icon-left]}]
[quo/button
{:size size
:container-style container-style
:customization-color customization-color
:icon-left icon-left
:on-press (if on-press
on-press
#(authorize/authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:on-enter-password on-enter-password
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label}))}
button-label])))
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,43 @@
(ns status-im2.common.standard-authentication.standard-auth.slide-button.view
(:require
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.standard-authentication.standard-auth.authorize :as authorize]))
(defn- view-internal
[_]
(let [reset-slider? (reagent/atom false)
on-close #(reset! reset-slider? true)]
(fn [{:keys [biometric-auth?
track-text
customization-color
auth-button-label
on-enter-password
on-auth-success
on-auth-fail
auth-button-icon-left
size
theme
blur?
container-style]}]
[rn/view {:style {:flex 1}}
[quo/slide-button
{:size size
:container-style container-style
:customization-color customization-color
:on-reset (when @reset-slider? #(reset! reset-slider? false))
:on-complete #(authorize/authorize {:on-close on-close
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
:on-enter-password on-enter-password
:biometric-auth? biometric-auth?
:on-auth-success on-auth-success
:on-auth-fail on-auth-fail
:auth-button-label auth-button-label})
:track-icon (if biometric-auth? :i/face-id :password)
:track-text track-text}]])))
(def view (quo.theme/with-theme view-internal))
@@ -1,15 +1,20 @@
(ns status-im2.contexts.onboarding.enable-biometrics.view
(:require
[quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im2.common.biometric.events :as biometric]
[status-im2.common.parallax.view :as parallax]
[status-im2.common.parallax.whitelist :as whitelist]
[status-im2.common.resources :as resources]
[status-im2.common.standard-authentication.core :as standard-auth]
[status-im2.contexts.onboarding.enable-biometrics.style :as style]
[status-im2.navigation.state :as state]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn page-title
[]
@@ -21,22 +26,39 @@
:description-accessibility-label :enable-biometrics-sub-title}])
(defn enable-biometrics-buttons
[insets]
[insets theme]
(let [supported-biometric-type (rf/sub [:biometric/supported-type])
bio-type-label (biometric/get-label-by-type supported-biometric-type)
profile-color (:color (rf/sub [:onboarding-2/profile]))]
profile-color (or (:color (rf/sub [:onboarding-2/profile]))
(rf/sub [:profile/customization-color]))
syncing-results? (= :syncing-results @state/root-id)]
[rn/view {:style (style/buttons insets)}
[quo/button
{:accessibility-label :enable-biometrics-button
:on-press #(rf/dispatch [:onboarding-2/enable-biometrics])
:icon-left :i/face-id
:customization-color profile-color}
(i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})]
[standard-auth/button
(merge
{:size 40
:accessibility-label :enable-biometrics-button
:icon-left :i/face-id
:customization-color profile-color
:button-label (i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})}
(if syncing-results?
{:theme theme
:blur? true
:on-enter-password (fn [entered-password]
(rf/dispatch
[:onboarding-2/authenticate-enable-biometrics
(security/safe-unmask-data
entered-password)])
(rf/dispatch [:hide-bottom-sheet]))
:auth-button-label (i18n/label :t/confirm)}
{:on-press #(rf/dispatch [:onboarding-2/enable-biometrics])}))]
[quo/button
{:accessibility-label :maybe-later-button
:background :blur
:type :grey
:on-press #(rf/dispatch [:onboarding-2/create-account-and-login])
:on-press #(rf/dispatch (if syncing-results?
[:navigate-to-within-stack
[:enable-notifications :enable-biometrics]]
[:onboarding-2/create-account-and-login]))
:container-style {:margin-top 12}}
(i18n/label :t/maybe-later)]]))
@@ -55,12 +77,19 @@
:style (style/page-illustration width)
:source (resources/get-image :biometrics)}]))
(defn enable-biometrics
[]
(defn f-enable-biometrics
[{:keys [theme]}]
(let [insets (safe-area/get-insets)]
[rn/view {:style (style/page-container insets)}
[page-title]
(if whitelist/whitelisted?
[enable-biometrics-parallax]
[enable-biometrics-simple])
[enable-biometrics-buttons insets]]))
[enable-biometrics-buttons insets theme]]))
(defn- internale-enable-biometrics
[params]
[:f> f-enable-biometrics params])
(def view (quo.theme/with-theme internale-enable-biometrics))
@@ -51,7 +51,7 @@
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back-within-stack :new-to-status])}]
:on-press #(rf/dispatch [:navigate-back-within-stack :enable-biometrics])}]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
+34 -3
View File
@@ -35,11 +35,30 @@
{:biometric/authenticate {:on-success #(rf/dispatch [:onboarding-2/biometrics-done])
:on-fail #(rf/dispatch [:onboarding-2/biometrics-fail %])}})
(rf/defn authenticate-enable-biometrics
{:events [:onboarding-2/authenticate-enable-biometrics]}
[{:keys [db]} password]
{:db (-> db
(assoc-in [:onboarding-2/profile :password] password)
(assoc-in [:onboarding-2/profile :syncing?] true))
:biometric/authenticate {:on-success #(rf/dispatch [:onboarding-2/biometrics-done])
:on-fail #(rf/dispatch [:onboarding-2/biometrics-fail %])}})
(rf/defn navigate-to-enable-notifications
{:events [:onboarding-2/navigate-to-enable-notifications]}
[{:keys [db]}]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:db (dissoc db :onboarding-2/profile)
:dispatch [:navigate-to-within-stack [:enable-notifications :enable-biometrics]]}))
(rf/defn biometrics-done
{:events [:onboarding-2/biometrics-done]}
[{:keys [db]}]
{:db (assoc-in db [:onboarding-2/profile :auth-method] constants/auth-method-biometric)
:dispatch [:onboarding-2/create-account-and-login]})
(let [syncing? (get-in db [:onboarding-2/profile :syncing?])]
{:db (assoc-in db [:onboarding-2/profile :auth-method] constants/auth-method-biometric)
:dispatch (if syncing?
[:onboarding-2/finalize-setup]
[:onboarding-2/create-account-and-login])}))
(rf/defn biometrics-fail
{:events [:onboarding-2/biometrics-fail]}
@@ -83,6 +102,14 @@
[:navigate-to-within-stack [:enable-biometrics :new-to-status]]
[:onboarding-2/create-account-and-login])}))
(rf/defn navigate-to-enable-biometrics
{:events [:onboarding-2/navigate-to-enable-biometrics]}
[{:keys [db]}]
(let [supported-type (:biometric/supported-type db)]
{:dispatch (if supported-type
[:open-modal :enable-biometrics]
[:open-modal :enable-notifications])}))
(rf/defn seed-phrase-entered
{:events [:onboarding-2/seed-phrase-entered]}
[_ seed-phrase on-error]
@@ -120,6 +147,7 @@
[{:keys [db]}]
(let [masked-password (get-in db [:onboarding-2/profile :password])
key-uid (get-in db [:profile/profile :key-uid])
syncing? (get-in db [:onboarding-2/profile :syncing?])
biometric-enabled? (= (get-in db [:onboarding-2/profile :auth-method])
constants/auth-method-biometric)]
(cond-> {:db (assoc db :onboarding-2/generated-keys? true)}
@@ -127,7 +155,10 @@
(assoc :keychain/save-password-and-auth-method
{:key-uid key-uid
:masked-password masked-password
:on-success #(log/debug "successfully saved biometric")
:on-success (fn []
(if syncing?
(rf/dispatch [:onboarding-2/navigate-to-enable-notifications])
(log/error "successfully saved biometrics")))
:on-error #(log/error "failed to save biometrics"
{:key-uid key-uid
:error %})}))))
@@ -54,7 +54,7 @@
{:on-press (fn []
(when on-press
(on-press))
(rf/dispatch [:open-modal :enable-notifications]))
(rf/dispatch [:onboarding-2/navigate-to-enable-biometrics]))
:accessibility-label :continue-button
:customization-color profile-color
:container-style style/continue-button}
@@ -73,12 +73,12 @@
(data-store.settings/rpc->settings settings)
profile-overview (profile.rpc/rpc->profiles-overview account)]
(rf/merge cofx
{:db (-> db
(assoc :chats/loading? true
:networks/current-network current-network
:networks/networks (merge networks config/default-networks-by-id)
:profile/profile (merge profile-overview settings))
(assoc-in [:wallet :ui :tokens-loading?] true))}
{:db (assoc db
:chats/loading? true
:networks/current-network current-network
:wallet/tokens-loading? true
:networks/networks (merge networks config/default-networks-by-id)
:profile/profile (merge profile-overview settings))}
(notifications/load-preferences)
(data-store.chats/fetch-chats-preview
{:on-success
@@ -153,7 +153,6 @@
[status-im2.contexts.quo-preview.tags.number-tag :as number-tag]
[status-im2.contexts.quo-preview.tags.permission-tag :as permission-tag]
[status-im2.contexts.quo-preview.tags.status-tags :as status-tags]
[status-im2.contexts.quo-preview.tags.summary-tag :as summary-tag]
[status-im2.contexts.quo-preview.tags.tag :as tag]
[status-im2.contexts.quo-preview.tags.tags :as tags]
[status-im2.contexts.quo-preview.tags.tiny-tag :as tiny-tag]
@@ -434,8 +433,6 @@
:component permission-tag/view}
{:name :status-tags
:component status-tags/view}
{:name :summary-tag
:component summary-tag/view}
{:name :tag
:component tag/view}
{:name :tags
@@ -1,66 +0,0 @@
(ns status-im2.contexts.quo-preview.tags.summary-tag
(:require
[quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]))
(defn data
[type]
(case type
:token
{:customization-color "#9999991A"
:label "150 ETH"
:image-source (quo.resources/get-token :eth)}
:address
{:label "0x39c...Bd2"}
:user
{:image-source (resources/mock-images :user-picture-male4)
:customization-color :blue
:label "Mark Libot"}
:collectible
{:label "Isekai #1"
:image-source (resources/mock-images :collectible2)
:customization-color :yellow}
:network
{:image-source (quo.resources/get-network :ethereum)
:label "Mainnet"}
:saved-address
{:customization-color :flamingo
:label "Peter Lambo"}
:account
{:label "Account"
:emoji "🍿"
:customization-color :purple}))
(def descriptor
[{:key :type
:type :select
:options [{:value "Token"
:key :token}
{:value "Address"
:key :address}
{:value "User"
:key :user}
{:value "Collectible"
:key :collectible}
{:value "Network"
:key :network}
{:value "Saved address"
:key :saved-address}
{:value "Account"
:key :account}]}])
(defn view
[]
(let [state (reagent/atom
(merge {:type :token}
(data :token)))]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor}
[rn/view {:style {:align-items :center}}
[quo/summary-tag (merge @state (data (:type @state)))]]])))
@@ -8,7 +8,7 @@
[reagent.core :as reagent]
[status-im2.common.qr-codes.view :as qr-codes]
[status-im2.common.resources :as resources]
[status-im2.common.standard-authentication.standard-auth.view :as standard-auth]
[status-im2.common.standard-authentication.core :as standard-auth]
[status-im2.contexts.syncing.setup-syncing.style :as style]
[status-im2.contexts.syncing.utils :as sync-utils]
[utils.datetime :as datetime]
@@ -119,7 +119,7 @@
(i18n/label :t/copy-qr)]])
(when-not (sync-utils/valid-connection-string? @code)
[rn/view {:style style/standard-auth}
[standard-auth/view
[standard-auth/slide-button
{:blur? true
:size :size-40
:track-text (i18n/label :t/slide-to-reveal-code)
@@ -1,12 +1,22 @@
(ns status-im2.contexts.wallet.common.utils
(:require [clojure.string :as string]
[status-im2.constants :as constants]
[utils.number]))
[status-im2.constants :as constants]))
(defn get-first-name
[full-name]
(first (string/split full-name #" ")))
(defn get-balance-by-address
[balances address]
(->> balances
(filter #(= (:address %) address))
first
:balance))
(defn get-account-by-address
[accounts address]
(some #(when (= (:address %) address) %) accounts))
(defn prettify-balance
[balance]
(str "$" (.toFixed (if (number? balance) balance 0) 2)))
@@ -22,24 +32,3 @@
[number-of-accounts]
(let [path (get-derivation-path number-of-accounts)]
(format-derivation-path path)))
(defn- calculate-raw-balance
[raw-balance decimals]
(if-let [n (utils.number/parse-int raw-balance nil)]
(/ n (Math/pow 10 (utils.number/parse-int decimals)))
0))
(defn- total-token-value-in-all-chains
[{:keys [balances-per-chain decimals]}]
(->> balances-per-chain
(vals)
(map #(calculate-raw-balance (:raw-balance %) decimals))
(reduce +)))
(defn calculate-balance
[tokens-in-account]
(->> tokens-in-account
(map (fn [token]
(* (total-token-value-in-all-chains token)
(-> token :market-values-per-currency :usd :price))))
(reduce +)))
@@ -7,7 +7,7 @@
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.common.standard-authentication.standard-auth.view :as standard-auth]
[status-im2.common.standard-authentication.core :as standard-auth]
[status-im2.constants :as constants]
[status-im2.contexts.emoji-picker.utils :as emoji-picker.utils]
[status-im2.contexts.wallet.common.utils :as utils]
@@ -114,7 +114,7 @@
{:list-type :settings
:label (i18n/label :t/origin)
:data (get-keypair-data primary-name @derivation-path @account-color)}]
[standard-auth/view
[standard-auth/slide-button
{:size :size-48
:track-text (i18n/label :t/slide-to-create-account)
:customization-color @account-color
@@ -4,33 +4,29 @@
[quo.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.wallet.common.screen-base.create-or-edit-account.view
:as create-or-edit-account]
[status-im2.contexts.wallet.common.sheets.network-preferences.view
:as network-preferences]
[status-im2.contexts.wallet.common.screen-base.create-or-edit-account.view :as
create-or-edit-account]
[status-im2.contexts.wallet.common.sheets.network-preferences.view :as network-preferences]
[status-im2.contexts.wallet.edit-account.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- show-save-account-toast
[updated-key theme]
(let [message (case updated-key
:name :t/edit-wallet-account-name-updated-message
:color :t/edit-wallet-account-colour-updated-message
:emoji :t/edit-wallet-account-emoji-updated-message
nil)]
(rf/dispatch [:toasts/upsert
{:id :edit-account
:icon :i/correct
:icon-color (colors/resolve-color :success theme)
:text (i18n/label message)}])))
(defn- save-account
[{:keys [account updated-key new-value theme]}]
(let [edited-account-data (assoc account updated-key new-value)]
[{:keys [theme type value account]}]
(let [edited-account-data (assoc account type value)
message (case type
:name :t/edit-wallet-account-name-updated-message
:color :t/edit-wallet-account-colour-updated-message
:emoji :t/edit-wallet-account-emoji-updated-message
nil)
callback #(rf/dispatch [:toasts/upsert
{:id :edit-account
:icon :i/correct
:icon-color (colors/resolve-color :success theme)
:text (i18n/label message)}])]
(rf/dispatch [:wallet/save-account
{:account edited-account-data
:on-success #(show-save-account-toast updated-key theme)}])))
{:account edited-account-data
:callback callback}])))
(defn- view-internal
[{:keys [theme]}]
@@ -38,22 +34,22 @@
show-confirm-button? (reagent/atom false)
on-change-color (fn [edited-color {:keys [color] :as account}]
(when (not= edited-color color)
(save-account {:account account
:updated-key :color
:new-value edited-color
:theme theme})))
(save-account {:account account
:type :color
:value edited-color
:theme theme})))
on-change-emoji (fn [edited-emoji {:keys [emoji] :as account}]
(when (not= edited-emoji emoji)
(save-account {:account account
:updated-key :emoji
:new-value edited-emoji
:theme theme})))
(save-account {:account account
:type :emoji
:value edited-emoji
:theme theme})))
on-confirm-name (fn [account]
(rn/dismiss-keyboard!)
(save-account {:account account
:updated-key :name
:new-value @edited-account-name
:theme theme}))]
(save-account {:account account
:type :name
:value @edited-account-name
:theme theme}))]
(fn []
(let [{:keys [name emoji address color]
:as account} (rf/sub [:wallet/current-viewing-account])
@@ -86,18 +82,17 @@
:right-icon :i/advanced
:card? true
:title (i18n/label :t/address)
:custom-subtitle (fn []
[quo/address-text
{:networks [{:network-name :ethereum :short-name "eth"}
{:network-name :optimism :short-name "opt"}
{:network-name :arbitrum :short-name "arb1"}]
:address address
:format :long}])
:custom-subtitle (fn [] [quo/address-text
{:networks [{:network-name :ethereum :short-name "eth"}
{:network-name :optimism :short-name "opt"}
{:network-name :arbitrum :short-name "arb1"}]
:address address
:format :long}])
:on-press (fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn []
[network-preferences/view
{:on-save #(js/alert "calling on save")}])}]))
{:content (fn [] [network-preferences/view
{:on-save #(js/alert
"calling on save")}])}]))
:container-style style/data-item}]]))))
(def view (quo.theme/with-theme view-internal))
+18 -43
View File
@@ -11,7 +11,6 @@
[taoensso.timbre :as log]
[utils.ethereum.chain :as chain]
[utils.i18n :as i18n]
[utils.number]
[utils.re-frame :as rf]
[utils.security.core :as security]
[utils.transforms :as types]))
@@ -41,8 +40,7 @@
{:db (update db :wallet dissoc :current-viewing-account-address)
:fx [[:dispatch [:navigate-back]]]}))
(rf/reg-event-fx
:wallet/get-accounts-success
(rf/reg-event-fx :wallet/get-accounts-success
(fn [{:keys [db]} [accounts]]
(let [wallet-db (get db :wallet)
new-account? (:new-account? wallet-db)
@@ -63,8 +61,7 @@
{:dispatch [:wallet/navigate-to-account navigate-to-account]
:ms 300}]])))))
(rf/reg-event-fx
:wallet/get-accounts
(rf/reg-event-fx :wallet/get-accounts
(fn [_]
{:fx [[:json-rpc/call
[{:method "accounts_getAccounts"
@@ -75,54 +72,35 @@
(rf/reg-event-fx
:wallet/save-account
(fn [_ [{:keys [account on-success]}]]
(fn [_ [{:keys [account callback]}]]
{:fx [[:json-rpc/call
[{:method "accounts_saveAccount"
:params [(data-store/<-account account)]
:on-success (fn []
(rf/dispatch [:wallet/get-accounts])
(when (fn? on-success)
(on-success)))
(when (fn? callback)
(callback)))
:on-error #(log/info "failed to save account "
{:error %
:event :wallet/save-account})}]]]}))
(rf/reg-event-fx
:wallet/get-wallet-token
(rf/reg-event-fx :wallet/get-wallet-token
(fn [{:keys [db]}]
(let [addresses (->> (get-in db [:wallet :accounts])
vals
(map :address))]
(let [addresses (map :address (vals (get-in db [:wallet :accounts])))]
{:fx [[:json-rpc/call
[{:method "wallet_getWalletToken"
:params [addresses]
:on-success [:wallet/store-wallet-token]
:on-success [:wallet/get-wallet-token-success]
:on-error #(log/info "failed to get wallet token "
{:error %
:event :wallet/get-wallet-token
:params addresses})}]]]})))
(defn- fix-chain-id-keys
[token]
(update token :balances-per-chain update-keys (comp utils.number/parse-int name)))
(rf/reg-event-fx
:wallet/store-wallet-token
(fn [{:keys [db]} [raw-tokens-data]]
(let [tokens (-> raw-tokens-data
(update-keys name)
(update-vals #(cske/transform-keys csk/->kebab-case %))
(update-vals #(mapv fix-chain-id-keys %)))
add-tokens (fn [stored-accounts tokens-per-account]
(reduce-kv (fn [accounts address tokens-data]
(if (accounts address)
(update accounts address assoc :tokens tokens-data)
accounts))
stored-accounts
tokens-per-account))]
{:db (-> db
(update-in [:wallet :accounts] add-tokens tokens)
(assoc-in [:wallet :ui :tokens-loading?] false))})))
(rf/reg-event-fx :wallet/get-wallet-token-success
(fn [{:keys [db]} [tokens]]
{:db (assoc db
:wallet/tokens tokens
:wallet/tokens-loading? false)}))
(rf/defn scan-address-success
{:events [:wallet/scan-address-success]}
@@ -144,8 +122,7 @@
:on-success on-success
:on-error #(log/info "failed to derive address " %)}]]]})))
(rf/reg-event-fx
:wallet/add-account
(rf/reg-event-fx :wallet/add-account
(fn [{:keys [db]} [password {:keys [emoji account-name color]} {:keys [public-key address path]}]]
(let [key-uid (get-in db [:profile/profile :key-uid])
sha3-pwd (native-module/sha3 (security/safe-unmask-data password))
@@ -169,12 +146,11 @@
:on-success [:wallet/get-accounts]
:on-error #(log/info "failed to create account " %)}]]]})))
(rf/reg-event-fx
:wallet/derive-address-and-add-account
(rf/reg-event-fx :wallet/derive-address-and-add-account
(fn [_ [password account-details]]
(let [on-success (fn [derived-address-details]
(let [on-success (fn [derived-adress-details]
(rf/dispatch [:wallet/add-account password account-details
(first derived-address-details)]))]
(first derived-adress-details)]))]
{:fx [[:dispatch [:wallet/create-derived-addresses password account-details on-success]]]})))
(rf/defn get-ethereum-chains
@@ -223,8 +199,7 @@
(rf/reg-event-fx :wallet/clear-stored-collectibles clear-stored-collectibles)
(rf/reg-event-fx
:wallet/request-collectibles
(rf/reg-event-fx :wallet/request-collectibles
(fn [{:keys [db]} [{:keys [start-at-index new-request?]}]]
(let [request-id 0
collectibles-filter nil
+31 -8
View File
@@ -8,6 +8,7 @@
[status-im2.contexts.wallet.common.activity-tab.view :as activity]
[status-im2.contexts.wallet.common.collectibles-tab.view :as collectibles]
[status-im2.contexts.wallet.common.temp :as temp]
[status-im2.contexts.wallet.common.utils :as utils]
[status-im2.contexts.wallet.home.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -27,9 +28,9 @@
:on-press #(rf/dispatch [:navigate-to :add-address-to-watch])
:add-divider? true}]]])
(defn- new-account-card-data
[]
{:customization-color (rf/sub [:profile/customization-color])
(defn- add-account-placeholder
[color]
{:customization-color color
:on-press #(rf/dispatch [:show-bottom-sheet {:content new-account}])
:type :add-account})
@@ -38,6 +39,21 @@
{:id :collectibles :label (i18n/label :t/collectibles) :accessibility-label :collectibles-tab}
{:id :activity :label (i18n/label :t/activity) :accessibility-label :activity-tab}])
(defn account-cards
[{:keys [accounts loading? balances profile-color]}]
(let [accounts-with-balances
(mapv
(fn [{:keys [color address] :as account}]
(assoc account
:customization-color color
:type :empty
:on-press #(rf/dispatch [:wallet/navigate-to-account address])
:loading? loading?
:balance (utils/prettify-balance
(utils/get-balance-by-address balances address))))
accounts)]
(conj accounts-with-balances (add-account-placeholder profile-color))))
(defn view
[]
(rf/dispatch [:wallet/request-collectibles
@@ -46,10 +62,14 @@
(let [top (safe-area/get-top)
selected-tab (reagent/atom (:id (first tabs-data)))]
(fn []
(let [networks (rf/sub [:wallet/network-details])
account-cards-data (rf/sub [:wallet/account-cards-data])
cards (conj account-cards-data (new-account-card-data))]
[rn/view {:style {:margin-top top :flex 1}}
(let [accounts (rf/sub [:wallet/accounts])
loading? (rf/sub [:wallet/tokens-loading?])
balances (rf/sub [:wallet/balances])
profile-color (rf/sub [:profile/customization-color])
networks (rf/sub [:wallet/network-details])]
[rn/view
{:style {:margin-top top
:flex 1}}
[common.top-nav/view]
[rn/view {:style style/overview-container}
[quo/wallet-overview (temp/wallet-overview-state networks)]]
@@ -60,7 +80,10 @@
[rn/flat-list
{:style style/accounts-list
:content-container-style style/accounts-list-container
:data cards
:data (account-cards {:accounts accounts
:loading? loading?
:balances balances
:profile-color profile-color})
:horizontal true
:separator [rn/view {:style {:width 12}}]
:render-fn quo/account-card
@@ -1,4 +1,4 @@
(ns status-im2.integration-test.chat-test
(ns status-im2.integration-test.chat
(:require
[cljs.test :refer [deftest is]]
[day8.re-frame.test :as rf-test]
@@ -16,7 +16,7 @@
"0x0402905bed83f0bbf993cee8239012ccb1a8bc86907ead834c1e38476a0eda71414eed0e25f525f270592a2eebb01c9119a4ed6429ba114e51f5cb0a28dae1adfd")
(deftest one-to-one-chat-test
(h/log-headline :one-to-one-chat-test)
(h/log-headline one-to-one-chat-test)
(rf-test/run-test-async
(h/with-app-initialized
(h/with-account
@@ -1,4 +1,4 @@
(ns status-im2.integration-test.community-test
(ns status-im2.integration-test.community
(:require [cljs.test :refer [deftest]]
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
@@ -1,4 +1,4 @@
(ns status-im2.integration-test.core-test
(ns status-im2.integration-test.core
(:require
[cljs.test :refer [deftest]]
[day8.re-frame.test :as rf-test]
@@ -8,14 +8,17 @@
status-im.subs.root
[status-im.utils.test :as utils.test]
status-im2.events
status-im2.integration-test.chat
status-im2.integration-test.wallet
status-im2.navigation.core
status-im2.subs.root
[test-helpers.integration :as h]))
(utils.test/init!)
(deftest initialize-app-test
(h/log-headline :initialize-app-test)
(rf-test/run-test-async
(utils.test/init!)
(rf/dispatch [:app-started])
(rf-test/wait-for
;; use initialize-view because it has the longest avg. time and
@@ -1,6 +1,6 @@
(ns status-im2.integration-test.wallet-test
(ns status-im2.integration-test.wallet
(:require
[cljs.test :refer [is]]
[cljs.test :refer [deftest is]]
[clojure.string :as string]
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
@@ -12,9 +12,7 @@
status-im2.subs.root
[test-helpers.integration :as h]))
;; Workaround to skip test. Switch to `deftest` when test is fixed.
(defn create-wallet-account-test
[]
(deftest create-wallet-account-test
(h/log-headline :create-wallet-account-test)
(rf-test/run-test-async
(h/with-app-initialized
@@ -26,9 +24,7 @@
(h/logout)
(rf-test/wait-for [::logout/logout-method]))))))
;; Workaround to skip test. Switch to `deftest` when test is fixed.
(defn back-up-seed-phrase-test
[]
(deftest back-up-seed-phrase-test
(h/log-headline :back-up-seed-phrase-test)
(rf-test/run-test-async
(h/with-app-initialized
+9 -5
View File
@@ -161,11 +161,15 @@
:component create-password/create-password}
{:name :enable-biometrics
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations transitions/push-animations-for-transparent-background
:popGesture false}
:component enable-biometrics/enable-biometrics}
:options {:theme :dark
:layout options/onboarding-transparent-layout
:animations (merge transitions/new-to-status-modal-animations
transitions/push-animations-for-transparent-background)
:popGesture false
:modalPresentationStyle :overCurrentContext
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false}}
:component enable-biometrics/view}
{:name :generating-keys
:options {:theme :dark
+4
View File
@@ -145,6 +145,10 @@
(reg-root-key-sub :communities/selected-tab :communities/selected-tab)
(reg-root-key-sub :contract-communities :contract-communities)
;;wallet
(reg-root-key-sub :wallet/tokens :wallet/tokens)
(reg-root-key-sub :wallet/tokens-loading? :wallet/tokens-loading?)
;;activity center
(reg-root-key-sub :activity-center :activity-center)
+35 -31
View File
@@ -1,19 +1,36 @@
(ns status-im2.subs.wallet.wallet
(:require [re-frame.core :as rf]
(:require [re-frame.core :as re-frame]
[status-im2.contexts.wallet.common.utils :as utils]
[utils.number]))
(rf/reg-sub
:wallet/ui
:<- [:wallet]
:-> :ui)
(defn- calculate-raw-balance
[raw-balance decimals]
(if-let [n (utils.number/parse-int raw-balance nil)]
(/ n (Math/pow 10 (utils.number/parse-int decimals)))
0))
(rf/reg-sub
:wallet/tokens-loading?
:<- [:wallet/ui]
:-> :tokens-loading?)
(defn- total-per-token
[item]
(reduce (fn [ac balances]
(+ (calculate-raw-balance (:rawBalance balances)
(:decimals item))
ac))
0
(vals (:balancesPerChain item))))
(rf/reg-sub
(defn- calculate-balance
[address tokens]
(let [token (get tokens (keyword address))
result (reduce
(fn [acc item]
(let [total-values (* (total-per-token item)
(get-in item [:marketValuesPerCurrency :USD :price]))]
(+ acc total-values)))
0
token)]
result))
(re-frame/reg-sub
:wallet/accounts
:<- [:wallet]
:-> #(->> %
@@ -21,33 +38,20 @@
vals
(sort-by :position)))
(rf/reg-sub
(re-frame/reg-sub
:wallet/balances
:<- [:wallet/accounts]
(fn [accounts]
(zipmap (map :address accounts)
(map #(-> % :tokens utils/calculate-balance) accounts))))
:<- [:wallet/tokens]
(fn [[accounts tokens]]
(for [{:keys [address]} accounts]
{:address address
:balance (calculate-balance address tokens)})))
(rf/reg-sub
:wallet/account-cards-data
:<- [:wallet/accounts]
:<- [:wallet/balances]
:<- [:wallet/tokens-loading?]
(fn [[accounts balances tokens-loading?]]
(mapv (fn [{:keys [color address] :as account}]
(assoc account
:customization-color color
:type :empty
:on-press #(rf/dispatch [:wallet/navigate-to-account address])
:loading? tokens-loading?
:balance (utils/prettify-balance (get balances address))))
accounts)))
(rf/reg-sub
(re-frame/reg-sub
:wallet/current-viewing-account
:<- [:wallet]
:<- [:wallet/balances]
(fn [[{:keys [current-viewing-account-address] :as wallet} balances]]
(-> wallet
(get-in [:accounts current-viewing-account-address])
(assoc :balance (get balances current-viewing-account-address)))))
(assoc :balance (utils/get-balance-by-address balances current-viewing-account-address)))))
+92 -83
View File
@@ -8,35 +8,43 @@
(use-fixtures :each
{:before #(reset! rf-db/app-db {})})
(def tokens-0x1
[{:decimals 1
:symbol "ETH"
:name "Ether"
:balances-per-chain {1 {:raw-balance "20" :has-error false}
2 {:raw-balance "10" :has-error false}}
:market-values-per-currency {:usd {:price 1000}}}
{:decimals 2
:symbol "DAI"
:name "Dai Stablecoin"
:balances-per-chain {1 {:raw-balance "100" :has-error false}
2 {:raw-balance "150" :has-error false}}
:market-values-per-currency {:usd {:price 100}}}])
(def tokens-0x2
[{:decimals 3
:symbol "ETH"
:name "Ether"
:balances-per-chain {1 {:raw-balance "2500" :has-error false}
2 {:raw-balance "3000" :has-error false}
3 {:raw-balance "<nil>" :has-error false}}
:market-values-per-currency {:usd {:price 200}}}
{:decimals 10
:symbol "DAI"
:name "Dai Stablecoin"
:balances-per-chain {1 {:raw-balance "10000000000" :has-error false}
2 {:raw-balance "0" :has-error false}
3 {:raw-balance "<nil>" :has-error false}}
:market-values-per-currency {:usd {:price 1000}}}])
(def tokens
{:0x1 [{:decimals 1
:symbol "ETH"
:name "Ether"
:balancesPerChain {:1 {:rawBalance "20"
:hasError false}
:2 {:rawBalance "10"
:hasError false}}
:marketValuesPerCurrency {:USD {:price 1000}}} ;; total should be 3000
{:decimals 2
:symbol "DAI"
:name "Dai Stablecoin"
:balancesPerChain {:1 {:rawBalance "100"
:hasError false}
:2 {:rawBalance "150"
:hasError false}}
:marketValuesPerCurrency {:USD {:price 100}}}] ;; total should be 250
:0x2 [{:decimals 3
:symbol "ETH"
:name "Ether"
:balancesPerChain {:1 {:rawBalance "2500"
:hasError false}
:2 {:rawBalance "3000"
:hasError false}
:3 {:rawBalance "<nil>"
:hasError false}}
:marketValuesPerCurrency {:USD {:price 200}}} ;; total should be 1100
{:decimals 10
:symbol "DAI"
:name "Dai Stablecoin"
:balancesPerChain {:1 {:rawBalance "10000000000"
:hasError false}
:2 {:rawBalance "0"
:hasError false}
:3 {:rawBalance "<nil>"
:hasError false}}
:marketValuesPerCurrency {:USD {:price 1000}}}]}) ;; total should be 1000
(def accounts
{"0x1" {:path "m/44'/60'/0'/0/0"
@@ -57,8 +65,7 @@
:operable "fully"
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false
:tokens tokens-0x1}
:removed false}
"0x2" {:path "m/44'/60'/0'/0/1"
:emoji "💎"
:key-uid "0x2f5ea39"
@@ -77,63 +84,66 @@
:operable "fully"
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false
:tokens tokens-0x2}})
:removed false}})
(h/deftest-sub :wallet/balances
[sub-name]
(testing "a map: address->balance"
(swap! rf-db/app-db #(assoc-in % [:wallet :accounts] accounts))
(is (= {"0x1" 3250 "0x2" 2100}
(testing "returns seq of maps containing :address and :balance"
(swap! rf-db/app-db #(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc :wallet/tokens tokens)))
(is (= `({:address "0x1"
:balance 3250}
{:address "0x2"
:balance 2100})
(rf/sub [sub-name])))))
(h/deftest-sub :wallet/accounts
[sub-name]
(testing "returns all accounts without balance"
(swap! rf-db/app-db #(assoc-in % [:wallet :accounts] accounts))
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc :wallet/tokens tokens)))
(is
(= (list {:path "m/44'/60'/0'/0/0"
:emoji "😃"
:key-uid "0x2f5ea39"
:address "0x1"
:wallet false
:name "Account One"
:type :generated
:chat false
:test-preferred-chain-ids #{5 420 421613}
:color :blue
:hidden false
:prod-preferred-chain-ids #{1 10 42161}
:position 0
:clock 1698945829328
:created-at 1698928839000
:operable "fully"
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false
:tokens tokens-0x1}
{:path "m/44'/60'/0'/0/1"
:emoji "💎"
:key-uid "0x2f5ea39"
:address "0x2"
:wallet false
:name "Account Two"
:type :generated
:chat false
:test-preferred-chain-ids #{5 420 421613}
:color :purple
:hidden false
:prod-preferred-chain-ids #{1 10 42161}
:position 1
:clock 1698945829328
:created-at 1698928839000
:operable "fully"
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false
:tokens tokens-0x2})
(= `({:path "m/44'/60'/0'/0/0"
:emoji "😃"
:key-uid "0x2f5ea39"
:address "0x1"
:wallet false
:name "Account One"
:type :generated
:chat false
:test-preferred-chain-ids #{5 420 421613}
:color :blue
:hidden false
:prod-preferred-chain-ids #{1 10 42161}
:position 0
:clock 1698945829328
:created-at 1698928839000
:operable "fully"
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false}
{:path "m/44'/60'/0'/0/1"
:emoji "💎"
:key-uid "0x2f5ea39"
:address "0x2"
:wallet false
:name "Account Two"
:type :generated
:chat false
:test-preferred-chain-ids #{5 420 421613}
:color :purple
:hidden false
:prod-preferred-chain-ids #{1 10 42161}
:position 1
:clock 1698945829328
:created-at 1698928839000
:operable "fully"
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false})
(rf/sub [sub-name])))))
(h/deftest-sub :wallet/current-viewing-account
@@ -142,8 +152,8 @@
(swap! rf-db/app-db
#(-> %
(assoc-in [:wallet :accounts] accounts)
(assoc-in [:wallet :current-viewing-account-address] "0x1")))
(assoc-in [:wallet :current-viewing-account-address] "0x1")
(assoc :wallet/tokens tokens)))
(is
(= {:path "m/44'/60'/0'/0/0"
:emoji "😃"
@@ -164,6 +174,5 @@
:mixedcase-address "0x7bcDfc75c431"
:public-key "0x04371e2d9d66b82f056bc128064"
:removed false
:balance 3250
:tokens tokens-0x1}
:balance 3250}
(rf/sub [sub-name])))))
+12 -12
View File
@@ -4,21 +4,21 @@
(defmacro with-app-initialized
[& body]
`(do
(status-im.utils.test/init!)
(if (test-helpers.integration/app-initialized)
(do ~@body)
(do
(rf/dispatch [:app-started])
(rf-test/wait-for [:profile/get-profiles-overview-success]
~@body)))))
`(if (app-initialized)
(do ~@body)
(do
(rf/dispatch [:app-started])
(rf-test/wait-for
[:profile/get-profiles-overview-success]
~@body))))
(defmacro with-account
[& body]
`(if (test-helpers.integration/messenger-started)
`(if (messenger-started)
(do ~@body)
(do
(test-helpers.integration/create-multiaccount!)
(rf-test/wait-for [:status-im.transport.core/messenger-started]
(test-helpers.integration/assert-messenger-started)
(create-multiaccount!)
(rf-test/wait-for
[:status-im.transport.core/messenger-started]
(assert-messenger-started)
~@body))))
-1
View File
@@ -1,5 +1,4 @@
(ns test-helpers.integration
(:require-macros [test-helpers.integration])
(:require
[cljs.test :refer [is]]
[native-module.core :as native-module]
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "fix/shards-pubsub-topic",
"commit-sha1": "e7d9f59db4ccbf2c301d5b8dd705943be8c73097",
"src-sha256": "0hwy10ycjgbh332h1fl5hyw8j9nds0idqk980svaj76ckgsi7dlv"
"version": "debug/resend-edits",
"commit-sha1": "f1d1726a4e12159013d72008c949fee77e48627c",
"src-sha256": "0yl33bsq7x59mp8s029qw00h0m5wfg28zk3r1w7zp3m6w4j34p3d"
}
+60 -85
View File
@@ -1,7 +1,7 @@
import os
import re
import signal
import requests
import urllib.request
from contextlib import contextmanager
from dataclasses import dataclass
from datetime import datetime
@@ -161,57 +161,6 @@ def is_uploaded():
return True
@contextmanager
def _upload_time_limit(seconds):
def signal_handler(signum, frame):
raise TimeoutError("Apk upload took more than %s seconds" % seconds)
signal.signal(signal.SIGALRM, signal_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
class UploadApkException(Exception):
pass
def _upload_and_check_response(apk_file_path):
with _upload_time_limit(600):
with open(apk_file_path, 'rb') as f:
resp = sauce.storage._session.request('post', '/v1/storage/upload', files={'payload': f})
try:
if resp['item']['name'] != test_suite_data.apk_name:
raise UploadApkException("Incorrect apk was uploaded to Sauce storage, response:\n%s" % resp)
except KeyError:
raise UploadApkException("Error when uploading apk to Sauce storage, response:\n%s" % resp)
def _upload_and_check_response_with_retries(apk_file_path, retries=3):
for _ in range(retries):
try:
_upload_and_check_response(apk_file_path)
break
except (ConnectionError, RemoteDisconnected):
sleep(10)
def _download_apk(url):
# Absolute path adde to handle CI runs.
apk_path = os.path.join(os.path.dirname(__file__), test_suite_data.apk_name)
print('Downloading: %s' % url)
try:
resp = requests.get(url)
resp.raise_for_status()
except requests.RequestException as err:
print(resp.text)
raise err
with open(apk_path, 'wb') as f:
f.write(resp.content)
return apk_path
def pytest_configure(config):
global option
option = config.option
@@ -231,49 +180,75 @@ def pytest_configure(config):
apibase = 'eu-central-1.saucelabs.com'
else:
raise NotImplementedError("Unknown SauceLabs datacenter")
global sauce
sauce = SauceLab('https://api.' + apibase + '/', sauce_username, sauce_access_key)
if config.getoption('log_steps'):
import logging
logging.basicConfig(level=logging.INFO)
if config.getoption('env') == 'api':
return
if config.getoption('env') != 'api':
test_suite_data.apk_name = ([i for i in [i for i in config.getoption('apk').split('/')
if '.apk' in i]])[0]
if is_master(config):
pr_number = config.getoption('pr_number')
if config.getoption('testrail_report'):
if pr_number:
run_number = len(testrail_report.get_runs(pr_number)) + 1
run_name = 'PR-%s run #%s' % (pr_number, run_number)
else:
run_name = test_suite_data.apk_name
testrail_report.add_run(run_name)
if pr_number:
from github import Github
repo = Github(github_token).get_user('status-im').get_repo('status-mobile')
pull = repo.get_pull(int(pr_number))
pull.get_commits()[0].create_status(state='pending', context='Mobile e2e tests',
description='e2e tests are running')
if config.getoption('env') == 'sauce':
if not is_uploaded():
def _upload_and_check_response(apk_file_path):
@contextmanager
def _upload_time_limit(seconds):
def signal_handler(signum, frame):
raise TimeoutError("Apk upload took more than %s seconds" % seconds)
test_suite_data.apk_name = ([i for i in [i for i in config.getoption('apk').split('/')
if '.apk' in i]])[0]
if not is_master(config):
return
signal.signal(signal.SIGALRM, signal_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
pr_number = config.getoption('pr_number')
if config.getoption('testrail_report'):
if pr_number:
run_number = len(testrail_report.get_runs(pr_number)) + 1
run_name = 'PR-%s run #%s' % (pr_number, run_number)
else:
run_name = test_suite_data.apk_name
testrail_report.add_run(run_name)
with _upload_time_limit(600):
class UploadApkException(Exception):
pass
if pr_number:
from github import Github
repo = Github(github_token).get_user('status-im').get_repo('status-mobile')
pull = repo.get_pull(int(pr_number))
pull.get_commits()[0].create_status(
state='pending',
context='Mobile e2e tests',
description='e2e tests are running'
)
with open(apk_file_path, 'rb') as f:
resp = sauce.storage._session.request('post', '/v1/storage/upload',
files={'payload': f})
try:
if resp['item']['name'] != test_suite_data.apk_name:
raise UploadApkException(
"Incorrect apk was uploaded to Sauce storage, response:\n%s" % resp)
except KeyError:
raise UploadApkException(
"Error when uploading apk to Sauce storage, response:\n%s" % resp)
if config.getoption('env') == 'sauce' and not is_uploaded():
apk_src = config.getoption('apk')
if apk_src.startswith('http'):
apk_path = _download_apk(apk_src)
else:
apk_path = apk_src
if 'http' in config.getoption('apk'):
# it works with just a file_name, but I've added full path because not sure how it'll behave on the remote run (Jenkins)
file_path, to_remove = os.path.join(os.path.dirname(__file__), test_suite_data.apk_name), True
urllib.request.urlretrieve(config.getoption('apk'),
filename=file_path) # if url is not valid it raises an error
else:
file_path, to_remove = config.getoption('apk'), False
_upload_and_check_response_with_retries(apk_path)
if apk_src.startswith('http'):
os.remove(apk_path)
for _ in range(3):
try:
_upload_and_check_response(apk_file_path=file_path)
break
except (ConnectionError, RemoteDisconnected):
sleep(10)
if to_remove:
os.remove(file_path)
def pytest_unconfigure(config):
@@ -158,20 +158,20 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
except Failed:
self.errors.append("Link message reaction is not shown for the sender")
# self.home_2.just_fyi("Check 'Open in Status' option")
# # url_to_open = 'http://status.im' # ToDo: enable when a bug with Status link is fixed
# url_to_open = 'https://coinmarketcap.com/'
# self.chat_1.send_message(url_to_open)
# chat_element = self.chat_2.chat_element_by_text(url_to_open)
# if chat_element.is_element_displayed(120):
# chat_element.click_on_link_inside_message_body()
# web_view = self.chat_2.open_in_status_button.click()
# # if not web_view.element_by_text('Private, Secure Communication').is_element_displayed(60):
# if not web_view.element_by_text_part(
# "Today's Cryptocurrency Prices by Market Cap").is_element_displayed(30):
# self.errors.append('URL was not opened from 1-1 chat')
# else:
# self.errors.append("Message with URL was not received") # ToDo: temp
self.home_2.just_fyi("Check 'Open in Status' option")
# url_to_open = 'http://status.im' # ToDo: enable when a bug with Status link is fixed
url_to_open = 'https://coinmarketcap.com/'
self.chat_1.send_message(url_to_open)
chat_element = self.chat_2.chat_element_by_text(url_to_open)
if chat_element.is_element_displayed(120):
chat_element.click_on_link_inside_message_body()
web_view = self.chat_2.open_in_status_button.click()
# if not web_view.element_by_text('Private, Secure Communication').is_element_displayed(60):
if not web_view.element_by_text_part(
"Today's Cryptocurrency Prices by Market Cap").is_element_displayed(30):
self.errors.append('URL was not opened from 1-1 chat')
else:
self.errors.append("Message with URL was not received")
self.errors.verify_no_errors()
@@ -293,7 +293,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
sent_time_variants = self.chat_2.convert_device_time_to_chat_timestamp()
if timestamp not in sent_time_variants:
self.errors.append(
'Timestamp on message %s does not correspond expected %s' % (timestamp, sent_time_variants))
'Timestamp on message %s does not correspond expected [%s]' % (timestamp, *sent_time_variants))
except NoSuchElementException:
self.errors.append("No timestamp on message %s" % messages[0])
for message in [messages[1], messages[2]]:
@@ -248,7 +248,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
self.home.just_fyi("Check that can login with different user")
self.home.reopen_app(sign_in=False)
self.sign_in.show_profiles_button.wait_and_click()
self.sign_in.show_profiles_button.click()
self.sign_in.element_by_text(self.username).click()
self.sign_in.sign_in()
self.home.communities_tab.click()
@@ -257,7 +257,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
self.home.just_fyi("Check that can remove user from logged out state")
self.home.reopen_app(sign_in=False)
self.sign_in.show_profiles_button.wait_and_click()
self.sign_in.show_profiles_button.click()
user_card = self.sign_in.get_user(username=self.username)
user_card.open_user_options()
self.sign_in.remove_profile_button.click()
@@ -267,7 +267,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
self.home.just_fyi("Check that removed user is not shown in the list anymore")
self.home.reopen_app(sign_in=False)
self.sign_in.show_profiles_button.wait_and_click()
self.sign_in.show_profiles_button.click()
if self.sign_in.element_by_text(self.username).is_element_displayed():
self.errors.append("Removed user is re-appeared after relogin!")