Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37c0daec34 | ||
|
|
676998b83b | ||
|
|
755ef19315 | ||
|
|
bc9b0f8c87 | ||
|
|
c8b063493b | ||
|
|
84a3fffe9f | ||
|
|
949e78a17e | ||
|
|
a821ec5a14 | ||
|
|
4648066ec7 | ||
|
|
e85bc539d3 | ||
|
|
c26d298573 | ||
|
|
cdde36ca28 |
@@ -36,4 +36,3 @@ SHOW_NOT_IMPLEMENTED_FEATURES=0
|
||||
ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=1
|
||||
SENTRY_ENVIRONMENT=ci-main
|
||||
|
||||
@@ -40,4 +40,3 @@ ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
MOBILE_DATA_SYNCING_TOGGLE_ENABLE=0
|
||||
API_LOGGING_ENABLED=1
|
||||
SENTRY_ENVIRONMENT=ci-main
|
||||
|
||||
@@ -37,4 +37,3 @@ TEST_NETWORKS_ENABLED=1
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=1
|
||||
SENTRY_ENVIRONMENT=ci-main
|
||||
|
||||
@@ -24,4 +24,3 @@ TEST_NETWORKS_ENABLED=0
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=0
|
||||
SENTRY_ENVIRONMENT=ci-nightly
|
||||
|
||||
@@ -21,4 +21,3 @@ TEST_NETWORKS_ENABLED=0
|
||||
STATUS_PROXY_STAGE_NAME=prod
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=0
|
||||
SENTRY_ENVIRONMENT=production
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.15'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -41,7 +41,6 @@ pipeline {
|
||||
BUILD_ENV = 'prod'
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
SENTRY_PRODUCTION = "${utils.isReleaseBuild() ? 'true' : 'false'}"
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.15'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.15'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -41,7 +41,6 @@ pipeline {
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
BUNDLE_PATH = "${HOME}/.bundle"
|
||||
SENTRY_PRODUCTION = "${utils.isReleaseBuild() ? 'true' : 'false'}"
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
@@ -150,7 +150,7 @@ This one is straightforward, just evaluate a navigation dispatch form from anywh
|
||||
|
||||
#### REPL-ing a component
|
||||
|
||||
This is also straighforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
|
||||
This is also straightforward, but there are some small differences. Just like above, we only have to evaluate a dispatch form, as follows:
|
||||
|
||||
```cljs
|
||||
;; example debugging a quo component, although it could be any other component e.g. from the `status-im2` ns.
|
||||
|
||||
@@ -26,4 +26,4 @@ These log files are uploaded to Jenkins as CI job artifacts on failure using `ar
|
||||
* `set_xcode_version.log` - Output from `node_modules/react-native/scripts/react-native-xcode.sh`.
|
||||
- Created by redirecting output of `shellScript` in `ios/StatusIm.xcodeproj/project.pbxproj` for "Run Script" build Phase.
|
||||
* `Status PR-StatusImPR.log - Created by [Fastlane Gym](https://docs.fastlane.tools/actions/gym/).
|
||||
- Configred via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
|
||||
- Configured via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
|
||||
|
||||
@@ -108,15 +108,6 @@ class StatusModule(private val reactContext: ReactApplicationContext, private va
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun intendedPanic(message: String) {
|
||||
StatusBackendClient.executeStatusGoRequest(
|
||||
endpoint = "IntendedPanic",
|
||||
requestBody = "",
|
||||
statusgoFunction = { Statusgo.intendedPanic(message) },
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun addCentralizedMetric(request: String, callback: Callback) {
|
||||
StatusBackendClient.executeStatusGoRequestWithCallback(
|
||||
|
||||
@@ -109,13 +109,6 @@ RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) {
|
||||
callback:callback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(intendedPanic:(NSString *)message) {
|
||||
#if DEBUG
|
||||
NSLog(@"IntendedPanic() method called");
|
||||
#endif
|
||||
StatusgoIntendedPanic(message);
|
||||
}
|
||||
|
||||
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(fleets) {
|
||||
return [StatusBackendClient executeStatusGoRequestWithResult:@"Fleets"
|
||||
body:@""
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
, outputFileName ? "status-go-${source.shortRev}-${platform}.aar" }:
|
||||
|
||||
let
|
||||
inherit (lib) concatStringsSep optionalString optional splitString fileContents;
|
||||
inherit (lib) concatStringsSep optionalString optional splitString;
|
||||
isIOS = platform == "ios";
|
||||
isAndroid = platform == "android";
|
||||
enforceXCodeAvailable = callPackage ./enforceXCodeAvailable.nix { };
|
||||
@@ -46,10 +46,6 @@ in buildGoPackage rec {
|
||||
# TODO: try removing when go is upgraded to 1.22
|
||||
GODEBUG = "netdns=cgo+2";
|
||||
|
||||
# Sentry for status-go
|
||||
SENTRY_CONTEXT_NAME = "status-mobile";
|
||||
SENTRY_CONTEXT_VERSION = fileContents ../../../VERSION;
|
||||
|
||||
preBuild = ''
|
||||
echo 'Generate static files'
|
||||
pushd go/src/$goPackagePath
|
||||
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 306 KiB |
|
After Width: | Height: | Size: 542 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
@@ -45,7 +45,6 @@ SECRETS_ENV_VARS=(
|
||||
'MIXPANEL_APP_ID'
|
||||
'MIXPANEL_TOKEN'
|
||||
'POKT_TOKEN'
|
||||
'SENTRY_DSN_STATUS_GO'
|
||||
)
|
||||
|
||||
# Secrets like this can't be passed via args or they end up in derivation.
|
||||
|
||||
@@ -123,8 +123,7 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/SENTRY_DSN_STATUS_GO #shadow/env "SENTRY_DSN_STATUS_GO"}
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
|
||||
:compiler-options {:output-feature-set :es6
|
||||
;;disable for android build as there
|
||||
;;is an intermittent warning with deftype
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.about-app.views
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.copyable-text :as copyable-text]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[quo.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(views/defview about-app
|
||||
[]
|
||||
(views/letsubs [app-version [:get-app-short-version]
|
||||
commit-hash [:get-commit-hash]
|
||||
node-version [:get-app-node-version]]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:type :title
|
||||
:title (i18n/label :t/about-app)
|
||||
:background :blur
|
||||
:icon-name :i/close
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[react/scroll-view
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text app-version}
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:accessibility-label :app-version
|
||||
:title (i18n/label :t/version)
|
||||
:accessory :text
|
||||
:accessory-text app-version}]]
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text commit-hash}
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:accessibility-label :commit-hash
|
||||
:title (i18n/label :t/app-commit)
|
||||
:accessory :text
|
||||
:accessory-text commit-hash}]]
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text node-version}
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:accessibility-label :node-version
|
||||
:title (i18n/label :t/node-version)
|
||||
:accessory :text
|
||||
:accessory-text node-version}]]]]))
|
||||
|
||||
(views/defview learn-more-sheet
|
||||
[]
|
||||
(views/letsubs [{:keys [title content]} [:bottom-sheet/options]]
|
||||
[react/view
|
||||
{:style {:padding-left 16
|
||||
:padding-top 16
|
||||
:padding-right 34
|
||||
:padding-bottom 0}}
|
||||
[react/view {:style {:align-items :center :flex-direction :row :margin-bottom 16}}
|
||||
[icons/icon :main-icons/info
|
||||
{:color colors/blue
|
||||
:container-style {:margin-right 13}}]
|
||||
[react/text {:style {:typography :title-bold}} title]]
|
||||
[react/text {:style {:color colors/gray}} content]]))
|
||||
|
||||
(def learn-more
|
||||
{:content learn-more-sheet})
|
||||
@@ -1,13 +1,10 @@
|
||||
(ns legacy.status-im.ui.screens.advanced-settings.views
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.core :as components]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.config :as config]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
@@ -25,23 +22,7 @@
|
||||
peer-syncing-enabled?]}]
|
||||
(keep
|
||||
identity
|
||||
[;; TODO(ilmotta): REMOVE BEFORE MERGE
|
||||
{:size :small
|
||||
:title (str "Is MixPanel token set?"
|
||||
(if (string/blank? config/mixpanel-token)
|
||||
"No"
|
||||
"Yes"))
|
||||
:on-press identity}
|
||||
(when (ff/enabled? ::ff/app-monitoring.intentional-crash)
|
||||
{:size :small
|
||||
:title (str "Force crash immediately"
|
||||
(when (string/blank? config/sentry-dsn-status-go)
|
||||
" (Sentry DSN is not set)"))
|
||||
:accessibility-label :intended-panic
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch [:app-monitoring/intended-panic
|
||||
"status-mobile intentional panic"]))})
|
||||
{:size :small
|
||||
[{:size :small
|
||||
:title (i18n/label :t/log-level)
|
||||
:accessibility-label :log-level-settings-button
|
||||
:on-press
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns legacy.status-im.ui.screens.screens
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.screens.about-app.views :as about-app]
|
||||
[legacy.status-im.ui.screens.advanced-settings.views :as advanced-settings]
|
||||
[legacy.status-im.ui.screens.appearance.views :as appearance]
|
||||
[legacy.status-im.ui.screens.backup-settings.view :as backup-settings]
|
||||
@@ -93,12 +92,6 @@
|
||||
:insets {:top? platform/android?}}
|
||||
:component sync-settings/sync-settings}
|
||||
|
||||
;; ABOUT
|
||||
{:name :about-app
|
||||
:options {:topBar {:visible false}
|
||||
:insets {:top? platform/android?}}
|
||||
:component about-app/about-app}
|
||||
|
||||
;; STATUS HELP
|
||||
{:name :help-center
|
||||
:options {:topBar {:visible false}
|
||||
|
||||
@@ -581,7 +581,3 @@
|
||||
(.createAccountFromPrivateKey ^js (account-manager)
|
||||
(types/clj->json {:privateKey private-key})
|
||||
callback)))
|
||||
|
||||
(defn intended-panic
|
||||
[message]
|
||||
(.intendedPanic ^js (status) message))
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
[rn/view {:style (style/loading-container size blur? theme)}]))
|
||||
|
||||
(defn- left-subtitle
|
||||
[{:keys [size subtitle-type subtitle-color icon icon-color blur? subtitle customization-color emoji
|
||||
[{:keys [size subtitle-text-props subtitle-type subtitle-color icon icon-color blur? subtitle
|
||||
customization-color emoji
|
||||
network-image]
|
||||
:or {subtitle-type :default}}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
@@ -39,9 +40,10 @@
|
||||
:style style/image}]
|
||||
nil)])
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/description subtitle-color blur? theme)}
|
||||
(merge {:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/description subtitle-color blur? theme)}
|
||||
subtitle-text-props)
|
||||
subtitle]
|
||||
(when (= subtitle-type :editable)
|
||||
[icons/icon :i/edit
|
||||
@@ -75,7 +77,8 @@
|
||||
|
||||
(defn- left-side
|
||||
"The description can either be given as a string `subtitle-type` or a component `custom-subtitle`"
|
||||
[{:keys [title status size blur? custom-subtitle icon subtitle subtitle-type subtitle-color icon-color
|
||||
[{:keys [title subtitle-text-props status size blur? custom-subtitle icon subtitle subtitle-type
|
||||
subtitle-color icon-color
|
||||
customization-color network-image emoji title-icon]
|
||||
:as props}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
@@ -94,6 +97,7 @@
|
||||
[custom-subtitle props]
|
||||
[left-subtitle
|
||||
{:theme theme
|
||||
:subtitle-text-props subtitle-text-props
|
||||
:size size
|
||||
:subtitle-type subtitle-type
|
||||
:subtitle-color subtitle-color
|
||||
@@ -140,6 +144,7 @@
|
||||
[:size {:optional true} [:maybe [:enum :default :small :large]]]
|
||||
[:title :string]
|
||||
[:subtitle {:optional true} [:maybe [:or :string :double]]]
|
||||
[:subtitle-text-props {:optional true} [:maybe :map]]
|
||||
[:custom-subtitle {:optional true} [:maybe fn?]]
|
||||
[:icon {:optional true} [:maybe :keyword]]
|
||||
[:title-icon {:optional true} [:maybe :keyword]]
|
||||
|
||||
@@ -79,11 +79,11 @@
|
||||
[rn/view {:style style/community-logo-ring}]])
|
||||
|
||||
(defn- description-container
|
||||
[{:keys [description description-text collection-text community-text
|
||||
collection-image community-image blur?]
|
||||
[{:keys [description description-text collection-text community-text blur?
|
||||
collection-image community-image description-accessibility-label]
|
||||
context-tag-props :context-tag
|
||||
summary-props :summary}]
|
||||
[rn/view
|
||||
[rn/view {:accessibility-label description-accessibility-label}
|
||||
(cond
|
||||
(and (= description :text) (not (string/blank? description-text)))
|
||||
[text/text
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
(ns status-im.common.app-monitoring.effects
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-fx :effects.app-monitoring/intended-panic
|
||||
(fn [message]
|
||||
(native-module/intended-panic message)))
|
||||
@@ -1,8 +0,0 @@
|
||||
(ns status-im.common.app-monitoring.events
|
||||
(:require
|
||||
status-im.common.app-monitoring.effects
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :app-monitoring/intended-panic
|
||||
(fn [_ [message]]
|
||||
{:fx [[:effects.app-monitoring/intended-panic message]]}))
|
||||
@@ -61,14 +61,17 @@
|
||||
(defn view
|
||||
[{:keys [header footer customization-color footer-container-padding header-container-style
|
||||
content-container-style gradient-cover? keyboard-should-persist-taps shell-overlay?
|
||||
blur-options content-avoid-keyboard? automatically-adjust-keyboard-insets]
|
||||
blur-options content-avoid-keyboard? automatically-adjust-keyboard-insets
|
||||
;; Note: Provide `initial-header-height` to avoid a jump due to the on-layout 1-frame
|
||||
;; delay. Revisit this on RN 0.76 since the on-layout delay has been fixed.
|
||||
initial-header-height]
|
||||
:or {footer-container-padding (safe-area/get-top)}}
|
||||
& children]
|
||||
(reagent/with-let [scroll-view-ref (atom nil)
|
||||
set-scroll-ref #(reset! scroll-view-ref %)
|
||||
window-height (:height (rn/get-window))
|
||||
footer-container-height (reagent/atom 0)
|
||||
header-height (reagent/atom 0)
|
||||
header-height (reagent/atom nil)
|
||||
content-container-height (reagent/atom 0)
|
||||
content-scroll-y (reagent/atom 0)
|
||||
keyboard-height (reagent/atom 0)
|
||||
@@ -112,7 +115,7 @@
|
||||
{:style
|
||||
(if content-avoid-keyboard?
|
||||
(style/content-keyboard-avoiding-view
|
||||
{:top @header-height
|
||||
{:top (or @header-height initial-header-height)
|
||||
:bottom (if keyboard-shown?
|
||||
@footer-container-height
|
||||
(+ bottom-safe-area @footer-container-height))})
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
(ns status-im.common.privacy.view
|
||||
(:require-macros [legacy.status-im.utils.slurp :refer [slurp]])
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.gesture :as gesture]))
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im.contexts.settings.common.header :as header]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(def privacy-statement-text (slurp "resources/privacy.mdwn"))
|
||||
|
||||
(defn privacy-statement
|
||||
[]
|
||||
[gesture/scroll-view {:margin 20}
|
||||
[gesture/scroll-view {:style {:margin 20}}
|
||||
[quo/text privacy-statement-text]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[quo/overlay {:type :shell}
|
||||
[header/view {:title (i18n/label :t/privacy-policy)}]
|
||||
[gesture/scroll-view {:style {:padding-horizontal 20}}
|
||||
[quo/text privacy-statement-text]]])
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
(def ui
|
||||
{:add-new-contact (js/require "../resources/images/ui2/add-contact.png")
|
||||
:biometrics (js/require "../resources/images/ui2/biometrics.png")
|
||||
:usage-data (js/require "../resources/images/ui2/usage-data.png")
|
||||
:login-syncing (js/require "../resources/images/ui2/login-syncing.png")
|
||||
:chat-privately-with-friends (js/require "../resources/images/ui2/chat-privately-with-friends.png")
|
||||
:desktop-how-to-pair-sign-in (js/require "../resources/images/ui2/desktop-how-to-pair-sign-in.png")
|
||||
:desktop-how-to-pair-logged-in (js/require
|
||||
|
||||
@@ -10,24 +10,43 @@
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-fx :effects.keycard/call-on-auth-success
|
||||
(fn [on-auth-success]
|
||||
(when on-auth-success (on-auth-success ""))))
|
||||
(defn- handle-password-success
|
||||
[has-partially-operable-accounts? on-auth-success masked-password]
|
||||
(let [on-auth-success-callback #(on-auth-success masked-password)]
|
||||
(rf/dispatch [:standard-auth/set-success true])
|
||||
(rf/dispatch [:standard-auth/reset-login-password])
|
||||
(if has-partially-operable-accounts?
|
||||
(rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable
|
||||
{:password masked-password
|
||||
:on-success on-auth-success-callback
|
||||
:on-error on-auth-success-callback}])
|
||||
(on-auth-success-callback))))
|
||||
|
||||
(defn authorize
|
||||
[{:keys [db]} [{:keys [on-auth-success keycard-supported?] :as args}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
keycard? (get-in db [:profile/profile :keycard-pairing])]
|
||||
[{:keys [db]} [{:keys [on-auth-success] :as args}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
keycard-profile? (get-in db [:profile/profile :keycard-pairing])]
|
||||
{:fx
|
||||
[(if keycard?
|
||||
(if keycard-supported?
|
||||
[:effects.keycard/call-on-auth-success on-auth-success]
|
||||
[:effects.utils/show-popup
|
||||
{:title "This feature is not supported yet "
|
||||
:content
|
||||
"Keycard support is limited to logging in
|
||||
and signing the sending transaction.
|
||||
Use Status Desktop to access all functions."}])
|
||||
[(if keycard-profile?
|
||||
[:dispatch
|
||||
[:standard-auth/authorize-with-keycard
|
||||
{:on-complete
|
||||
(fn [pin]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:keycard/get-keys
|
||||
{:pin pin
|
||||
:on-success (fn [{:keys [encryption-public-key]}]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(handle-password-success false
|
||||
on-auth-success
|
||||
(security/mask-data encryption-public-key)))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error
|
||||
%])}]))}]))}]]
|
||||
[:effects.biometric/check-if-available
|
||||
{:key-uid key-uid
|
||||
:on-success #(rf/dispatch [:standard-auth/authorize-with-biometric args])
|
||||
@@ -89,21 +108,12 @@
|
||||
(defn- bottom-sheet-password-view
|
||||
[{:keys [on-press-biometric on-auth-success auth-button-icon-left auth-button-label]}]
|
||||
(fn []
|
||||
(let [has-partially-operable-accounts? (rf/sub [:wallet/has-partially-operable-accounts?])
|
||||
handle-password-success
|
||||
(fn [password]
|
||||
(let [sha3-pwd (security/hash-masked-password password)
|
||||
on-auth-success-callback #(on-auth-success sha3-pwd)]
|
||||
(rf/dispatch [:standard-auth/set-success true])
|
||||
(rf/dispatch [:standard-auth/reset-login-password])
|
||||
(if has-partially-operable-accounts?
|
||||
(rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable
|
||||
{:password sha3-pwd
|
||||
:on-success on-auth-success-callback
|
||||
:on-error on-auth-success-callback}])
|
||||
(on-auth-success-callback))))]
|
||||
(let [has-partially-operable-accounts? (rf/sub [:wallet/has-partially-operable-accounts?])]
|
||||
[enter-password/view
|
||||
{:on-enter-password handle-password-success
|
||||
{:on-enter-password #(handle-password-success
|
||||
has-partially-operable-accounts?
|
||||
on-auth-success
|
||||
(security/hash-masked-password %))
|
||||
:on-press-biometrics on-press-biometric
|
||||
:button-icon-left auth-button-icon-left
|
||||
:button-label auth-button-label}])))
|
||||
|
||||
@@ -9,26 +9,25 @@
|
||||
|
||||
(defn view
|
||||
[{:keys [track-text customization-color auth-button-label on-auth-success on-auth-fail
|
||||
auth-button-icon-left size blur? container-style disabled? dependencies keycard-supported?]
|
||||
auth-button-icon-left size blur? container-style disabled? dependencies on-complete]
|
||||
:or {container-style {:flex 1}}}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
auth-method (rf/sub [:auth-method])
|
||||
biometric-auth? (= auth-method constants/auth-method-biometric)
|
||||
on-complete (rn/use-callback
|
||||
(fn [reset]
|
||||
(rf/dispatch [:standard-auth/authorize
|
||||
{:on-close (fn [success?]
|
||||
(js/setTimeout #(reset success?) 200))
|
||||
:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:keycard-supported? keycard-supported?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label}]))
|
||||
(vec (conj dependencies on-auth-success on-auth-fail)))
|
||||
biometric-type (rf/sub [:biometrics/supported-type])]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
auth-method (rf/sub [:auth-method])
|
||||
biometric-auth? (= auth-method constants/auth-method-biometric)
|
||||
on-complete-callback (rn/use-callback
|
||||
(fn [reset-slider-fn]
|
||||
(js/setTimeout #(reset-slider-fn false) 500)
|
||||
(rf/dispatch [:standard-auth/authorize
|
||||
{:auth-button-icon-left auth-button-icon-left
|
||||
:theme theme
|
||||
:blur? blur?
|
||||
:biometric-auth? biometric-auth?
|
||||
:on-auth-success on-auth-success
|
||||
:on-auth-fail on-auth-fail
|
||||
:auth-button-label auth-button-label}]))
|
||||
(vec (conj dependencies on-auth-success on-auth-fail)))
|
||||
on-complete (or on-complete on-complete-callback)
|
||||
biometric-type (rf/sub [:biometrics/supported-type])]
|
||||
[quo/slide-button
|
||||
{:container-style container-style
|
||||
:size size
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
(ns status-im.common.terms.view
|
||||
(:require-macros [legacy.status-im.utils.slurp :refer [slurp]])
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.gesture :as gesture]))
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im.contexts.settings.common.header :as header]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(def terms-of-use-text (slurp "resources/terms-of-use.mdwn"))
|
||||
|
||||
(defn terms-of-use
|
||||
[]
|
||||
[gesture/scroll-view {:margin 20}
|
||||
[gesture/scroll-view {:style {:margin 20}}
|
||||
[quo/text terms-of-use-text]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[quo/overlay {:type :shell}
|
||||
[header/view {:title (i18n/label :t/terms-of-service)}]
|
||||
[gesture/scroll-view {:style {:padding-horizontal 20}}
|
||||
[quo/text terms-of-use-text]]])
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
:long-enough?
|
||||
:short-enough?)))))
|
||||
|
||||
(def password-tip? (set constants/password-tips))
|
||||
|
||||
(defn strength
|
||||
[validations]
|
||||
(->> (select-keys validations constants/password-tips)
|
||||
(vals)
|
||||
(filter true?)
|
||||
count))
|
||||
(->> validations
|
||||
(filter #(and (password-tip? (key %)) (val %)))
|
||||
(count)))
|
||||
|
||||
@@ -150,8 +150,3 @@
|
||||
(goog-define STATUS_BACKEND_SERVER_ROOT_DATA_DIR "")
|
||||
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
|
||||
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")
|
||||
|
||||
;;;; Sentry
|
||||
;; Documentation: status-go/internal/sentry/README.md
|
||||
(goog-define SENTRY_DSN_STATUS_GO "")
|
||||
(def sentry-dsn-status-go SENTRY_DSN_STATUS_GO)
|
||||
|
||||
@@ -334,6 +334,7 @@
|
||||
(def ^:const privacy-policy-link "https://status.im/privacy-policy/")
|
||||
(def ^:const terms-of-service-link "https://status.im/terms-of-use")
|
||||
(def ^:const create-account-link "https://status.app/help/wallet/create-wallet-accounts")
|
||||
(def ^:const mobile-upvote-link "https://status-mobile.featureupvote.com")
|
||||
|
||||
(def ^:const visibility-status-unknown 0)
|
||||
(def ^:const visibility-status-automatic 1)
|
||||
@@ -641,3 +642,9 @@
|
||||
(def ^:const wallet-connect-transaction-refresh-interval-ms 10000)
|
||||
|
||||
(def ^:const native-token-symbol "ETH")
|
||||
|
||||
;; About app links
|
||||
(def ^:const status-app-url "http://status.app")
|
||||
(def ^:const go-waku-url "https://github.com/waku-org/go-waku")
|
||||
(def ^:const status-go-url "https://github.com/status-im/status-go")
|
||||
(def ^:const status-mobile-url "https://github.com/status-im/status-mobile")
|
||||
|
||||
@@ -52,8 +52,8 @@
|
||||
{:eventName "navigation"
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {:viewId "onboarding.create-profile-info"}}}]
|
||||
(tracking/track-view-id-event :screen/onboarding.create-profile)))
|
||||
:eventValue {:viewId "onboarding.create-profile-password"}}}]
|
||||
(tracking/track-view-id-event :screen/onboarding.create-profile-password)))
|
||||
(is (= [] (tracking/track-view-id-event :unknown-stack)))))
|
||||
|
||||
(deftest tracked-event-test
|
||||
|
||||
@@ -11,30 +11,35 @@
|
||||
[{:keys [contact-id]}]
|
||||
(let [{:keys [contact-request-state
|
||||
community-id
|
||||
chat-name]} (rf/sub [:chats/current-chat-chat-view])
|
||||
chat-type (rf/sub [:chats/chat-type])
|
||||
[primary-name _] (if (= chat-type :public-chat)
|
||||
[(str "#" chat-name) ""]
|
||||
(rf/sub [:contacts/contact-two-names-by-identity contact-id]))
|
||||
community-chat? (= chat-type :community-chat)
|
||||
joined (when community-chat?
|
||||
(rf/sub [:communities/community-joined community-id]))
|
||||
pending? (when community-chat?
|
||||
(rf/sub [:communities/my-pending-request-to-join community-id]))
|
||||
contact-request-send? (or (not contact-request-state)
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-none))
|
||||
contact-request-received? (= contact-request-state
|
||||
constants/contact-request-state-received)
|
||||
contact-request-pending? (= contact-request-state
|
||||
constants/contact-request-state-sent)]
|
||||
chat-name]} (rf/sub [:chats/current-chat-chat-view])
|
||||
chat-type (rf/sub [:chats/chat-type])
|
||||
[primary-name _] (if (= chat-type :public-chat)
|
||||
[(str "#" chat-name) ""]
|
||||
(rf/sub [:contacts/contact-two-names-by-identity contact-id]))
|
||||
community-chat? (= chat-type :community-chat)
|
||||
joined (when community-chat?
|
||||
(rf/sub [:communities/community-joined community-id]))
|
||||
pending? (when community-chat?
|
||||
(rf/sub [:communities/my-pending-request-to-join community-id]))
|
||||
contact-request-send? (or (not contact-request-state)
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-none))
|
||||
contact-request-received? (= contact-request-state
|
||||
constants/contact-request-state-received)
|
||||
contact-request-pending? (= contact-request-state
|
||||
constants/contact-request-state-sent)
|
||||
keycard? (rf/sub [:keycard/keycard-profile?])
|
||||
keycard-feature-unavailable (rn/use-callback
|
||||
#(rf/dispatch [:keycard/feature-unavailable-show]))]
|
||||
[rn/view {:style style/container}
|
||||
[quo/permission-context
|
||||
{:blur? true
|
||||
:on-press (cond
|
||||
(and community-chat? (not pending?) (not joined))
|
||||
#(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id community-id}])
|
||||
(if keycard?
|
||||
keycard-feature-unavailable
|
||||
#(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id community-id}]))
|
||||
|
||||
(not community-chat?)
|
||||
#(rf/dispatch [:chat.ui/show-profile contact-id]))
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
(fn []
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [id]} (rf/sub [:get-screen-params])
|
||||
{:keys [color name images]} (rf/sub [:communities/community id])]
|
||||
{:keys [color name images]} (rf/sub [:communities/community id])
|
||||
keycard? (rf/sub [:keycard/keycard-profile?])
|
||||
keycard-feature-unavailable (rn/use-callback
|
||||
#(rf/dispatch [:keycard/feature-unavailable-show]))]
|
||||
[rn/safe-area-view {:flex 1}
|
||||
[gesture/scroll-view {:style style/container}
|
||||
[rn/view style/page-container
|
||||
@@ -59,7 +62,9 @@
|
||||
(i18n/label :t/cancel)]
|
||||
[quo/button
|
||||
{:accessibility-label :join-community-button
|
||||
:on-press #(join-community-and-navigate-back id)
|
||||
:on-press (if keycard?
|
||||
keycard-feature-unavailable
|
||||
#(join-community-and-navigate-back id))
|
||||
:container-style {:flex 1}
|
||||
:inner-style {:background-color (colors/resolve-color color theme)}}
|
||||
(i18n/label :t/request-to-join)]]
|
||||
|
||||
@@ -106,12 +106,14 @@
|
||||
[quo/text (i18n/label :t/network-not-supported)])
|
||||
|
||||
(defn- request-access-button
|
||||
[id color]
|
||||
[id color keycard? keycard-feature-unavailable]
|
||||
[quo/button
|
||||
{:on-press (if config/community-accounts-selection-enabled?
|
||||
#(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id id}])
|
||||
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
|
||||
{:on-press (if keycard?
|
||||
keycard-feature-unavailable
|
||||
(if config/community-accounts-selection-enabled?
|
||||
#(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id id}])
|
||||
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}])))
|
||||
:accessibility-label :show-request-to-join-screen-button
|
||||
:customization-color color
|
||||
:container-style {:margin-bottom 12}
|
||||
@@ -126,27 +128,33 @@
|
||||
|
||||
(defn- token-requirements
|
||||
[{:keys [id color role-permissions?]}]
|
||||
(let [{:keys [can-request-access? no-member-permission? networks-not-supported?
|
||||
highest-permission-role
|
||||
tokens]} (rf/sub [:community/token-gated-overview id])
|
||||
highest-role-text (i18n/label
|
||||
(communities.utils/role->translation-key highest-permission-role :t/member))
|
||||
on-press (rn/use-callback
|
||||
(fn []
|
||||
(if config/community-accounts-selection-enabled?
|
||||
(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id id}])
|
||||
(rf/dispatch [:open-modal :community-requests-to-join
|
||||
{:id id}])))
|
||||
[id])
|
||||
on-press-info #(rf/dispatch
|
||||
[:show-bottom-sheet {:content token-gated-communities-info}])]
|
||||
(let
|
||||
[{:keys [can-request-access? no-member-permission? networks-not-supported?
|
||||
highest-permission-role
|
||||
tokens]} (rf/sub [:community/token-gated-overview id])
|
||||
highest-role-text (i18n/label
|
||||
(communities.utils/role->translation-key highest-permission-role
|
||||
:t/member))
|
||||
on-press (rn/use-callback
|
||||
(fn []
|
||||
(if config/community-accounts-selection-enabled?
|
||||
(rf/dispatch [:open-modal :community-account-selection-sheet
|
||||
{:community-id id}])
|
||||
(rf/dispatch [:open-modal :community-requests-to-join
|
||||
{:id id}])))
|
||||
[id])
|
||||
on-press-info #(rf/dispatch
|
||||
[:show-bottom-sheet {:content token-gated-communities-info}])
|
||||
keycard? (rf/sub [:keycard/keycard-profile?])
|
||||
keycard-feature-unavailable (rn/use-callback
|
||||
#(rf/dispatch [:keycard/feature-unavailable-show]))]
|
||||
|
||||
(cond
|
||||
networks-not-supported?
|
||||
[network-not-supported]
|
||||
|
||||
(or (not role-permissions?) no-member-permission?)
|
||||
[request-access-button id color]
|
||||
[request-access-button id color keycard? keycard-feature-unavailable]
|
||||
|
||||
:else
|
||||
[quo/community-token-gating
|
||||
@@ -154,7 +162,7 @@
|
||||
:tokens tokens
|
||||
:community-color color
|
||||
:satisfied? can-request-access?
|
||||
:on-press on-press
|
||||
:on-press (if keycard? keycard-feature-unavailable on-press)
|
||||
:on-press-info on-press-info}])))
|
||||
|
||||
(defn- join-community
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
status-im.contexts.keycard.pin.events
|
||||
status-im.contexts.keycard.sign.events
|
||||
[status-im.contexts.keycard.utils :as keycard.utils]
|
||||
utils.datetime))
|
||||
[utils.address :as address]
|
||||
utils.datetime
|
||||
[utils.ethereum.eip.eip55 :as eip55]))
|
||||
|
||||
(rf/reg-event-fx :keycard/on-card-connected
|
||||
(fn [{:keys [db]} _]
|
||||
@@ -65,6 +67,30 @@
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/export-key data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
|
||||
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:keycard/export-key
|
||||
{:pin pin
|
||||
:path derivation-path
|
||||
:on-success (fn [public-key]
|
||||
(let [derived-account {:public-key (str "0x" public-key)
|
||||
:address (eip55/address->checksum
|
||||
(str "0x"
|
||||
(address/public-key->address
|
||||
(subs public-key 2))))
|
||||
:path derivation-path}]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:wallet/add-account
|
||||
(assoc account-preferences :key-uid key-uid)
|
||||
derived-account])))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/cancel-connection
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update db
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
(ns status-im.contexts.keycard.feature-unavailable.events
|
||||
(:require
|
||||
[status-im.contexts.keycard.feature-unavailable.view :as feature-unavailable]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:keycard/feature-unavailable-show
|
||||
(fn [_ [options]]
|
||||
{:fx [[:dispatch
|
||||
[:show-bottom-sheet
|
||||
{:theme (:theme options)
|
||||
:content feature-unavailable/view}]]]}))
|
||||
@@ -0,0 +1,28 @@
|
||||
(ns status-im.contexts.keycard.feature-unavailable.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn on-upvote
|
||||
[]
|
||||
(rf/dispatch [:open-url constants/mobile-upvote-link]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:title (i18n/label :t/feature-unavailable)
|
||||
:description (i18n/label :t/feature-unavailable-for-keycard-description)}]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:icon :i/info
|
||||
:style {:margin-top 8 :margin-horizontal 20}}
|
||||
[:<>
|
||||
(i18n/label :t/feature-unavailable-info)
|
||||
[quo/text
|
||||
{:style {:text-decoration-line :underline}
|
||||
:size :paragraph-2
|
||||
:on-press on-upvote}
|
||||
(i18n/label :t/upvote-it)]]]])
|
||||
@@ -91,7 +91,7 @@
|
||||
:title (i18n/label :t/log-in-by-syncing)
|
||||
:subtitle (i18n/label :t/log-in-by-syncing-subtitle)
|
||||
:accessibility-label :log-in-by-syncing-icon-card
|
||||
:image (resources/get-image :ethereum-address)
|
||||
:image (resources/get-image :login-syncing)
|
||||
:on-press show-check-before-syncing}])
|
||||
|
||||
(defn- use-empty-keycard-icon-card
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.contexts.onboarding.create-password.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def heading {:margin-bottom 20})
|
||||
(def heading-subtitle {:color colors/white})
|
||||
@@ -21,6 +22,18 @@
|
||||
:padding-top 12
|
||||
:padding-horizontal 20})
|
||||
|
||||
(def disclaimer-container {:padding-horizontal 20})
|
||||
(def footer-container {:padding-bottom 12})
|
||||
(def footer-button-container {:margin-top 20 :padding-horizontal 20})
|
||||
|
||||
(def blur-options
|
||||
{:blur-amount 34
|
||||
:blur-radius 20
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
:background-color (if platform/android?
|
||||
colors/neutral-100
|
||||
colors/neutral-80-opa-1-blur)
|
||||
:padding-vertical 0
|
||||
:padding-horizontal 0})
|
||||
|
||||
(def page-nav-height 56)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
(ns status-im.contexts.onboarding.create-password.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.floating-button-page.view :as floating-button]
|
||||
[status-im.common.password-with-hint.view :as password-with-hint]
|
||||
@@ -29,22 +27,37 @@
|
||||
(i18n/label :t/password-creation-subtitle)]])
|
||||
|
||||
(defn password-inputs
|
||||
[{:keys [passwords-match? on-change-password on-change-repeat-password on-input-focus
|
||||
password-long-enough? password-short-enough? empty-password? show-password-validation?
|
||||
on-blur-repeat-password]}]
|
||||
(let [hint-1-status (if password-long-enough? :success :default)
|
||||
hint-2-status (if passwords-match? :success :error)
|
||||
hint-2-text (if passwords-match?
|
||||
(i18n/label :t/password-creation-match)
|
||||
(i18n/label :t/password-creation-dont-match))
|
||||
error? (and show-password-validation?
|
||||
(not passwords-match?)
|
||||
(not empty-password?))]
|
||||
[{:keys [set-password set-repeat-password same-password-length? same-passwords?
|
||||
password-long-enough? password-short-enough? non-empty-password?]}]
|
||||
(let [[show-validation?
|
||||
set-show-validation?] (rn/use-state false)
|
||||
on-change-password (rn/use-callback
|
||||
(fn [new-value]
|
||||
(set-password new-value)
|
||||
(when same-password-length?
|
||||
(set-show-validation? true)))
|
||||
[same-password-length?])
|
||||
on-change-repeat-password (rn/use-callback
|
||||
(fn [new-value]
|
||||
(set-repeat-password new-value)
|
||||
(when same-password-length?
|
||||
(set-show-validation? true)))
|
||||
[same-password-length?])
|
||||
on-blur-repeat-password (rn/use-callback
|
||||
#(set-show-validation? non-empty-password?)
|
||||
[non-empty-password?])
|
||||
hint-1-status (if password-long-enough? :success :default)
|
||||
hint-2-status (if same-passwords? :success :error)
|
||||
hint-2-text (if same-passwords?
|
||||
(i18n/label :t/password-creation-match)
|
||||
(i18n/label :t/password-creation-dont-match))
|
||||
error? (and show-validation?
|
||||
(not same-passwords?)
|
||||
non-empty-password?)]
|
||||
[:<>
|
||||
[password-with-hint/view
|
||||
{:hint (if (not password-short-enough?)
|
||||
{:text (i18n/label
|
||||
:t/password-creation-max-length-hint)
|
||||
{:text (i18n/label :t/password-creation-max-length-hint)
|
||||
:status :error
|
||||
:shown? true}
|
||||
{:text (i18n/label :t/password-creation-hint)
|
||||
@@ -52,55 +65,50 @@
|
||||
:shown? true})
|
||||
:placeholder (i18n/label :t/password-creation-placeholder-1)
|
||||
:on-change-text on-change-password
|
||||
:on-focus on-input-focus
|
||||
:auto-focus true}]
|
||||
[rn/view {:style style/space-between-inputs}]
|
||||
[password-with-hint/view
|
||||
{:hint {:text hint-2-text
|
||||
:status hint-2-status
|
||||
:shown? (and (not empty-password?)
|
||||
show-password-validation?)}
|
||||
:shown? (and non-empty-password? show-validation?)}
|
||||
:error? error?
|
||||
:placeholder (i18n/label :t/password-creation-placeholder-2)
|
||||
:on-change-text on-change-repeat-password
|
||||
:on-focus on-input-focus
|
||||
:on-blur on-blur-repeat-password}]]))
|
||||
|
||||
(defn help
|
||||
[{{:keys [lower-case? upper-case? numbers? symbols?]} :validations
|
||||
password-strength :password-strength}]
|
||||
[rn/view
|
||||
[quo/strength-divider {:type (constants/strength-status password-strength :info)}
|
||||
(i18n/label :t/password-creation-tips-title)]
|
||||
[rn/view {:style style/password-tips}
|
||||
[quo/tips {:completed? lower-case?}
|
||||
(i18n/label :t/password-creation-tips-1)]
|
||||
[quo/tips {:completed? upper-case?}
|
||||
(i18n/label :t/password-creation-tips-2)]
|
||||
[quo/tips {:completed? numbers?}
|
||||
(i18n/label :t/password-creation-tips-3)]
|
||||
[quo/tips {:completed? symbols?}
|
||||
(i18n/label :t/password-creation-tips-4)]]])
|
||||
[{:keys [lower-case? upper-case? numbers? symbols?] :as validations}]
|
||||
(let [password-strength (constants/strength-status (password/strength validations) :info)]
|
||||
[rn/view
|
||||
[quo/strength-divider {:type password-strength}
|
||||
(i18n/label :t/password-creation-tips-title)]
|
||||
[rn/view {:style style/password-tips}
|
||||
[quo/tips {:completed? lower-case?}
|
||||
(i18n/label :t/password-creation-tips-1)]
|
||||
[quo/tips {:completed? upper-case?}
|
||||
(i18n/label :t/password-creation-tips-2)]
|
||||
[quo/tips {:completed? numbers?}
|
||||
(i18n/label :t/password-creation-tips-3)]
|
||||
[quo/tips {:completed? symbols?}
|
||||
(i18n/label :t/password-creation-tips-4)]]]))
|
||||
|
||||
(defn- use-password-checks
|
||||
[password]
|
||||
(rn/use-memo
|
||||
(fn []
|
||||
(let [{:keys [long-enough? short-enough?]
|
||||
:as validations} (password/validate password)]
|
||||
{:password-long-enough? long-enough?
|
||||
:password-short-enough? short-enough?
|
||||
:password-validations validations
|
||||
:password-strength (password/strength validations)
|
||||
:empty-password? (empty? password)}))
|
||||
(-> password
|
||||
(password/validate)
|
||||
(assoc :non-empty? (seq password))))
|
||||
[password]))
|
||||
|
||||
(defn- use-repeat-password-checks
|
||||
[password repeat-password]
|
||||
(rn/use-memo
|
||||
(fn []
|
||||
{:same-password-length? (and (seq password) (= (count password) (count repeat-password)))
|
||||
:same-passwords? (and (seq password) (= password repeat-password))})
|
||||
{:same-password-length? (and (seq password)
|
||||
(= (count password) (count repeat-password)))
|
||||
:same-passwords? (and (seq password)
|
||||
(= password repeat-password))})
|
||||
[password repeat-password]))
|
||||
|
||||
(defn create-password-doc
|
||||
@@ -119,102 +127,70 @@
|
||||
{:content create-password-doc
|
||||
:shell? true}]))
|
||||
|
||||
(defn- navigate-back
|
||||
[]
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(defn- navigate-back [] (rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn- page-nav
|
||||
[]
|
||||
(let [{:keys [top]} (safe-area/get-insets)]
|
||||
[quo/page-nav
|
||||
{:margin-top top
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press navigate-back
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press on-press-info}]}]))
|
||||
[top]
|
||||
[quo/page-nav
|
||||
{:margin-top top
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press navigate-back
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press on-press-info}]}])
|
||||
|
||||
(defn- help-and-confirm-button
|
||||
[{:keys [password-validations same-passwords? on-submit]}]
|
||||
(let [{customization-color :color} (rf/sub [:onboarding/profile])
|
||||
all-requirements-met? (and (:non-empty? password-validations)
|
||||
(:long-enough? password-validations)
|
||||
(:short-enough? password-validations)
|
||||
same-passwords?)]
|
||||
[rn/view {:style style/footer-container}
|
||||
[help password-validations]
|
||||
[quo/button
|
||||
{:container-style style/footer-button-container
|
||||
:disabled? (not all-requirements-met?)
|
||||
:customization-color customization-color
|
||||
:on-press on-submit}
|
||||
(i18n/label :t/password-creation-confirm)]]))
|
||||
|
||||
(defn- on-confirm-password
|
||||
[password]
|
||||
(rf/dispatch [:onboarding/password-set (security/mask-data password)]))
|
||||
|
||||
(defn create-password
|
||||
[]
|
||||
(let [[password set-password] (rn/use-state "")
|
||||
[repeat-password set-repeat-password] (rn/use-state "")
|
||||
[accepts-disclaimer? set-accepts-disclaimer?] (rn/use-state false)
|
||||
[focused-input set-focused-input] (rn/use-state nil)
|
||||
[show-password-validation?
|
||||
set-show-password-validation?] (rn/use-state false)
|
||||
{user-color :color} (rf/sub [:onboarding/profile])
|
||||
|
||||
|
||||
{:keys [password-long-enough?
|
||||
password-short-enough?
|
||||
password-validations password-strength
|
||||
empty-password?]} (use-password-checks password)
|
||||
|
||||
{:keys [same-password-length? same-passwords?]} (use-repeat-password-checks password
|
||||
repeat-password)
|
||||
|
||||
meet-requirements? (and (not empty-password?)
|
||||
password-long-enough?
|
||||
password-short-enough?
|
||||
same-passwords?
|
||||
accepts-disclaimer?)]
|
||||
|
||||
(let [[password set-password] (rn/use-state "")
|
||||
[repeat-password
|
||||
set-repeat-password] (rn/use-state "")
|
||||
{:keys [long-enough? short-enough? non-empty?]
|
||||
:as password-validations} (use-password-checks password)
|
||||
{:keys [same-password-length?
|
||||
same-passwords?]} (use-repeat-password-checks password repeat-password)
|
||||
on-submit (rn/use-callback
|
||||
#(on-confirm-password password)
|
||||
[password])
|
||||
top (safe-area/get-top)]
|
||||
[floating-button/view
|
||||
{:header [page-nav]
|
||||
:keyboard-should-persist-taps :handled
|
||||
:content-avoid-keyboard? true
|
||||
{:header [page-nav top]
|
||||
:initial-header-height (+ style/page-nav-height top)
|
||||
:keyboard-should-persist-taps :handled
|
||||
:content-avoid-keyboard? true
|
||||
:automatically-adjust-keyboard-insets true
|
||||
:blur-options
|
||||
{:blur-amount 34
|
||||
:blur-radius 20
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur)
|
||||
:padding-vertical 0
|
||||
:padding-horizontal 0}
|
||||
:footer-container-padding 0
|
||||
:footer
|
||||
[rn/view
|
||||
{:style style/footer-container}
|
||||
(when same-passwords?
|
||||
[rn/view {:style style/disclaimer-container}
|
||||
[quo/disclaimer
|
||||
{:blur? true
|
||||
:on-change (partial set-accepts-disclaimer? not)
|
||||
:checked? accepts-disclaimer?
|
||||
:customization-color user-color}
|
||||
(i18n/label :t/password-creation-disclaimer)]])
|
||||
(when (and (= focused-input :password) (not same-passwords?))
|
||||
[help
|
||||
{:validations password-validations
|
||||
:password-strength password-strength}])
|
||||
[quo/button
|
||||
{:container-style style/footer-button-container
|
||||
:disabled? (not meet-requirements?)
|
||||
:customization-color user-color
|
||||
:on-press #(rf/dispatch
|
||||
[:onboarding/password-set
|
||||
(security/mask-data password)])}
|
||||
(i18n/label :t/password-creation-confirm)]]}
|
||||
|
||||
:blur-options style/blur-options
|
||||
:footer-container-padding 0
|
||||
:footer [help-and-confirm-button
|
||||
{:password-validations password-validations
|
||||
:same-passwords? same-passwords?
|
||||
:on-submit on-submit}]}
|
||||
[rn/view {:style style/form-container}
|
||||
[header]
|
||||
[password-inputs
|
||||
{:password-long-enough? password-long-enough?
|
||||
:password-short-enough? password-short-enough?
|
||||
:passwords-match? same-passwords?
|
||||
:empty-password? empty-password?
|
||||
:show-password-validation? show-password-validation?
|
||||
:on-input-focus #(set-focused-input :password)
|
||||
:on-change-password (fn [new-value]
|
||||
(set-password new-value)
|
||||
(when same-password-length?
|
||||
(set-show-password-validation? true)))
|
||||
|
||||
:on-change-repeat-password (fn [new-value]
|
||||
(set-repeat-password new-value)
|
||||
(when same-password-length?
|
||||
(set-show-password-validation? true)))
|
||||
:on-blur-repeat-password #(if empty-password?
|
||||
(set-show-password-validation? false)
|
||||
(set-show-password-validation? true))}]]]))
|
||||
{:password-long-enough? long-enough?
|
||||
:password-short-enough? short-enough?
|
||||
:non-empty-password? non-empty?
|
||||
:same-passwords? same-passwords?
|
||||
:same-password-length? same-password-length?
|
||||
:set-password set-password
|
||||
:set-repeat-password set-repeat-password}]]]))
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
(ns status-im.contexts.onboarding.create-profile.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def continue-button
|
||||
{:width "100%"
|
||||
:margin-left :auto
|
||||
:margin-top (if platform/android? :auto 0)
|
||||
:margin-right :auto})
|
||||
|
||||
(def button-container
|
||||
{:width "100%"
|
||||
:padding-left 20
|
||||
:padding-right 20
|
||||
:padding-top 12
|
||||
:align-self :flex-end
|
||||
:height 64})
|
||||
|
||||
(defn view-button-container
|
||||
[keyboard-shown?]
|
||||
(merge button-container
|
||||
(if platform/ios?
|
||||
{:margin-bottom (if keyboard-shown? 0 34)}
|
||||
{:margin-bottom (if keyboard-shown? 12 34)})))
|
||||
|
||||
(def blur-button-container
|
||||
(merge button-container
|
||||
(when platform/android? {:padding-bottom 12})))
|
||||
|
||||
(def page-container
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:z-index 100})
|
||||
|
||||
(def info-message
|
||||
{:margin-top 8})
|
||||
|
||||
(def title
|
||||
{:color colors/white
|
||||
:margin-top 12
|
||||
:margin-bottom 18})
|
||||
|
||||
(def color-title
|
||||
{:color colors/white-70-blur
|
||||
:margin-top 20
|
||||
:margin-bottom 16})
|
||||
|
||||
(def content-container
|
||||
{:padding-horizontal 20})
|
||||
|
||||
(def input-container
|
||||
{:align-items :flex-start})
|
||||
|
||||
(def profile-input-container
|
||||
{:flex-direction :row
|
||||
:justify-content :center})
|
||||
@@ -1,210 +0,0 @@
|
||||
(ns status-im.contexts.onboarding.create-profile.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.avatar-picture-picker.view :as profile-picture-picker]
|
||||
[status-im.common.validation.profile :as profile-validator]
|
||||
[status-im.constants :as c]
|
||||
[status-im.contexts.onboarding.create-profile.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.responsiveness :as responsiveness]))
|
||||
|
||||
(def scroll-view-height (reagent/atom 0))
|
||||
(def content-container-height (reagent/atom 0))
|
||||
|
||||
(defn show-button-background
|
||||
[keyboard-height keyboard-shown content-scroll-y]
|
||||
(let [button-container-height 64
|
||||
keyboard-view-height (+ keyboard-height button-container-height)]
|
||||
(when keyboard-shown
|
||||
(cond
|
||||
platform/android?
|
||||
(< (- @scroll-view-height button-container-height) @content-container-height)
|
||||
|
||||
platform/ios?
|
||||
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
|
||||
|
||||
:else
|
||||
false))))
|
||||
|
||||
(defn button-container
|
||||
[show-keyboard? keyboard-shown show-background? keyboard-height children]
|
||||
(let [height (reagent/atom 0)]
|
||||
(reset! height (if show-keyboard? (if keyboard-shown keyboard-height 0) 0))
|
||||
[rn/view {:style {:margin-top :auto}}
|
||||
(cond
|
||||
(and (> @height 0) show-background?)
|
||||
[quo/blur
|
||||
(when keyboard-shown
|
||||
{:blur-amount 34
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
:background-color (if platform/android? colors/neutral-100 colors/neutral-80-opa-1-blur)
|
||||
:style style/blur-button-container})
|
||||
children]
|
||||
|
||||
(and (> @height 0) (not show-background?))
|
||||
[rn/view {:style (style/view-button-container true)}
|
||||
children]
|
||||
|
||||
(not show-keyboard?)
|
||||
[rn/view {:style (style/view-button-container false)}
|
||||
children])]))
|
||||
|
||||
(defn- page
|
||||
[{:keys [onboarding-profile-data navigation-bar-top]}]
|
||||
(reagent/with-let [show-keyboard? (reagent/atom false)
|
||||
content-scroll-y (reagent/atom 0)
|
||||
show-listener (oops/ocall rn/keyboard
|
||||
"addListener"
|
||||
(if platform/android?
|
||||
"keyboardDidShow"
|
||||
"keyboardWillShow")
|
||||
#(reset! show-keyboard? true))
|
||||
hide-listener (oops/ocall rn/keyboard
|
||||
"addListener"
|
||||
(if platform/android?
|
||||
"keyboardDidHide"
|
||||
"keyboardWillHide")
|
||||
#(reset! show-keyboard? false))
|
||||
{:keys [image-path display-name color]} onboarding-profile-data
|
||||
full-name (reagent/atom display-name)
|
||||
validation-msg (reagent/atom
|
||||
(profile-validator/validation-name
|
||||
@full-name))
|
||||
on-change-text (fn [s]
|
||||
(reset! validation-msg
|
||||
(profile-validator/validation-name
|
||||
s))
|
||||
(reset! full-name (string/trim s)))
|
||||
custom-color (reagent/atom (or color
|
||||
c/profile-default-color))
|
||||
profile-pic (reagent/atom image-path)
|
||||
on-change-profile-pic #(reset! profile-pic %)
|
||||
on-change #(reset! custom-color %)]
|
||||
(let [name-too-short? (profile-validator/name-too-short? @full-name)
|
||||
valid-name? (and (not @validation-msg) (not name-too-short?))
|
||||
info-message (if @validation-msg
|
||||
@validation-msg
|
||||
(i18n/label :t/minimum-characters
|
||||
{:min-chars
|
||||
profile-validator/min-length}))
|
||||
info-type (cond @validation-msg :error
|
||||
name-too-short? :default
|
||||
:else :success)
|
||||
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
show-background? (show-button-background keyboard-height
|
||||
keyboard-shown
|
||||
@content-scroll-y)
|
||||
{window-width :width} (rn/get-window)]
|
||||
[rn/view {:style style/page-container}
|
||||
[quo/page-nav
|
||||
{:margin-top navigation-bar-top
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[rn/scroll-view
|
||||
{:on-layout (fn [event]
|
||||
(let [height (oops/oget event "nativeEvent.layout.height")]
|
||||
(reset! scroll-view-height height)
|
||||
(reset! content-scroll-y 0)))
|
||||
:on-scroll (fn [event]
|
||||
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
|
||||
(reset! content-scroll-y y)))
|
||||
:scroll-event-throttle 64
|
||||
:content-container-style {:flexGrow 1}}
|
||||
[rn/view
|
||||
{:on-layout (fn [event]
|
||||
(let [height (oops/oget event "nativeEvent.layout.height")]
|
||||
(reset! content-container-height height)))}
|
||||
[rn/view
|
||||
{:style style/content-container}
|
||||
[quo/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style style/title} (i18n/label :t/create-profile)]
|
||||
[rn/view
|
||||
{:style style/input-container}
|
||||
[rn/view
|
||||
{:style style/profile-input-container}
|
||||
[quo/profile-input
|
||||
{:customization-color @custom-color
|
||||
:placeholder (i18n/label :t/your-name)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[profile-picture-picker/view
|
||||
{:on-result on-change-profile-pic
|
||||
:has-picture? false}])
|
||||
:shell? true}]))
|
||||
:image-picker-props {:profile-picture @profile-pic
|
||||
:full-name (if (seq @full-name)
|
||||
@full-name
|
||||
(i18n/label :t/your-name))
|
||||
:customization-color @custom-color}
|
||||
:title-input-props {:default-value display-name
|
||||
:auto-focus true
|
||||
:max-length c/profile-name-max-length
|
||||
:on-change-text on-change-text}}]]
|
||||
|
||||
[quo/info-message
|
||||
{:status info-type
|
||||
:size :default
|
||||
:icon (if valid-name? :i/positive-state :i/info)
|
||||
:color (when (= :default info-type) colors/white-70-blur)
|
||||
:container-style style/info-message}
|
||||
info-message]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/color-title}
|
||||
(i18n/label :t/accent-colour)]]]
|
||||
[quo/color-picker
|
||||
{:blur? true
|
||||
:default-selected :blue
|
||||
:on-change on-change
|
||||
:window-width window-width
|
||||
:container-style {:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
|
||||
window-width)}}]]]
|
||||
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style {:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0}
|
||||
:pointer-events :box-none}
|
||||
[button-container @show-keyboard? keyboard-shown show-background? keyboard-height
|
||||
[quo/button
|
||||
{:accessibility-label :submit-create-profile-button
|
||||
:type :primary
|
||||
:customization-color @custom-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:onboarding/profile-data-set
|
||||
{:image-path @profile-pic
|
||||
:display-name @full-name
|
||||
:color @custom-color}]))
|
||||
:container-style style/continue-button
|
||||
:disabled? (or (not valid-name?) (not (seq @full-name)))}
|
||||
(i18n/label :t/continue)]]]])
|
||||
(finally
|
||||
(oops/ocall show-listener "remove")
|
||||
(oops/ocall hide-listener "remove"))))
|
||||
|
||||
(defn create-profile
|
||||
[]
|
||||
(let [{:keys [top]} (safe-area/get-insets)
|
||||
onboarding-profile-data (rf/sub [:onboarding/profile])]
|
||||
[page
|
||||
{:navigation-bar-top top
|
||||
:onboarding-profile-data onboarding-profile-data}]))
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.onboarding.events
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im.common.biometric.events
|
||||
[status-im.constants :as constants]
|
||||
@@ -111,63 +112,57 @@
|
||||
(rf/reg-event-fx
|
||||
:onboarding/password-set
|
||||
(fn [{:keys [db]} [masked-password]]
|
||||
(let [biometric-supported-type (get-in db [:biometrics :supported-type])]
|
||||
(let [biometric-supported-type (get-in db [:biometrics :supported-type])
|
||||
from-screen (get db
|
||||
:onboarding/navigated-to-enter-seed-phrase-from-screen
|
||||
:screen/onboarding.new-to-status)]
|
||||
{:db (-> db
|
||||
(assoc-in [:onboarding/profile :password] masked-password)
|
||||
(assoc-in [:onboarding/profile :auth-method] constants/auth-method-password))
|
||||
:fx [[:dispatch
|
||||
(if biometric-supported-type
|
||||
[:navigate-to-within-stack
|
||||
[:screen/onboarding.enable-biometrics
|
||||
(get db
|
||||
:onboarding/navigated-to-enter-seed-phrase-from-screen
|
||||
:screen/onboarding.new-to-status)]]
|
||||
[:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]]
|
||||
[:onboarding/create-account-and-login])]]})))
|
||||
|
||||
(rf/defn navigate-to-enable-biometrics
|
||||
{:events [:onboarding/navigate-to-enable-biometrics]}
|
||||
[{:keys [db]}]
|
||||
(let [supported-type (get-in db [:biometrics :supported-type])]
|
||||
{:dispatch (if supported-type
|
||||
[:open-modal :screen/onboarding.enable-biometrics]
|
||||
[:open-modal :screen/onboarding.enable-notifications])}))
|
||||
(rf/reg-event-fx
|
||||
:onboarding/navigate-to-enable-biometrics
|
||||
(fn [{:keys [db]}]
|
||||
(let [supported-type (get-in db [:biometrics :supported-type])]
|
||||
{:dispatch (if supported-type
|
||||
[:open-modal :screen/onboarding.enable-biometrics]
|
||||
[:open-modal :screen/onboarding.enable-notifications])})))
|
||||
|
||||
(rf/defn seed-phrase-validated
|
||||
{:events [:onboarding/seed-phrase-validated]}
|
||||
[{:keys [db]} seed-phrase key-uid]
|
||||
(let [syncing-account-recovered? (and (seq (:syncing/key-uid db))
|
||||
(= (:syncing/key-uid db) key-uid))
|
||||
next-screen (if syncing-account-recovered?
|
||||
:screen/onboarding.create-profile-password
|
||||
:screen/onboarding.create-profile)]
|
||||
(if (contains? (:profile/profiles-overview db) key-uid)
|
||||
{:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
|
||||
(re-frame/dispatch
|
||||
[:profile/profile-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}}
|
||||
{:db (-> db
|
||||
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
|
||||
(assoc-in [:onboarding/profile :key-uid] key-uid)
|
||||
(assoc-in [:onboarding/profile :color] constants/profile-default-color))
|
||||
:fx [[:dispatch
|
||||
[:navigate-to-within-stack
|
||||
[next-screen
|
||||
(get db
|
||||
:onboarding/navigated-to-enter-seed-phrase-from-screen
|
||||
:screen/onboarding.new-to-status)]]]]})))
|
||||
(rf/reg-event-fx
|
||||
:onboarding/seed-phrase-validated
|
||||
(fn [{:keys [db]} [seed-phrase key-uid]]
|
||||
(let [next-screen :screen/onboarding.create-profile-password
|
||||
from-screen (get db
|
||||
:onboarding/navigated-to-enter-seed-phrase-from-screen
|
||||
:screen/onboarding.new-to-status)]
|
||||
(if (contains? (:profile/profiles-overview db) key-uid)
|
||||
{:fx [[:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
|
||||
(re-frame/dispatch [:profile/profile-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}]]}
|
||||
{:db (-> db
|
||||
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
|
||||
(assoc-in [:onboarding/profile :key-uid] key-uid)
|
||||
(assoc-in [:onboarding/profile :color] constants/profile-default-color))
|
||||
:fx [[:dispatch [:navigate-to-within-stack [next-screen from-screen]]]]}))))
|
||||
|
||||
(rf/defn navigate-to-create-profile
|
||||
{:events [:onboarding/navigate-to-create-profile]}
|
||||
[{:keys [db]}]
|
||||
;; Restart the flow
|
||||
{:db (dissoc db :onboarding/profile)
|
||||
:dispatch [:navigate-to-within-stack
|
||||
[:screen/onboarding.create-profile :screen/onboarding.new-to-status]]})
|
||||
(rf/reg-event-fx
|
||||
:onboarding/navigate-to-create-profile
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(assoc-in [:onboarding/profile :color] (rand-nth colors/account-colors))
|
||||
(update :onboarding/profile dissoc :image-path))
|
||||
:fx [[:dispatch
|
||||
[:navigate-to-within-stack
|
||||
[:screen/onboarding.create-profile-password :screen/onboarding.new-to-status]]]]}))
|
||||
|
||||
(rf/reg-event-fx :onboarding/navigate-to-sign-in-by-syncing
|
||||
(fn [{:keys [db]}]
|
||||
@@ -180,26 +175,43 @@
|
||||
(fn [{:keys [db]} [auth-method]]
|
||||
{:db (assoc db :auth-method auth-method)}))
|
||||
|
||||
(rf/defn onboarding-new-account-finalize-setup
|
||||
{:events [:onboarding/finalize-setup]}
|
||||
[{:keys [db]}]
|
||||
(let [masked-password (get-in db [:onboarding/profile :password])
|
||||
key-uid (get-in db [:profile/profile :key-uid])
|
||||
syncing? (get-in db [:onboarding/profile :syncing?])
|
||||
auth-method (get-in db [:onboarding/profile :auth-method])
|
||||
biometric-enabled? (= auth-method constants/auth-method-biometric)]
|
||||
(cond-> {:db (assoc db :onboarding/generated-keys? true)}
|
||||
biometric-enabled?
|
||||
(assoc :keychain/save-password-and-auth-method
|
||||
{:key-uid key-uid
|
||||
:masked-password (if syncing?
|
||||
masked-password
|
||||
(security/hash-masked-password masked-password))
|
||||
:on-success (fn []
|
||||
(rf/dispatch [:onboarding/set-auth-method auth-method])
|
||||
(when syncing?
|
||||
(rf/dispatch
|
||||
[:onboarding/navigate-to-enable-notifications-from-syncing])))
|
||||
:on-error #(log/error "failed to save biometrics"
|
||||
{:key-uid key-uid
|
||||
:error %})}))))
|
||||
(def ^:const temp-display-name
|
||||
"While creating a profile, we cannot use an empty string; this value works as a
|
||||
placeholder that will be updated later once the compressed key exists. See
|
||||
`status-im.contexts.profile.edit.name.events/get-default-display-name` for more details."
|
||||
"temporal username")
|
||||
|
||||
(rf/reg-event-fx
|
||||
:onboarding/use-temporary-display-name
|
||||
(fn [{:keys [db]} [temporary-display-name?]]
|
||||
{:db (assoc db
|
||||
:onboarding/profile
|
||||
{:temporary-display-name? temporary-display-name?
|
||||
:display-name (if temporary-display-name?
|
||||
temp-display-name
|
||||
"")})}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:onboarding/finalize-setup
|
||||
(fn [{db :db}]
|
||||
(let [{:keys [password syncing? auth-method
|
||||
temporary-display-name?]} (:onboarding/profile db)
|
||||
{:keys [key-uid] :as profile} (:profile/profile db)
|
||||
biometric-enabled? (= auth-method constants/auth-method-biometric)]
|
||||
{:db (assoc db :onboarding/generated-keys? true)
|
||||
:fx [(when temporary-display-name?
|
||||
[:dispatch [:profile/set-default-profile-name profile]])
|
||||
(when biometric-enabled?
|
||||
[:keychain/save-password-and-auth-method
|
||||
{:key-uid key-uid
|
||||
:masked-password (if syncing?
|
||||
password
|
||||
(security/hash-masked-password password))
|
||||
:on-success (fn []
|
||||
(rf/dispatch [:onboarding/set-auth-method auth-method])
|
||||
(when syncing?
|
||||
(rf/dispatch
|
||||
[:onboarding/navigate-to-enable-notifications-from-syncing])))
|
||||
:on-error #(log/error "failed to save biometrics"
|
||||
{:key-uid key-uid
|
||||
:error %})}])]})))
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:onboarding/use-temporary-display-name false])
|
||||
(rf/dispatch [:open-modal
|
||||
:screen/onboarding.share-usage
|
||||
{:next-screen :screen/onboarding.sync-or-recover-profile}]))
|
||||
@@ -60,6 +61,7 @@
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:onboarding/use-temporary-display-name true])
|
||||
(rf/dispatch [:open-modal :screen/onboarding.share-usage
|
||||
{:next-screen :screen/onboarding.new-to-status}]))
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(ns status-im.contexts.onboarding.share-usage.style)
|
||||
(ns status-im.contexts.onboarding.share-usage.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def title-container
|
||||
{:margin-horizontal 20
|
||||
@@ -16,3 +17,7 @@
|
||||
[insets]
|
||||
{:margin 20
|
||||
:margin-bottom (+ 12 (:bottom insets))})
|
||||
|
||||
(def page
|
||||
{:flex 1
|
||||
:background-color colors/neutral-100})
|
||||
|
||||
@@ -17,35 +17,38 @@
|
||||
(rf/dispatch [:navigate-to-within-stack [next-screen :screen/onboarding.share-usage]]) ;; Onboarding
|
||||
(rf/dispatch [:navigate-back]))) ;; Login Screen
|
||||
|
||||
(defn- learn-more
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content learn-more-sheet/view
|
||||
:shell? true}]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [insets (safe-area/get-insets)
|
||||
next-screen (:next-screen (rf/sub [:get-screen-params :screen/onboarding.share-usage]))
|
||||
share-usage-data (rn/use-callback #(share-usage-data-fn true next-screen))
|
||||
maybe-later (rn/use-callback #(share-usage-data-fn false next-screen))
|
||||
learn-more (rn/use-callback #(rf/dispatch [:show-bottom-sheet
|
||||
{:content learn-more-sheet/view
|
||||
:shell? true}]))]
|
||||
[:<>
|
||||
maybe-later (rn/use-callback #(share-usage-data-fn false next-screen))]
|
||||
[rn/view {:style style/page}
|
||||
[quo/page-nav
|
||||
{:margin-top (:top insets)
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:icon-name :i/close
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [{:icon-left :i/info
|
||||
:accessibility-label :learn-more
|
||||
:label (i18n/label :t/learn-more)
|
||||
:on-press learn-more}]}]
|
||||
[quo/text-combinations
|
||||
{:container-style style/title-container
|
||||
:title (i18n/label :t/help-us-improve-status)
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/help-us-improve-status)
|
||||
:title-accessibility-label :share-usage-title
|
||||
:description (i18n/label :t/collecting-usage-data)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/collecting-usage-data)
|
||||
:description-accessibility-label :share-usage-subtitle}]
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:style (style/page-illustration (:width (rn/get-window)))
|
||||
:source (resources/get-image :biometrics)}]
|
||||
:source (resources/get-image :usage-data)}]
|
||||
[rn/view {:style (style/buttons insets)}
|
||||
[quo/button
|
||||
{:size 40
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
(ns status-im.contexts.profile.edit.name.events
|
||||
(:require [utils.i18n :as i18n]
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-profile-name-success
|
||||
@@ -20,3 +22,16 @@
|
||||
:on-success [:profile/edit-profile-name-success]}]]]})
|
||||
|
||||
(rf/reg-event-fx :profile/edit-name edit-profile-name)
|
||||
|
||||
(defn display-name-from-compressed-key
|
||||
[profile]
|
||||
(-> profile :compressed-key (string/split #"zQ3") second (subs 0 constants/profile-name-max-length)))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/set-default-profile-name
|
||||
(fn [{db :db} [profile]]
|
||||
(let [default-display-name (display-name-from-compressed-key profile)]
|
||||
{:db (assoc-in db [:profile/profile :display-name] default-display-name)
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setDisplayName"
|
||||
:params [default-display-name]}]]]})))
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
{:dataDir (native-module/backup-disabled-data-dir)
|
||||
:mixpanelAppId config/mixpanel-app-id
|
||||
:mixpanelToken config/mixpanel-token
|
||||
:sentryDSN config/sentry-dsn-status-go
|
||||
:mediaServerEnableTLS (config/enabled? config/STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS)
|
||||
:logEnabled (not (string/blank? config/log-level))
|
||||
:logLevel config/log-level
|
||||
|
||||
@@ -152,15 +152,12 @@
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile.login/login-node-signal
|
||||
(fn [{{:onboarding/keys [recovered-account? new-account?] :as db} :db}
|
||||
[{:keys [settings account ensUsernames error]}]]
|
||||
(fn [{db :db} [{:keys [settings account ensUsernames error]}]]
|
||||
(log/debug "[signals] node.login" "error" error)
|
||||
(if error
|
||||
{:db (update db :profile/login #(-> % (dissoc :processing) (assoc :error error)))}
|
||||
{:db (dissoc db :profile/login)
|
||||
:fx [(when (and new-account? (not recovered-account?))
|
||||
[:dispatch-later [{:ms 1000 :dispatch [:wallet-legacy/set-initial-blocks-range]}]])
|
||||
[:dispatch-later [{:ms 2000 :dispatch [:ens/update-usernames ensUsernames]}]]
|
||||
:fx [[:dispatch-later [{:ms 2000 :dispatch [:ens/update-usernames ensUsernames]}]]
|
||||
[:dispatch [:profile.login/login-existing-profile settings account]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
[]
|
||||
(when @push-animation-fn-atom
|
||||
(@push-animation-fn-atom))
|
||||
(rf/dispatch [:onboarding/use-temporary-display-name true])
|
||||
(debounce/throttle-and-dispatch
|
||||
[:open-modal :screen/onboarding.new-to-status]
|
||||
1000))
|
||||
@@ -55,6 +56,7 @@
|
||||
[]
|
||||
(when @push-animation-fn-atom
|
||||
(@push-animation-fn-atom))
|
||||
(rf/dispatch [:onboarding/use-temporary-display-name false])
|
||||
(debounce/throttle-and-dispatch
|
||||
[:open-modal :screen/onboarding.sync-or-recover-profile]
|
||||
1000))
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
:blur? true
|
||||
:image-props :i/light})]
|
||||
[{:title (i18n/label :t/about)
|
||||
:on-press #(rf/dispatch [:open-modal :about-app])
|
||||
:on-press #(rf/dispatch [:open-modal :screen/settings.about])
|
||||
:action :arrow
|
||||
:blur? true}
|
||||
{:title (i18n/label :t/status-help)
|
||||
|
||||
@@ -7,33 +7,37 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- on-press-biometric-enable
|
||||
[button-label theme]
|
||||
[button-label theme keycard-profile?]
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:standard-auth/authorize-with-password
|
||||
{:blur? true
|
||||
:theme theme
|
||||
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
|
||||
:on-auth-success (fn [password]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch
|
||||
[:biometric/authenticate
|
||||
{:on-success #(rf/dispatch [:biometric/enable password])
|
||||
:on-fail #(rf/dispatch [:biometric/show-message (ex-cause %)])}]))}])))
|
||||
(if keycard-profile?
|
||||
(rf/dispatch [:keycard/feature-unavailable-show {:theme :dark}])
|
||||
(rf/dispatch
|
||||
[:standard-auth/authorize-with-password
|
||||
{:blur? true
|
||||
:theme theme
|
||||
:auth-button-label (i18n/label :t/biometric-enable-button {:bio-type-label button-label})
|
||||
:on-auth-success (fn [password]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch
|
||||
[:biometric/authenticate
|
||||
{:on-success #(rf/dispatch [:biometric/enable password])
|
||||
:on-fail #(rf/dispatch [:biometric/show-message
|
||||
(ex-cause %)])}]))}]))))
|
||||
|
||||
(defn- get-biometric-item
|
||||
[theme]
|
||||
(let [auth-method (rf/sub [:auth-method])
|
||||
biometric-type (rf/sub [:biometrics/supported-type])
|
||||
label (biometric/get-label-by-type biometric-type)
|
||||
icon (biometric/get-icon-by-type biometric-type)
|
||||
supported? (boolean biometric-type)
|
||||
enabled? (= auth-method constants/auth-method-biometric)
|
||||
biometric-on? (and supported? enabled?)
|
||||
press-handler (when supported?
|
||||
(if biometric-on?
|
||||
(fn [] (rf/dispatch [:biometric/disable]))
|
||||
(on-press-biometric-enable label theme)))]
|
||||
(let [auth-method (rf/sub [:auth-method])
|
||||
biometric-type (rf/sub [:biometrics/supported-type])
|
||||
keycard-profile? (rf/sub [:keycard/keycard-profile?])
|
||||
label (biometric/get-label-by-type biometric-type)
|
||||
icon (biometric/get-icon-by-type biometric-type)
|
||||
supported? (boolean biometric-type)
|
||||
enabled? (= auth-method constants/auth-method-biometric)
|
||||
biometric-on? (and supported? enabled?)
|
||||
press-handler (when supported?
|
||||
(if biometric-on?
|
||||
(fn [] (rf/dispatch [:biometric/disable]))
|
||||
(on-press-biometric-enable label theme keycard-profile?)))]
|
||||
{:title label
|
||||
:image-props icon
|
||||
:image :icon
|
||||
@@ -58,7 +62,8 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
keycard-profile? (rf/sub [:keycard/keycard-profile?])]
|
||||
[quo/overlay {:type :shell :top-inset? true}
|
||||
[quo/page-nav
|
||||
{:background :blur
|
||||
@@ -68,6 +73,7 @@
|
||||
[quo/category
|
||||
{:key :category
|
||||
:data [(get-biometric-item theme)
|
||||
(get-change-password-item)]
|
||||
(when-not keycard-profile?
|
||||
(get-change-password-item))]
|
||||
:blur? true
|
||||
:list-type :settings}]]))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
(ns status-im.contexts.settings.about.style)
|
||||
|
||||
(def category-spacing {:padding-bottom 12})
|
||||
|
||||
(def app-info-container
|
||||
{:padding-horizontal 20
|
||||
:padding-top 8
|
||||
:padding-bottom 16
|
||||
:row-gap 16})
|
||||
@@ -0,0 +1,101 @@
|
||||
(ns status-im.contexts.settings.about.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.about.style :as style]
|
||||
[status-im.contexts.settings.common.header :as header]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- open-link
|
||||
[url]
|
||||
(rf/dispatch [:browser.ui/open-url url]))
|
||||
|
||||
(defn- copy
|
||||
[data item-name]
|
||||
(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy data
|
||||
:post-copy-message (str item-name
|
||||
" "
|
||||
(i18n/label :t/sharing-copied-to-clipboard))}]))
|
||||
|
||||
(def about-data
|
||||
[{:app-info? true}
|
||||
{:category-label (i18n/label :t/website)
|
||||
:items [{:title "status.app"
|
||||
:on-press #(open-link constants/status-app-url)
|
||||
:blur? true
|
||||
:action :arrow
|
||||
:action-props {:icon :i/external}}]}
|
||||
{:category-label (i18n/label :t/github-repos)
|
||||
:items [{:title "status-mobile"
|
||||
:on-press #(open-link constants/status-mobile-url)
|
||||
:blur? true
|
||||
:action :arrow
|
||||
:action-props {:icon :i/external}}
|
||||
{:title "status-go"
|
||||
:on-press #(open-link constants/status-go-url)
|
||||
:blur? true
|
||||
:action :arrow
|
||||
:action-props {:icon :i/external}}
|
||||
{:title "go-waku"
|
||||
:on-press #(open-link constants/go-waku-url)
|
||||
:blur? true
|
||||
:action :arrow
|
||||
:action-props {:icon :i/external}}]}
|
||||
{:category-label (i18n/label :t/documents)
|
||||
:items [{:title (i18n/label :t/privacy-policy)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/settings.privacy-policy])
|
||||
:blur? true
|
||||
:action :arrow}
|
||||
{:title (i18n/label :t/terms-of-service)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/settings.terms-of-use])
|
||||
:blur? true
|
||||
:action :arrow}]}])
|
||||
|
||||
(defn info-item
|
||||
[{:keys [title info]}]
|
||||
[quo/data-item
|
||||
{:size :default
|
||||
:status :default
|
||||
:right-icon :i/copy
|
||||
:card? true
|
||||
:blur? true
|
||||
:title title
|
||||
:on-press #(copy info title)
|
||||
:subtitle info
|
||||
:subtitle-type :default
|
||||
:subtitle-text-props {:number-of-lines 1
|
||||
:ellipsize-mode :middle}}])
|
||||
|
||||
(defn- app-info
|
||||
[]
|
||||
(let [app-version (rf/sub [:get-app-short-version])
|
||||
commit-hash (rf/sub [:get-commit-hash])
|
||||
node-version (rf/sub [:get-app-node-version])]
|
||||
[rn/view {:style style/app-info-container}
|
||||
[info-item {:title (i18n/label :t/version) :info app-version}]
|
||||
[info-item {:title (i18n/label :t/app-commit) :info commit-hash}]
|
||||
[info-item {:title (i18n/label :t/node-version) :info node-version}]]))
|
||||
|
||||
(defn category
|
||||
[{:keys [app-info? category-label items]}]
|
||||
(if app-info?
|
||||
[app-info]
|
||||
[quo/category
|
||||
{:label category-label
|
||||
:list-type :settings
|
||||
:container-style style/category-spacing
|
||||
:blur? true
|
||||
:data items}]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[quo/overlay {:type :shell}
|
||||
[header/view {:title (i18n/label :t/about)}]
|
||||
[rn/flat-list
|
||||
{:data about-data
|
||||
:shows-vertical-scroll-indicator false
|
||||
:render-fn category
|
||||
:bounces false
|
||||
:over-scroll-mode :never}]])
|
||||
@@ -0,0 +1,14 @@
|
||||
(ns status-im.contexts.settings.common.header
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.events-helper :as events-helper]))
|
||||
|
||||
(defn view
|
||||
[{:keys [title]}]
|
||||
[rn/view {:style {:padding-top (safe-area/get-top)}}
|
||||
[quo/page-nav
|
||||
{:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top {:title title}]])
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
(defn- keypair
|
||||
[{keypair-type :type
|
||||
:keys [accounts name]
|
||||
:keys [accounts name keycard?]
|
||||
:as item}
|
||||
_ _
|
||||
{:keys [profile-picture compressed-key customization-color]}]
|
||||
@@ -59,7 +59,7 @@
|
||||
:type (if default-keypair?
|
||||
:default-keypair
|
||||
:keypair)
|
||||
:stored :on-device
|
||||
:stored (if keycard? :on-keycard :on-device)
|
||||
:shortened-key shortened-key
|
||||
:customization-color customization-color
|
||||
:profile-picture profile-picture})}))
|
||||
@@ -68,7 +68,7 @@
|
||||
[quo/keypair
|
||||
{:blur? true
|
||||
:status-indicator false
|
||||
:stored :on-device
|
||||
:stored (if keycard? :on-keycard :on-device)
|
||||
:action (if default-keypair? :none :options)
|
||||
:accounts accounts
|
||||
:customization-color customization-color
|
||||
|
||||
@@ -38,7 +38,11 @@
|
||||
#(if (:enabled? %)
|
||||
:paired-devices
|
||||
:unpaired-devices)
|
||||
other-devices)]
|
||||
other-devices)
|
||||
keycard? (rf/sub [:keycard/keycard-profile?])
|
||||
keycard-feature-unavailable (rn/use-callback
|
||||
#(rf/dispatch [:keycard/feature-unavailable-show
|
||||
{:theme :dark}]))]
|
||||
[quo/overlay {:type :shell :top-inset? true}
|
||||
[quo/page-nav
|
||||
{:type :no-title
|
||||
@@ -60,7 +64,9 @@
|
||||
:type :primary
|
||||
:customization-color profile-color
|
||||
:icon-only? true
|
||||
:on-press open-setup-syncing-with-customization-color}
|
||||
:on-press (if keycard?
|
||||
keycard-feature-unavailable
|
||||
open-setup-syncing-with-customization-color)}
|
||||
:i/add]]
|
||||
[device/view (merge user-device {:this-device? true})]
|
||||
(when (seq paired-devices)
|
||||
|
||||
@@ -69,7 +69,9 @@
|
||||
(let [{:keys [customization-color] :as profile} (rf/sub [:profile/profile-with-image])
|
||||
{:keys [address path watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
{keypair-name :name
|
||||
keypair-type :type} (rf/sub [:wallet/current-viewing-account-keypair])
|
||||
keypair-type :type
|
||||
keycards :keycards} (rf/sub [:wallet/current-viewing-account-keypair])
|
||||
keypair-keycard? (boolean (seq keycards))
|
||||
networks (rf/sub [:wallet/network-preference-details])
|
||||
origin-type (case keypair-type
|
||||
:seed
|
||||
@@ -98,7 +100,7 @@
|
||||
(when (not watch-only?)
|
||||
[quo/account-origin
|
||||
{:type origin-type
|
||||
:stored :on-device
|
||||
:stored (if keypair-keycard? :on-keycard :on-device)
|
||||
:profile-picture (profile.utils/photo profile)
|
||||
:customization-color customization-color
|
||||
:derivation-path path
|
||||
|
||||
@@ -58,13 +58,14 @@
|
||||
[item _ _
|
||||
{:keys [profile-picture compressed-key selected-key-uid set-selected-key-uid customization-color]}]
|
||||
(let [profile-keypair? (= (:type item) :profile)
|
||||
keycard? (boolean (seq (:keycards item)))
|
||||
accounts (parse-accounts (:accounts item))]
|
||||
[quo/keypair
|
||||
{:customization-color customization-color
|
||||
:profile-picture (when profile-keypair? profile-picture)
|
||||
:status-indicator false
|
||||
:type (if profile-keypair? :default-keypair :other)
|
||||
:stored :on-device
|
||||
:stored (if keycard? :on-keycard :on-device)
|
||||
:on-options-press #(js/alert "Options pressed")
|
||||
:action :selector
|
||||
:blur? false
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
[utils.string]))
|
||||
|
||||
(defn- get-keypair-data
|
||||
[{:keys [title primary-keypair? new-keypair? derivation-path customization-color]}]
|
||||
[{:keys [title primary-keypair? new-keypair? derivation-path customization-color keycard?]}]
|
||||
[{:title title
|
||||
:image (if primary-keypair? :avatar :icon)
|
||||
:image-props (if primary-keypair?
|
||||
@@ -35,7 +35,7 @@
|
||||
:button-text (i18n/label :t/edit)
|
||||
:alignment :flex-start}
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/on-device)}}
|
||||
:description-props {:text (i18n/label (if keycard? :on-keycard :on-device))}}
|
||||
(when-not (string/blank? derivation-path)
|
||||
(let [formatted-path (string/replace derivation-path #"/" " / ")
|
||||
on-auth-success (fn [password]
|
||||
@@ -123,7 +123,7 @@
|
||||
:container-style color-picker-style}]])])))
|
||||
|
||||
(defn- new-account-origin
|
||||
[{:keys [keypair-title derivation-path customization-color]}]
|
||||
[{:keys [keypair-title derivation-path customization-color keycard?]}]
|
||||
(let [{keypair-name :name} (rf/sub [:wallet/selected-keypair])
|
||||
primary? (rf/sub [:wallet/selected-primary-keypair?])
|
||||
keypair-name (or keypair-title
|
||||
@@ -135,7 +135,8 @@
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:label (i18n/label :t/origin)
|
||||
:data (get-keypair-data {:primary-keypair? primary?
|
||||
:data (get-keypair-data {:keycard? keycard?
|
||||
:primary-keypair? primary?
|
||||
:title keypair-name
|
||||
:derivation-path derivation-path
|
||||
:customization-color customization-color})}]]))
|
||||
@@ -229,20 +230,37 @@
|
||||
set-derivation-path #(reset! derivation-path %)]
|
||||
(fn [{:keys [on-change-text set-account-color set-emoji customization-color error]}]
|
||||
(let [{:keys [derived-from
|
||||
key-uid]} (rf/sub [:wallet/selected-keypair])
|
||||
on-auth-success (rn/use-callback
|
||||
(fn [password]
|
||||
(let [preferences {:account-name @account-name
|
||||
:color @account-color
|
||||
:emoji @emoji}]
|
||||
(rf/dispatch
|
||||
[:wallet/derive-address-and-add-account
|
||||
{:password password
|
||||
:derived-from-address derived-from
|
||||
:key-uid key-uid
|
||||
:derivation-path @derivation-path
|
||||
:account-preferences preferences}])))
|
||||
[derived-from])]
|
||||
key-uid keycards]} (rf/sub [:wallet/selected-keypair])
|
||||
keycard? (boolean (seq keycards))
|
||||
on-auth-success (rn/use-callback
|
||||
(fn [password]
|
||||
(let [preferences {:account-name @account-name
|
||||
:color @account-color
|
||||
:emoji @emoji}]
|
||||
(rf/dispatch
|
||||
[:wallet/derive-address-and-add-account
|
||||
{:password password
|
||||
:derived-from-address derived-from
|
||||
:key-uid key-uid
|
||||
:derivation-path @derivation-path
|
||||
:account-preferences preferences}])))
|
||||
[derived-from])
|
||||
on-complete (rn/use-callback
|
||||
(fn []
|
||||
(let [preferences {:account-name @account-name
|
||||
:color @account-color
|
||||
:emoji @emoji}]
|
||||
(rf/dispatch
|
||||
[:standard-auth/authorize-with-keycard
|
||||
{:on-complete
|
||||
#(rf/dispatch
|
||||
[:keycard/connect-derive-address-and-add-account
|
||||
{:pin %
|
||||
:derived-from-address derived-from
|
||||
:key-uid key-uid
|
||||
:derivation-path @derivation-path
|
||||
:account-preferences preferences}])}])))
|
||||
[derived-from])]
|
||||
(rn/use-effect
|
||||
#(rf/dispatch
|
||||
[:wallet/next-derivation-path
|
||||
@@ -252,10 +270,13 @@
|
||||
|
||||
[floating-button
|
||||
{:account-color @account-color
|
||||
:slide-button-props {:on-auth-success on-auth-success
|
||||
:disabled? (or (empty? @account-name)
|
||||
(string/blank? @derivation-path)
|
||||
(some? error))}}
|
||||
:slide-button-props {:on-auth-success (when-not keycard? on-auth-success)
|
||||
:on-complete
|
||||
(when keycard? on-complete)
|
||||
:disabled?
|
||||
(or (empty? @account-name)
|
||||
(string/blank? @derivation-path)
|
||||
(some? error))}}
|
||||
[avatar
|
||||
{:account-color @account-color
|
||||
:emoji @emoji
|
||||
@@ -269,7 +290,8 @@
|
||||
{:account-color @account-color
|
||||
:set-account-color set-account-color}]
|
||||
[new-account-origin
|
||||
{:derivation-path @derivation-path
|
||||
{:keycard? keycard?
|
||||
:derivation-path @derivation-path
|
||||
:customization-color customization-color}]]))))
|
||||
|
||||
(defn view
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
type :no-title}}]
|
||||
(let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
networks (rf/sub [:wallet/selected-network-details])
|
||||
sending-collectible? (rf/sub [:wallet/sending-collectible?])]
|
||||
sending-collectible? (rf/sub [:wallet/sending-collectible?])
|
||||
keycard? (rf/sub [:wallet/selected-keypair-keycard?])]
|
||||
[quo/page-nav
|
||||
{:type type
|
||||
:icon-name icon-name
|
||||
@@ -45,7 +46,10 @@
|
||||
(not watch-only?)
|
||||
show-dapps-button?)
|
||||
{:icon-name :i/dapps
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})
|
||||
:on-press #(rf/dispatch
|
||||
(if keycard?
|
||||
[:keycard/feature-unavailable-show]
|
||||
[:navigate-to :screen/wallet.connected-dapps]))})
|
||||
(when-not sending-collectible?
|
||||
{:content-type :account-switcher
|
||||
:customization-color color
|
||||
|
||||
@@ -404,15 +404,13 @@
|
||||
:market-values-per-token market-values-per-token}))
|
||||
calculated-tokens (map calculate-token tokens)]
|
||||
(sort-by (fn [token]
|
||||
(let [fiat-value (get-in token [:values :fiat-unformatted-value])
|
||||
priority (get constants/token-sort-priority (:token token) ##Inf)]
|
||||
[(- fiat-value) priority]))
|
||||
(let [fiat-value (get-in token [:values :fiat-unformatted-value])]
|
||||
[(- fiat-value)]))
|
||||
calculated-tokens)))
|
||||
|
||||
(defn sort-tokens
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt (comp - :balance) priority) tokens)))
|
||||
(sort-by (fn [token] (- (:balance token))) tokens))
|
||||
|
||||
(defn- transaction-data
|
||||
[{:keys [from-address to-address token-address route data eth-transfer?]}]
|
||||
@@ -543,8 +541,7 @@
|
||||
|
||||
(defn sort-tokens-by-name
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt :symbol priority) tokens)))
|
||||
(sort-by :symbol tokens))
|
||||
|
||||
(defn tokens-with-balance
|
||||
[tokens networks chain-ids]
|
||||
|
||||
@@ -291,3 +291,10 @@
|
||||
(cske/transform-keys transforms/->kebab-case-keyword)
|
||||
(map #(assoc % :unique-id (collectible-utils/get-collectible-unique-id %)))
|
||||
vec))
|
||||
|
||||
(defn selected-keypair-keycard?
|
||||
[db]
|
||||
(let [keypairs (get-in db [:wallet :keypairs])
|
||||
selected-keypair-uid (get-in db [:wallet :ui :create-account :selected-keypair-uid])
|
||||
keypair (get keypairs selected-keypair-uid)]
|
||||
(boolean (seq (:keycards keypair)))))
|
||||
|
||||
@@ -231,3 +231,37 @@
|
||||
:wallet true
|
||||
:default-account? true})]}}}
|
||||
(sut/reconcile-keypairs [raw-keypair-profile])))))
|
||||
|
||||
(def mock-db
|
||||
{:wallet {:keypairs
|
||||
{"0x123" {:type "key"
|
||||
:key-uid "0x123"
|
||||
:keycards [{:id "keycard1"}]}
|
||||
"0x456" {:type "key"
|
||||
:key-uid "0x456"
|
||||
:keycards []}}
|
||||
:ui {:create-account {:selected-keypair-uid "0x123"}}}})
|
||||
|
||||
(deftest selected-keypair-keycard?-test
|
||||
(testing "returns true when the selected keypair has keycards"
|
||||
(is (true? (sut/selected-keypair-keycard? mock-db))))
|
||||
|
||||
(testing "returns false when the selected keypair does not have keycards"
|
||||
(let [db (assoc-in mock-db [:wallet :ui :create-account :selected-keypair-uid] "0x456")]
|
||||
(is (false? (sut/selected-keypair-keycard? db)))))
|
||||
|
||||
(testing "returns false when the selected keypair does not exist"
|
||||
(let [db (assoc-in mock-db [:wallet :ui :create-account :selected-keypair-uid] "0x789")]
|
||||
(is (false? (sut/selected-keypair-keycard? db)))))
|
||||
|
||||
(testing "returns false when keypairs map is empty"
|
||||
(let [db (assoc-in mock-db [:wallet :keypairs] {})]
|
||||
(is (false? (sut/selected-keypair-keycard? db)))))
|
||||
|
||||
(testing "returns false when no keypair is selected"
|
||||
(let [db (assoc-in mock-db [:wallet :ui :create-account :selected-keypair-uid] nil)]
|
||||
(is (false? (sut/selected-keypair-keycard? db)))))
|
||||
|
||||
(testing "returns false when db does not contain wallet data"
|
||||
(let [db {}]
|
||||
(is (false? (sut/selected-keypair-keycard? db))))))
|
||||
|
||||
@@ -307,9 +307,8 @@
|
||||
|
||||
(rf/reg-event-fx :wallet/add-account
|
||||
(fn [_
|
||||
[{:keys [key-uid password account-name emoji color type]
|
||||
:or {type :generated}}
|
||||
{:keys [public-key address path] :as _derived-account}]]
|
||||
[{:keys [key-uid password account-name emoji color type] :or {type :generated}}
|
||||
{:keys [public-key address path]}]]
|
||||
(let [lowercase-address (some-> address
|
||||
string/lower-case)
|
||||
account-config {:key-uid (when (= type :generated) key-uid)
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
:wallet/wallet-send-tx-type :tx/send
|
||||
:wallet/wallet-send-fee-fiat-formatted "$5,00"
|
||||
:wallet/sending-collectible? false
|
||||
:wallet/selected-keypair-keycard? false
|
||||
:wallet/send-total-amount-formatted "250 ETH"
|
||||
:wallet/total-amount (money/bignumber "250")
|
||||
:wallet/prices-per-token {:ETH {:usd 10}}
|
||||
|
||||
@@ -248,7 +248,9 @@
|
||||
account))}
|
||||
user-props {:full-name to-address
|
||||
:address (utils/get-shortened-address
|
||||
to-address)}]
|
||||
to-address)}
|
||||
sign-on-keycard? (get-in transaction-for-signing
|
||||
[:signingDetails :signOnKeycard])]
|
||||
;; In token send flow we already have transaction built when
|
||||
;; we reach confirmation screen. But in send collectible flow
|
||||
;; routes request happens at the same time with navigation to
|
||||
@@ -279,20 +281,24 @@
|
||||
:transaction-type transaction-type}]
|
||||
(when (and (not loading-suggested-routes?) route (seq route))
|
||||
[standard-auth/slide-button
|
||||
{:keycard-supported? true
|
||||
:size :size-48
|
||||
{:size :size-48
|
||||
:track-text (if (= transaction-type :tx/bridge)
|
||||
(i18n/label :t/slide-to-bridge)
|
||||
(i18n/label :t/slide-to-send))
|
||||
:container-style {:z-index 2}
|
||||
:disabled? (not transaction-for-signing)
|
||||
:customization-color account-color
|
||||
:auth-button-label (i18n/label :t/confirm)
|
||||
:on-complete (when sign-on-keycard?
|
||||
#(rf/dispatch
|
||||
[:wallet/prepare-signatures-for-transactions
|
||||
:send
|
||||
""]))
|
||||
:on-auth-success
|
||||
(fn [data]
|
||||
(fn [psw]
|
||||
(rf/dispatch
|
||||
[:wallet/prepare-signatures-for-transactions
|
||||
:send data]))
|
||||
:auth-button-label (i18n/label :t/confirm)}])]
|
||||
[:wallet/prepare-signatures-for-transactions :send
|
||||
psw]))}])]
|
||||
:gradient-cover? true
|
||||
:customization-color (:color account)}
|
||||
[rn/view
|
||||
|
||||
@@ -217,18 +217,23 @@
|
||||
|
||||
(defn- slide-button
|
||||
[]
|
||||
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
on-auth-success (rn/use-callback
|
||||
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))]
|
||||
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing])
|
||||
sign-on-keycard? (get-in transaction-for-signing
|
||||
[:signingDetails :signOnKeycard])
|
||||
on-auth-success (rn/use-callback
|
||||
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))
|
||||
on-complete (rn/use-callback
|
||||
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap ""]))]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-sign)
|
||||
:container-style {:z-index 2}
|
||||
:customization-color (:color account)
|
||||
:disabled? (or loading-swap-proposal? (not swap-proposal))
|
||||
:keycard-supported? true
|
||||
:on-complete (when sign-on-keycard? on-complete)
|
||||
:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/confirm)}]))
|
||||
|
||||
|
||||
@@ -168,7 +168,9 @@
|
||||
transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)]
|
||||
account-color (:color account)
|
||||
sign-on-keycard? (get-in transaction-for-signing
|
||||
[:signingDetails :signOnKeycard])]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-swap)
|
||||
@@ -178,7 +180,11 @@
|
||||
(not swap-proposal)
|
||||
(not transaction-for-signing))
|
||||
:auth-button-label (i18n/label :t/confirm)
|
||||
:keycard-supported? true
|
||||
:on-complete (when sign-on-keycard?
|
||||
#(rf/dispatch
|
||||
[:wallet/prepare-signatures-for-transactions
|
||||
:swap
|
||||
""]))
|
||||
:on-auth-success (fn [data]
|
||||
(rf/dispatch [:wallet/stop-get-swap-proposal])
|
||||
(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap data]))}]))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.contexts.wallet.data-store :as wallet-data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
@@ -30,11 +31,17 @@
|
||||
expired? (-> parsed-uri
|
||||
:expiryTimestamp
|
||||
uri/timestamp-expired?)
|
||||
version-supported? (uri/version-supported? version)]
|
||||
(if (or (not valid-wc-uri?)
|
||||
(not version-supported?)
|
||||
(= network-status :offline)
|
||||
expired?)
|
||||
version-supported? (uri/version-supported? version)
|
||||
keycard? (wallet-data-store/selected-keypair-keycard? db)]
|
||||
(cond
|
||||
|
||||
keycard?
|
||||
{:fx [[:dispatch [:keycard/feature-unavailable-show]]]}
|
||||
|
||||
(or (not valid-wc-uri?)
|
||||
(not version-supported?)
|
||||
(= network-status :offline)
|
||||
expired?)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
@@ -54,6 +61,8 @@
|
||||
|
||||
:else
|
||||
(i18n/label :t/something-went-wrong))}]]]}
|
||||
|
||||
:else
|
||||
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
status-im.common.alert-banner.events
|
||||
status-im.common.alert.effects
|
||||
status-im.common.app-monitoring.events
|
||||
status-im.common.async-storage.effects
|
||||
status-im.common.emoji-picker.events
|
||||
status-im.common.font.events
|
||||
@@ -28,6 +27,7 @@
|
||||
status-im.contexts.contact.blocking.events
|
||||
status-im.contexts.keycard.effects
|
||||
status-im.contexts.keycard.events
|
||||
status-im.contexts.keycard.feature-unavailable.events
|
||||
status-im.contexts.network.effects
|
||||
status-im.contexts.network.events
|
||||
status-im.contexts.onboarding.common.overlay.events
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
(def ^:private initial-flags
|
||||
{::community.edit-account-selection (enabled-in-env? :FLAG_EDIT_ACCOUNT_SELECTION_ENABLED)
|
||||
::app-monitoring.intentional-crash true ; (enabled-in-env? :FLAG_INTENTIONAL_CRASH_ENABLED)
|
||||
|
||||
;; Feature toggled (off by default) because the desktop app disabled this
|
||||
;; feature and we want both clients in sync. We keep the code because it
|
||||
|
||||
@@ -25,16 +25,15 @@
|
||||
|
||||
(defn root-options
|
||||
[{:keys [background-color theme status-bar-theme nav-bar-color]}]
|
||||
(merge
|
||||
(statusbar-and-navbar-options theme status-bar-theme nav-bar-color)
|
||||
{:topBar {:visible false}
|
||||
:layout {:componentBackgroundColor (or background-color
|
||||
(colors/theme-colors colors/white colors/neutral-100 theme))
|
||||
:orientation ["portrait"]
|
||||
:backgroundColor (or background-color
|
||||
(colors/theme-colors colors/white
|
||||
colors/neutral-100
|
||||
theme))}}))
|
||||
(let [layout-background (or background-color
|
||||
(colors/theme-colors colors/white colors/neutral-100 theme))
|
||||
component-background (or background-color
|
||||
(colors/theme-colors colors/white colors/neutral-100 theme))]
|
||||
(assoc (statusbar-and-navbar-options theme status-bar-theme nav-bar-color)
|
||||
:topBar {:visible false}
|
||||
:layout {:componentBackgroundColor component-background
|
||||
:orientation ["portrait"]
|
||||
:backgroundColor layout-background})))
|
||||
|
||||
(defn dark-root-options
|
||||
[]
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
[status-im.common.enter-seed-phrase.view :as enter-seed-phrase]
|
||||
[status-im.common.lightbox.view :as lightbox]
|
||||
[status-im.common.pdf-viewer.view :as pdf-viewer]
|
||||
[status-im.common.privacy.view :as privacy-policy]
|
||||
[status-im.common.terms.view :as terms-of-use]
|
||||
[status-im.config :as config]
|
||||
[status-im.contexts.chat.group.create.view :as group.create]
|
||||
[status-im.contexts.chat.group.details.view :as group.details]
|
||||
@@ -43,7 +45,6 @@
|
||||
[status-im.contexts.keycard.pin.enter.view :as keycard.pin.enter]
|
||||
[status-im.contexts.onboarding.create-or-sync-profile.view :as create-or-sync-profile]
|
||||
[status-im.contexts.onboarding.create-password.view :as create-password]
|
||||
[status-im.contexts.onboarding.create-profile.view :as create-profile]
|
||||
[status-im.contexts.onboarding.enable-biometrics.view :as enable-biometrics]
|
||||
[status-im.contexts.onboarding.enable-notifications.view :as enable-notifications]
|
||||
[status-im.contexts.onboarding.identifiers.view :as identifiers]
|
||||
@@ -74,6 +75,7 @@
|
||||
[status-im.contexts.profile.settings.screens.password.view :as settings-password]
|
||||
[status-im.contexts.profile.settings.screens.syncing.view :as settings.syncing]
|
||||
[status-im.contexts.profile.settings.view :as settings]
|
||||
[status-im.contexts.settings.about.view :as settings.about]
|
||||
[status-im.contexts.settings.keycard.view :as settings.keycard]
|
||||
[status-im.contexts.settings.language-and-currency.currency.view :as settings.currency-selection]
|
||||
[status-im.contexts.settings.language-and-currency.view :as settings.language-and-currency]
|
||||
@@ -154,39 +156,39 @@
|
||||
|
||||
(def chat-screens
|
||||
[{:name :start-a-new-chat
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :messenger.new-chat}
|
||||
:options {:sheet? true}
|
||||
:component new-chat/view}
|
||||
|
||||
{:name :chat
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :messenger.chat}
|
||||
:options {:popGesture false
|
||||
:animations transitions/stack-transition-from-bottom}
|
||||
:component chat/chat}
|
||||
|
||||
{:name :screen/group-create
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :messenger.new-group}
|
||||
:options {:sheet? true
|
||||
:skip-background? true}
|
||||
:component group.create/view}
|
||||
|
||||
{:name :screen/group-details
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :messenger.group-details}
|
||||
:component group.details/view}
|
||||
|
||||
{:name :screen/group-update
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :messenger.group-update}
|
||||
:options {:sheet? true
|
||||
:skip-background? true}
|
||||
:component group.update/view}
|
||||
|
||||
{:name :screen/group-add-manage-members
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:flow :messenger
|
||||
:alias-id :messenger.group-manage-members}
|
||||
:options {:sheet? true}
|
||||
@@ -194,12 +196,12 @@
|
||||
|
||||
(def community-screens
|
||||
[{:name :discover-communities
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.discover}
|
||||
:component communities.discover/view}
|
||||
|
||||
{:name :community-overview
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.overview}
|
||||
:options {:animations transitions/stack-transition-from-bottom}
|
||||
:component communities.overview/view}
|
||||
@@ -208,79 +210,79 @@
|
||||
;; joining a community. The non-sheet screen is used when editing shared
|
||||
;; addresses after the join request was sent.
|
||||
{:name :community-account-selection-sheet
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.select-addresses-for-joining-community}
|
||||
:options {:sheet? true}
|
||||
:component communities.accounts-selection/view}
|
||||
{:name :community-account-selection
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.select-addresses-for-community}
|
||||
:options {:insets {:top? true}}
|
||||
:component communities.accounts-selection/view}
|
||||
|
||||
{:name :community-requests-to-join
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.request-to-join}
|
||||
:options {:sheet? true}
|
||||
:component join-menu/view}
|
||||
|
||||
{:name :screen/share-community
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.share-community}
|
||||
:options options/transparent-screen-options
|
||||
:component share-community/view}
|
||||
|
||||
{:name :invite-people-community
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.invite-people}
|
||||
:options {:sheet? true}
|
||||
:component communities.invite/view}
|
||||
|
||||
{:name :share-community-channel
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.share-channel}
|
||||
:options options/transparent-screen-options
|
||||
:component share-community-channel/view}
|
||||
|
||||
{:name :screen/chat.view-channel-members-and-details
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.view-channel-members-and-details}
|
||||
:options {:insets {:top? true}}
|
||||
:component channel-view-channel-members-and-details/view}
|
||||
|
||||
{:name :addresses-for-permissions
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.choose-addresses-for-permissions}
|
||||
:options {:insets {:top? true}}
|
||||
:component addresses-for-permissions/view}
|
||||
|
||||
{:name :address-for-airdrop
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :community.choose-addresses-for-airdrop}
|
||||
:options {:insets {:top? true}}
|
||||
:component airdrop-addresses/view}])
|
||||
|
||||
(def contact-screens
|
||||
[{:name :new-contact
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :contact.new-contact}
|
||||
:options {:sheet? true}
|
||||
:component add-new-contact/new-contact}
|
||||
|
||||
{:name :scan-profile-qr-code
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :contact.scan-profile-qr-code}
|
||||
:options options/dark-screen
|
||||
:component scan-profile-qr-page/view}
|
||||
|
||||
{:name :contact-profile
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :contact.contact-profile}
|
||||
:options {:modalPresentationStyle :overCurrentContext}
|
||||
:component contact-profile/view}
|
||||
|
||||
{:name :share-contact
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :contact.share-profile}
|
||||
:options options/transparent-screen-options
|
||||
:component share-contact/view}])
|
||||
@@ -312,56 +314,56 @@
|
||||
|
||||
(def settings-screens
|
||||
[{:name :settings
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.profile-settings}
|
||||
:options options/transparent-screen-options
|
||||
:component settings/view}
|
||||
|
||||
{:name :screen/settings.keycard
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.keycard}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component settings.keycard/view}
|
||||
|
||||
{:name :edit-profile
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.edit-profile}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component edit-profile/view}
|
||||
|
||||
{:name :edit-accent-colour
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.edit-profile-accent-colour}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component edit-accent-colour/view}
|
||||
|
||||
{:name :edit-name
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.edit-profile-name}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component edit-name/view}
|
||||
|
||||
{:name :edit-bio
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.edit-profile-bio}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component edit-bio/view}
|
||||
|
||||
{:name :screen/settings-password
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.password}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings-password/view}
|
||||
|
||||
{:name :screen/change-password
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.change-password}
|
||||
:options (assoc options/transparent-modal-screen-options :theme :dark)
|
||||
:component change-password/view}
|
||||
|
||||
{:name :screen/change-password-loading
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.change-password-loading}
|
||||
:options (assoc
|
||||
options/transparent-modal-screen-options
|
||||
@@ -372,25 +374,25 @@
|
||||
:component change-password-loading/view}
|
||||
|
||||
{:name :screen/settings-messages
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.messages}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.messages/view}
|
||||
|
||||
{:name :screen/settings-blocked-users
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.blocked-users}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.blocked-users/view}
|
||||
|
||||
{:name :screen/settings-privacy-and-security
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.private-and-security}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.privacy-and-security/view}
|
||||
|
||||
{:name :screen/settings.share-usage-data
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.share-usage/view}
|
||||
|
||||
@@ -406,89 +408,104 @@
|
||||
:component syncing-devices-list/view}
|
||||
|
||||
{:name :screen/settings.language-and-currency
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.language-and-currency/view}
|
||||
|
||||
{:name :screen/settings.currency-selection
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.currency-selection/view}])
|
||||
:component settings.currency-selection/view}
|
||||
|
||||
{:name :screen/settings.about
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component settings.about/view}
|
||||
|
||||
{:name :screen/settings.privacy-policy
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component privacy-policy/view}
|
||||
|
||||
{:name :screen/settings.terms-of-use
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component terms-of-use/view}])
|
||||
|
||||
(def wallet-settings-screens
|
||||
[{:name :screen/settings.wallet
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component wallet-options/view}
|
||||
|
||||
{:name :screen/settings.rename-keypair
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-rename-keypair}
|
||||
:options options/transparent-screen-options
|
||||
:component keypair-rename/view}
|
||||
|
||||
{:name :screen/settings.encrypted-keypair-qr
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-encrypted-keypair-qr}
|
||||
:options options/transparent-screen-options
|
||||
:component encrypted-keypair-qr/view}
|
||||
|
||||
{:name :screen/settings.saved-addresses
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-saved-addresses}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component saved-addresses-settings/view}
|
||||
|
||||
{:name :screen/settings.keypairs-and-accounts
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-keypairs-and-accounts}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component keypairs-and-accounts/view}
|
||||
|
||||
{:name :screen/settings.scan-keypair-qr
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-scan-keypair-qr}
|
||||
:options options/transparent-screen-options
|
||||
:component scan-keypair-qr/view}
|
||||
|
||||
{:name :screen/settings.missing-keypair.import-seed-phrase
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-missing-keypair-import-seed-phrase}
|
||||
:options options/transparent-screen-options
|
||||
:component missing-keypairs.import-seed-phrase/view}
|
||||
|
||||
{:name :screen/settings.missing-keypair-import-private-key
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-missing-keypair-import-private-key}
|
||||
:options options/transparent-screen-options
|
||||
:component missing-keypairs.import-private-key/view}
|
||||
|
||||
{:name :screen/settings.network-settings
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-network-settings}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component network-settings/view}
|
||||
|
||||
{:name :screen/settings.save-address
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-saved-addresses}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component wallet-save-address/view}
|
||||
|
||||
{:name :screen/settings.edit-saved-address
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-edit-saved-addresses}
|
||||
:options (assoc options/dark-screen :sheet? true)
|
||||
:component wallet-save-address/view}
|
||||
|
||||
{:name :screen/settings.add-address-to-save
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-add-saved-address}
|
||||
:options options/transparent-modal-screen-options
|
||||
:component wallet-add-address-to-save/view}
|
||||
|
||||
{:name :screen/settings.share-saved-address
|
||||
:metrics {:track? :true
|
||||
:metrics {:track? true
|
||||
:alias-id :settings.wallet-share-saved-address}
|
||||
:options options/transparent-screen-options
|
||||
:component share-saved-address/view}])
|
||||
@@ -728,16 +745,6 @@
|
||||
:modalPresentationStyle :overCurrentContext}
|
||||
:component create-or-sync-profile/sync-or-recover-profile})
|
||||
|
||||
(def onboarding-create-profile
|
||||
{:name :screen/onboarding.create-profile
|
||||
:metrics {:track? true
|
||||
:alias-id :onboarding.create-profile-info}
|
||||
:options {:theme :dark
|
||||
:layout options/onboarding-transparent-layout
|
||||
:animations transitions/push-animations-for-transparent-background
|
||||
:popGesture false}
|
||||
:component create-profile/create-profile})
|
||||
|
||||
(def onboarding-create-profile-password
|
||||
{:name :screen/onboarding.create-profile-password
|
||||
:metrics {:track? true
|
||||
@@ -768,9 +775,7 @@
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:layout options/onboarding-transparent-layout
|
||||
:animations (merge
|
||||
transitions/new-to-status-modal-animations
|
||||
transitions/push-animations-for-transparent-background)
|
||||
:animations transitions/modal-animations-vertical
|
||||
:popGesture false
|
||||
:modalPresentationStyle :overCurrentContext}
|
||||
:component onboarding.share-usage/view})
|
||||
@@ -872,7 +877,6 @@
|
||||
[onboarding-intro
|
||||
onboarding-new-to-status
|
||||
onboarding-sync-or-recover-profile
|
||||
onboarding-create-profile
|
||||
onboarding-create-profile-password
|
||||
onboarding-enable-biometrics
|
||||
onboarding-preparing-status
|
||||
@@ -888,48 +892,48 @@
|
||||
|
||||
(def keycard-screens
|
||||
[{:name :screen/keycard.check
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.check/view}
|
||||
|
||||
{:name :screen/keycard.empty
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.empty/view}
|
||||
|
||||
{:name :screen/keycard.empty-create
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.empty/create}
|
||||
|
||||
{:name :screen/keycard.error
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.error/view}
|
||||
|
||||
{:name :screen/keycard.not-keycard
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.not-keycard/view}
|
||||
|
||||
{:name :screen/keycard.authorise
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.authorise/view}
|
||||
|
||||
{:name :screen/keycard.migrate
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.migrate/view}
|
||||
|
||||
{:name :screen/keycard.re-encrypting
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
@@ -938,7 +942,7 @@
|
||||
:component keycard.re-encrypting/view}
|
||||
|
||||
{:name :screen/keycard.migrate.success
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
@@ -947,7 +951,7 @@
|
||||
:component keycard.migrate.success/view}
|
||||
|
||||
{:name :screen/keycard.migrate.fail
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}
|
||||
:popGesture false
|
||||
@@ -956,30 +960,30 @@
|
||||
:component keycard.migrate.fail/view}
|
||||
|
||||
{:name :screen/keycard.pin.create
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.pin.create/view}
|
||||
|
||||
{:name :screen/keycard.pin.enter
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.pin.enter/view}
|
||||
|
||||
{:name :screen/keycard.profile-keys
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.migrate.profile-keys/view}
|
||||
|
||||
{:name :screen/keycard.create-profile
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.create/view}
|
||||
|
||||
{:name :screen/keycard.create.ready-to-add
|
||||
:metrics {:track? :true}
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component keycard.create/ready-to-add}])
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
:to (:width (rn/get-window))
|
||||
:duration constants/onboarding-modal-animation-duration}}})
|
||||
|
||||
(def modal-animations-vertical
|
||||
{:showModal {:translationY {:from (:height (rn/get-window))
|
||||
:to 0
|
||||
:duration constants/onboarding-modal-animation-duration}}
|
||||
:dismissModal {:translationY {:from 0
|
||||
:to (:height (rn/get-window))
|
||||
:duration constants/onboarding-modal-animation-duration}}})
|
||||
|
||||
;;;; Stack Transitions
|
||||
(def stack-slide-transition
|
||||
{:push {:content {:translationX {:from (:width (rn/get-window))
|
||||
|
||||
@@ -286,6 +286,12 @@
|
||||
:<- [:wallet/create-account]
|
||||
:-> :selected-keypair-uid)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/selected-keypair-keycard?
|
||||
:<- [:wallet/selected-keypair]
|
||||
(fn [{:keys [keycards]}]
|
||||
(boolean (seq keycards))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/selected-keypair
|
||||
:<- [:wallet/keypairs]
|
||||
@@ -343,12 +349,13 @@
|
||||
:<- [:wallet/keypairs-list]
|
||||
(fn [keypairs [_ format-options]]
|
||||
(reduce
|
||||
(fn [acc {:keys [accounts name type key-uid lowest-operability]}]
|
||||
(fn [acc {:keys [accounts name type key-uid lowest-operability keycards]}]
|
||||
(if (= lowest-operability :no)
|
||||
(update acc
|
||||
:missing
|
||||
conj
|
||||
{:type type
|
||||
:keycard? (boolean (seq keycards))
|
||||
:name name
|
||||
:key-uid key-uid
|
||||
:accounts (format-settings-missing-keypair-accounts accounts)})
|
||||
@@ -356,6 +363,7 @@
|
||||
:operable
|
||||
conj
|
||||
{:type type
|
||||
:keycard? (boolean (seq keycards))
|
||||
:name name
|
||||
:key-uid key-uid
|
||||
:accounts (format-settings-keypair-accounts accounts format-options)})))
|
||||
@@ -711,13 +719,11 @@
|
||||
(rf/reg-sub
|
||||
:wallet/zero-balance-in-all-non-watched-accounts?
|
||||
:<- [:wallet/aggregated-tokens]
|
||||
:<- [:profile/currency]
|
||||
:<- [:wallet/prices-per-token]
|
||||
(fn [[aggregated-tokens currency prices-per-token]]
|
||||
(let [balance (utils/calculate-balance-from-tokens {:currency currency
|
||||
:tokens aggregated-tokens
|
||||
:prices-per-token prices-per-token})]
|
||||
(and (not-empty aggregated-tokens) (money/equal-to balance 0)))))
|
||||
(fn [aggregated-tokens]
|
||||
(let [zero-balance? (->> aggregated-tokens
|
||||
(mapcat (comp vals :balances-per-chain))
|
||||
(every? #(money/equal-to (:raw-balance %) 0)))]
|
||||
(and (not-empty aggregated-tokens) zero-balance?))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/network-preference-details
|
||||
|
||||
@@ -1008,3 +1008,150 @@
|
||||
(update accounts "0x2" assoc :operable :partially)))
|
||||
(is (true? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/zero-balance-in-all-non-watched-accounts?
|
||||
[sub-name]
|
||||
(testing "returns true if the balance is zero in all non-watched accounts"
|
||||
(swap! rf-db/app-db
|
||||
#(assoc-in %
|
||||
[:wallet :accounts]
|
||||
{"0x1" {:address "0x1"
|
||||
:watch-only? false
|
||||
:tokens
|
||||
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}
|
||||
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}]}
|
||||
"0x2" {:address "0x2"
|
||||
:watch-only? false
|
||||
:tokens
|
||||
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}
|
||||
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}]}
|
||||
|
||||
"0x3"
|
||||
{:address "0x3"
|
||||
:watch-only? true
|
||||
:tokens [{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance
|
||||
(money/bignumber
|
||||
"2")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance
|
||||
(money/bignumber
|
||||
"1")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance
|
||||
(money/bignumber
|
||||
"0")
|
||||
:has-error false}}}
|
||||
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance
|
||||
(money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance
|
||||
(money/bignumber
|
||||
"2")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance
|
||||
(money/bignumber
|
||||
"0")
|
||||
:has-error
|
||||
false}}}]}}))
|
||||
(is (true? (rf/sub [sub-name]))))
|
||||
(testing "returns false if the balance is not zero in all non-watched accounts"
|
||||
(swap! rf-db/app-db
|
||||
#(assoc-in %
|
||||
[:wallet :accounts]
|
||||
{"0x1" {:address "0x1"
|
||||
:watch-only? false
|
||||
:tokens
|
||||
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"2")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"1")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}
|
||||
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"2")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}]}
|
||||
"0x2" {:address "0x2"
|
||||
:watch-only? true
|
||||
:tokens
|
||||
[{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"2")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"1")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}
|
||||
{:balances-per-chain {constants/ethereum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}
|
||||
constants/optimism-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"2")
|
||||
:has-error false}
|
||||
constants/arbitrum-mainnet-chain-id {:raw-balance (money/bignumber
|
||||
"0")
|
||||
:has-error false}}}]}}))
|
||||
(is (false? (rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :wallet/selected-keypair-keycard?
|
||||
[sub-name]
|
||||
(testing "returns true if the selected keypair has keycards"
|
||||
(swap! rf-db/app-db
|
||||
#(assoc-in %
|
||||
[:wallet :keypairs]
|
||||
{:keypair-1 {:id :keypair-1
|
||||
:keycards [:keycard-1 :keycard-2]}}))
|
||||
(swap! rf-db/app-db
|
||||
#(assoc-in % [:wallet :ui :create-account :selected-keypair-uid] :keypair-1))
|
||||
(is (true? (rf/sub [sub-name]))))
|
||||
|
||||
(testing "returns false if the selected keypair has no keycards"
|
||||
(swap! rf-db/app-db
|
||||
#(assoc-in %
|
||||
[:wallet :keypairs]
|
||||
{:keypair-2 {:id :keypair-2
|
||||
:keycards []}}))
|
||||
(swap! rf-db/app-db
|
||||
#(assoc-in % [:wallet :ui :create-account :selected-keypair-uid] :keypair-2))
|
||||
(is (false? (rf/sub [sub-name])))))
|
||||
|
||||
@@ -126,9 +126,12 @@
|
||||
|
||||
(def status
|
||||
(clj->js
|
||||
{:intendedPanic identity
|
||||
:getNodeConfig (fn [] (types/clj->json {:WakuV2Config ""}))
|
||||
:addCentralizedMetric (fn [_ callback]
|
||||
(callback))
|
||||
:fleets (fn [] (.fleets native-status))
|
||||
:startLocalNotifications identity}))
|
||||
{:getNodeConfig
|
||||
(fn [] (types/clj->json {:WakuV2Config ""}))
|
||||
:addCentralizedMetric
|
||||
(fn [_ callback]
|
||||
(callback))
|
||||
:fleets
|
||||
(fn [] (.fleets native-status))
|
||||
:startLocalNotifications
|
||||
identity}))
|
||||
|
||||
@@ -141,3 +141,14 @@
|
||||
(defn zero-address?
|
||||
[address]
|
||||
(= address zero-address))
|
||||
|
||||
(defn public-key->address
|
||||
[public-key]
|
||||
(let [length (count public-key)
|
||||
normalized-key (case length
|
||||
132 (str "0x" (subs public-key 4))
|
||||
130 public-key
|
||||
128 (str "0x" public-key)
|
||||
nil)]
|
||||
(when normalized-key
|
||||
(subs (native-module/sha3 normalized-key) 26))))
|
||||
|
||||
@@ -17,11 +17,10 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
def prepare_devices(self):
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
self.username_1, self.username_2 = 'sender', 'receiver'
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
|
||||
'username': self.username_1}),
|
||||
(self.device_2.create_user, {'username': self.username_2}))))
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
|
||||
(self.device_2.create_user,))))
|
||||
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
|
||||
self.public_key_1 = self.home_1.get_public_key()
|
||||
self.profile_link_2 = self.home_2.get_link_to_profile()
|
||||
@@ -98,8 +97,8 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
def test_activity_center_contact_request_accept_swipe_mark_all_as_read(self):
|
||||
self.device_2.just_fyi('Creating a new user on Device2')
|
||||
self.home_2.reopen_app(sign_in=False)
|
||||
new_username = "new user"
|
||||
self.device_2.create_user(username=new_username, first_user=False)
|
||||
self.device_2.create_user(first_user=False)
|
||||
new_username = self.home_2.get_username()
|
||||
|
||||
self.device_2.just_fyi('Device2 sends a contact request to Device1 via Paste button and check user details')
|
||||
self.home_2.chats_tab.click()
|
||||
@@ -149,30 +148,21 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
|
||||
@marks.testrail_id(702777)
|
||||
def test_add_contact_field_validation(self):
|
||||
# Profile link encoded data validation
|
||||
encoded_data = re.findall("u/(.*)#", self.profile_link_2)[0]
|
||||
decoded_string = base64.b64decode(encoded_data).decode("utf-8", "ignore")
|
||||
decoded_username = re.sub('[^A-Za-z0-9]+', '', decoded_string)
|
||||
if decoded_username != self.username_2:
|
||||
self.errors.append(
|
||||
"Can't find username '%s' in data which profile link '%s' contains. String '%s' is found instead" % (
|
||||
self.username_2, self.profile_link_2, decoded_username))
|
||||
public_key_2 = self.profile_link_2.split("#")[-1]
|
||||
|
||||
new_username_1 = "test user 123"
|
||||
|
||||
def _device_1_creates_user():
|
||||
self.home_1.just_fyi("Device 1 creates a new user")
|
||||
self.home_1.reopen_app(sign_in=False)
|
||||
self.device_1.create_user(username=new_username_1, first_user=False)
|
||||
self.device_1.create_user(first_user=False)
|
||||
return self.home_1.get_username()
|
||||
|
||||
def _device_2_sign_in():
|
||||
self.home_2.just_fyi("Device 2 sign in, user name is " + self.username_2)
|
||||
self.home_2.reopen_app(sign_in=False)
|
||||
self.device_2.sign_in(user_name=self.username_2)
|
||||
|
||||
self.loop.run_until_complete(run_in_parallel(((_device_1_creates_user, {}),
|
||||
(_device_2_sign_in, {}))))
|
||||
new_username_1, _ = self.loop.run_until_complete(run_in_parallel(((_device_1_creates_user, {}),
|
||||
(_device_2_sign_in, {}))))
|
||||
|
||||
self.device_1.just_fyi('Device1 sends a contact request to Device2 using his profile link')
|
||||
self.home_1.chats_tab.click()
|
||||
@@ -242,11 +232,11 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
|
||||
def prepare_devices(self):
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
self.username_1, self.username_2 = 'user1', 'user2'
|
||||
self.loop.run_until_complete(
|
||||
run_in_parallel(((self.device_1.create_user, {'username': self.username_1}),
|
||||
(self.device_2.create_user, {'username': self.username_2}))))
|
||||
run_in_parallel(((self.device_1.create_user,),
|
||||
(self.device_2.create_user,))))
|
||||
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
|
||||
self.public_key_2 = self.home_2.get_public_key()
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
@@ -382,11 +372,11 @@ class TestActivityMultipleDevicePRTwo(MultipleSharedDeviceTestCase):
|
||||
def prepare_devices(self):
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
self.username_1, self.username_2 = 'user1', 'user2'
|
||||
self.loop.run_until_complete(
|
||||
run_in_parallel(((self.device_1.create_user, {'username': self.username_1}),
|
||||
(self.device_2.create_user, {'username': self.username_2}))))
|
||||
run_in_parallel(((self.device_1.create_user,),
|
||||
(self.device_2.create_user,))))
|
||||
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.profile_1, self.profile_2 = self.home_1.get_profile_view(), self.home_2.get_profile_view()
|
||||
self.public_key_2 = self.home_2.get_public_key()
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
|
||||
@@ -20,13 +20,11 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
|
||||
self.username_1, self.username_2 = 'sender', 'receiver'
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
|
||||
'username': self.username_1}),
|
||||
(self.device_2.create_user, {'enable_notifications': True,
|
||||
'username': self.username_2}))))
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
|
||||
(self.device_2.create_user, {'enable_notifications': True}))))
|
||||
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.homes = (self.home_1, self.home_2)
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes)
|
||||
self.public_key_2 = self.home_2.get_public_key()
|
||||
|
||||
@@ -543,13 +541,11 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
|
||||
self.username_1, self.username_2 = 'sender', 'receiver'
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
|
||||
'username': self.username_1}),
|
||||
(self.device_2.create_user, {'enable_notifications': True,
|
||||
'username': self.username_2}))))
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
|
||||
(self.device_2.create_user, {'enable_notifications': True}))))
|
||||
self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.homes = (self.home_1, self.home_2)
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.profile_1, self.profile_2 = (home.get_profile_view() for home in self.homes)
|
||||
self.public_key_2 = self.home_2.get_public_key()
|
||||
|
||||
|
||||
@@ -21,17 +21,25 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
self.message_to_admin = 'Hey, admin!'
|
||||
self.public_keys, self.usernames, self.chats = {}, {}, {}
|
||||
self.sign_in_views = [SignInView(self.drivers[key]) for key in self.drivers]
|
||||
self.usernames = ('user admin', 'member_1', 'member_2')
|
||||
self.loop.run_until_complete(
|
||||
run_in_parallel(
|
||||
(
|
||||
(self.sign_in_views[0].create_user, {'enable_notifications': True, 'username': self.usernames[0]}),
|
||||
(self.sign_in_views[1].create_user, {'enable_notifications': True, 'username': self.usernames[1]}),
|
||||
(self.sign_in_views[2].create_user, {'enable_notifications': True, 'username': self.usernames[2]})
|
||||
(self.sign_in_views[0].create_user, {'enable_notifications': True}),
|
||||
(self.sign_in_views[1].create_user, {'enable_notifications': True}),
|
||||
(self.sign_in_views[2].create_user, {'enable_notifications': True})
|
||||
)
|
||||
)
|
||||
)
|
||||
self.homes = [sign_in.get_home_view() for sign_in in self.sign_in_views]
|
||||
self.usernames = self.loop.run_until_complete(
|
||||
run_in_parallel(
|
||||
(
|
||||
(self.homes[0].get_username,),
|
||||
(self.homes[1].get_username,),
|
||||
(self.homes[2].get_username,)
|
||||
)
|
||||
)
|
||||
)
|
||||
self.public_keys = self.loop.run_until_complete(
|
||||
run_in_parallel(
|
||||
(
|
||||
@@ -445,7 +453,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
current_time = datetime.datetime.strptime(device_time, "%Y-%m-%dT%H:%M:%S%z")
|
||||
expected_times = [current_time + datetime.timedelta(minutes=i) for i in range(479, 482)]
|
||||
expected_texts = [
|
||||
"Muted until %s %s" % (exp_time.strftime('%H:%M'), "today" if current_time.hour < 23 else "tomorrow") for
|
||||
"Muted until %s %s" % (exp_time.strftime('%H:%M'), "today" if current_time.hour < 16 else "tomorrow") for
|
||||
exp_time in expected_times]
|
||||
chat = self.homes[1].get_chat(self.chat_name)
|
||||
chat.long_press_element()
|
||||
@@ -475,7 +483,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
if after_mute_counter > initial_counter:
|
||||
self.errors.append("New messages counter near chats tab button is %s after mute, but should be %s" % (
|
||||
after_mute_counter, initial_counter))
|
||||
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[0], muted_message)):
|
||||
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[0], muted_message[:25])):
|
||||
self.errors.append("Message text '%s' is not shown in chat preview after mute" % muted_message)
|
||||
chat.click()
|
||||
if not self.chats[1].chat_element_by_text(muted_message).is_element_displayed(30):
|
||||
|
||||
@@ -21,9 +21,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
def prepare_devices(self):
|
||||
self.drivers, self.loop = create_shared_drivers(1)
|
||||
self.sign_in = SignInView(self.drivers[0])
|
||||
self.username = 'first user'
|
||||
|
||||
self.home = self.sign_in.create_user(username=self.username)
|
||||
self.home = self.sign_in.create_user()
|
||||
self.username = self.home.get_username()
|
||||
self.home.communities_tab.click_until_presence_of_element(self.home.plus_community_button)
|
||||
self.community_name = "closed community"
|
||||
self.channel_name = "cats"
|
||||
@@ -158,8 +158,8 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
def test_restore_multiaccount_with_waku_backup_remove_profile_switch(self):
|
||||
self.home.reopen_app(sign_in=False)
|
||||
self.home.just_fyi("Restore user with predefined communities and contacts")
|
||||
recover_user_name = 'Recover user'
|
||||
self.sign_in.recover_access(passphrase=waku_user.seed, second_user=True, username=recover_user_name)
|
||||
self.sign_in.recover_access(passphrase=waku_user.seed, second_user=True)
|
||||
recover_user_name = self.home.get_username()
|
||||
|
||||
self.home.just_fyi("Check contacts/blocked users")
|
||||
self.home.chats_tab.click()
|
||||
@@ -306,11 +306,10 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
def prepare_devices(self):
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
self.username_1, self.username_2 = "user_1", "user_2"
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
|
||||
'username': self.username_1}),
|
||||
(self.device_2.create_user, {'username': self.username_2}))))
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
|
||||
(self.device_2.create_user,))))
|
||||
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.public_key_2 = self.home_2.get_public_key()
|
||||
self.profile_1 = self.home_1.get_profile_view()
|
||||
[home.navigate_back_to_home_view() for home in self.homes]
|
||||
@@ -836,12 +835,10 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
def prepare_devices(self):
|
||||
self.drivers, self.loop = create_shared_drivers(2)
|
||||
self.device_1, self.device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
self.username_1, self.username_2 = "user_1", "user_2"
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True,
|
||||
'username': self.username_1}),
|
||||
(self.device_2.create_user, {'enable_notifications': True,
|
||||
'username': self.username_2}))))
|
||||
self.loop.run_until_complete(run_in_parallel(((self.device_1.create_user, {'enable_notifications': True}),
|
||||
(self.device_2.create_user, {'enable_notifications': True}))))
|
||||
self.homes = self.home_1, self.home_2 = self.device_1.get_home_view(), self.device_2.get_home_view()
|
||||
self.username_1, self.username_2 = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.public_key_2 = self.home_2.get_public_key()
|
||||
self.profile_1 = self.home_1.get_profile_view()
|
||||
[home.navigate_back_to_home_view() for home in self.homes]
|
||||
@@ -1024,6 +1021,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.errors.append('Community is still shown in the list after leave')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.xfail(reason="Can't navigate to a community channel before joining the community, "
|
||||
"https://github.com/status-im/status-mobile/issues/21776")
|
||||
@marks.testrail_id(702948)
|
||||
def test_community_hashtag_links_to_community_channels(self):
|
||||
for home in self.homes:
|
||||
@@ -1124,6 +1123,8 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.xfail(reason="Can't navigate to a community channel before joining the community, "
|
||||
"https://github.com/status-im/status-mobile/issues/21776")
|
||||
@marks.testrail_id(703629)
|
||||
def test_community_join_when_node_owner_offline(self):
|
||||
for home in self.homes:
|
||||
|
||||
@@ -13,9 +13,9 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.drivers, self.loop = create_shared_drivers(1)
|
||||
self.driver = self.drivers[0]
|
||||
self.sign_in = SignInView(self.driver)
|
||||
self.username = 'test user'
|
||||
|
||||
self.home = self.sign_in.create_user(username=self.username)
|
||||
self.home = self.sign_in.create_user()
|
||||
self.username = self.home.get_username()
|
||||
self.home.communities_tab.click_until_presence_of_element(self.home.plus_community_button)
|
||||
self.open_community_name = "open community"
|
||||
self.channel_name = "general"
|
||||
@@ -89,7 +89,7 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.home.get_chat(snt_community_name, community=True).click()
|
||||
snt_community_url = self.community_view.copy_community_link()
|
||||
self.home.reopen_app(sign_in=False)
|
||||
self.sign_in.create_user(username="second user", first_user=False)
|
||||
self.sign_in.create_user(first_user=False)
|
||||
self.home.browser_tab.click()
|
||||
|
||||
old, new = "https://status.app/", "status-app://"
|
||||
|
||||
@@ -20,10 +20,10 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.sign_in_3.get_home_view()
|
||||
self.sign_in_1.just_fyi("Device 1: create a new user")
|
||||
self.sign_in_3.just_fyi("Device 3: create a new user")
|
||||
self.user_name_1, self.user_name_3 = 'first user', 'third user'
|
||||
self.loop.run_until_complete(
|
||||
run_in_parallel(((self.sign_in_1.create_user, {'username': self.user_name_1}),
|
||||
(self.sign_in_3.create_user, {'username': self.user_name_3}))))
|
||||
run_in_parallel(((self.sign_in_1.create_user,),
|
||||
(self.sign_in_3.create_user,))))
|
||||
self.user_name_1, self.user_name_3 = self.home_1.get_username(), self.home_3.get_username()
|
||||
self.profile_1 = self.home_1.profile_button.click()
|
||||
self.profile_2 = self.home_2.get_profile_view()
|
||||
self.sign_in_3.just_fyi("Device 3: get public key")
|
||||
@@ -269,7 +269,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.sign_in_2.passphrase_edit_box.clear()
|
||||
self.sign_in_2.passphrase_edit_box.send_keys(transaction_senders['A']['passphrase'])
|
||||
self.sign_in_2.continue_button.click()
|
||||
if not self.sign_in_2.profile_title_input.is_element_displayed():
|
||||
if not self.sign_in_2.password_input.is_element_displayed():
|
||||
self.errors.append("Can't recover an access with a valid passphrase")
|
||||
self.sign_in_2.click_system_back_button()
|
||||
|
||||
|
||||
@@ -24,13 +24,11 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.sender, self.receiver = transaction_senders['ETH_1'], transaction_senders['ETH_2']
|
||||
self.sender['wallet_address'] = '0x' + self.sender['address']
|
||||
self.receiver['wallet_address'] = '0x' + self.receiver['address']
|
||||
self.sender_username, self.receiver_username = 'sender', 'receiver'
|
||||
self.loop.run_until_complete(
|
||||
run_in_parallel(((self.sign_in_1.recover_access, {'passphrase': self.sender['passphrase'],
|
||||
'username': self.sender_username}),
|
||||
(self.sign_in_2.recover_access, {'passphrase': self.receiver['passphrase'],
|
||||
'username': self.receiver_username}))))
|
||||
run_in_parallel(((self.sign_in_1.recover_access, {'passphrase': self.sender['passphrase']}),
|
||||
(self.sign_in_2.recover_access, {'passphrase': self.receiver['passphrase']}))))
|
||||
self.home_1, self.home_2 = self.sign_in_1.get_home_view(), self.sign_in_2.get_home_view()
|
||||
self.sender_username, self.receiver_username = self.home_1.get_username(), self.home_2.get_username()
|
||||
self.wallet_1, self.wallet_2 = self.sign_in_1.get_wallet_view(), self.sign_in_2.get_wallet_view()
|
||||
self.wallet_1.wallet_tab.click()
|
||||
self.wallet_2.wallet_tab.click()
|
||||
@@ -61,19 +59,19 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
def wait_for_wallet_balance_to_update(wallet_view, user_name, initial_eth_amount):
|
||||
wallet_view.just_fyi("Getting ETH amount in the wallet of the %s after transaction" % user_name)
|
||||
if user_name == 'sender':
|
||||
if user_name == self.sender_username:
|
||||
exp_amount = round(initial_eth_amount - amount_to_send, 4)
|
||||
else:
|
||||
exp_amount = round(initial_eth_amount + amount_to_send, 4)
|
||||
|
||||
# for _ in range(12): # ToDo: 120 sec wait time, enable when autoupdate feature is ready
|
||||
new_eth_amount = round(wallet_view.get_asset(asset_name='Ether').get_amount(), 4)
|
||||
if user_name == 'sender' and new_eth_amount <= exp_amount:
|
||||
if user_name == self.sender_username and new_eth_amount <= exp_amount:
|
||||
return
|
||||
if user_name == 'receiver' and new_eth_amount >= exp_amount:
|
||||
if user_name == self.receiver_username and new_eth_amount >= exp_amount:
|
||||
return
|
||||
self.errors.append(
|
||||
"Eth amount in the %ss wallet is %s but should be %s" % (user_name, new_eth_amount, exp_amount))
|
||||
"Eth amount in the %s's wallet is %s but should be %s" % (user_name, new_eth_amount, exp_amount))
|
||||
|
||||
# ToDo: disable relogin when autoupdate feature is ready
|
||||
self.home_1.just_fyi("Relogin for getting an updated balance")
|
||||
@@ -206,10 +204,10 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.arb_balance = {'Ether': 0.0001, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.5, 'Dai Stablecoin': 0.0}
|
||||
self.sender['wallet_address'] = '0x' + self.sender['address']
|
||||
self.receiver['wallet_address'] = '0x' + self.receiver['address']
|
||||
self.sender_username, self.receiver_username = 'sender', 'receiver'
|
||||
self.sign_in_view.recover_access(passphrase=self.sender['passphrase'], username=self.sender_username)
|
||||
self.sign_in_view.recover_access(passphrase=self.sender['passphrase'])
|
||||
|
||||
self.home_view = self.sign_in_view.get_home_view()
|
||||
self.sender_username = self.home_view.get_username()
|
||||
self.wallet_view = self.home_view.wallet_tab.click()
|
||||
|
||||
@marks.testrail_id(740490)
|
||||
|
||||
@@ -624,3 +624,12 @@ class HomeView(BaseView):
|
||||
element = Text(self.driver, accessibility_id='new-device-installation-id')
|
||||
element.wait_for_visibility_of_element()
|
||||
return element.text
|
||||
|
||||
def get_username(self):
|
||||
self.toast_content_element.wait_for_invisibility_of_element()
|
||||
profile_view = self.get_profile_view()
|
||||
profile_view = self.profile_button.click_until_presence_of_element(profile_view.default_username_text)
|
||||
profile_view.default_username_text.wait_for_element(3)
|
||||
username = profile_view.default_username_text.text
|
||||
profile_view.click_system_back_button()
|
||||
return username
|
||||
|
||||
@@ -179,7 +179,7 @@ class ProfileView(BaseView):
|
||||
|
||||
# Header
|
||||
self.public_key_text = Text(self.driver, accessibility_id="chat-key")
|
||||
self.default_username_text = Text(self.driver, accessibility_id="default-username")
|
||||
self.default_username_text = Text(self.driver, accessibility_id="username")
|
||||
self.contact_name_text = Text(self.driver, accessibility_id="contact-name")
|
||||
self.share_my_profile_button = Button(self.driver, accessibility_id="share-header-button")
|
||||
self.profile_picture = ProfilePictureElement(self.driver)
|
||||
|
||||
@@ -211,7 +211,7 @@ class SignInView(BaseView):
|
||||
self.profile_continue_button = Button(self.driver, accessibility_id="submit-create-profile-button")
|
||||
self.profile_password_edit_box = EditBox(self.driver, translation_id="password-creation-placeholder-1")
|
||||
self.profile_repeat_password_edit_box = EditBox(self.driver, translation_id="password-creation-placeholder-2")
|
||||
self.profile_confirm_password_button = Button(self.driver, translation_id="password-creation-confirm")
|
||||
self.profile_confirm_password_button = Button(self.driver, accessibility_id="Confirm password")
|
||||
self.enable_biometric_maybe_later_button = Button(self.driver, translation_id="maybe-later")
|
||||
self.identifiers_button = Button(self.driver, accessibility_id="skip-identifiers")
|
||||
self.start_button = Button(self.driver, accessibility_id="welcome-button")
|
||||
@@ -228,8 +228,6 @@ class SignInView(BaseView):
|
||||
input_elements[0].send_keys(password)
|
||||
input_elements[1].click()
|
||||
input_elements[1].send_keys(password)
|
||||
self.checkbox_button.scroll_to_element()
|
||||
self.checkbox_button.click()
|
||||
self.profile_confirm_password_button.click()
|
||||
|
||||
def set_profile(self, username: str, set_image=False):
|
||||
@@ -238,7 +236,7 @@ class SignInView(BaseView):
|
||||
if set_image:
|
||||
pass
|
||||
|
||||
def create_user(self, password=common_password, username="test user", first_user=True, enable_notifications=False):
|
||||
def create_user(self, password=common_password, first_user=True, enable_notifications=False):
|
||||
self.driver.info("## Creating new multiaccount with password:'%s'" % password, device=False)
|
||||
if first_user:
|
||||
self.create_profile_button.click_until_presence_of_element(self.start_fresh_lets_go_button)
|
||||
@@ -249,7 +247,6 @@ class SignInView(BaseView):
|
||||
self.plus_profiles_button.click()
|
||||
self.create_new_profile_button.click()
|
||||
self.start_fresh_lets_go_button.click_until_presence_of_element(self.profile_title_input)
|
||||
self.set_profile(username)
|
||||
self.set_password(password)
|
||||
self.chats_tab.wait_for_visibility_of_element(30)
|
||||
self.driver.info("## New multiaccount is created successfully!", device=False)
|
||||
@@ -261,7 +258,7 @@ class SignInView(BaseView):
|
||||
return home_view
|
||||
|
||||
def recover_access(self, passphrase: str, password: str = common_password, enable_notifications=False,
|
||||
second_user=False, username='Restore user', set_image=False, after_sync_code=False):
|
||||
second_user=False, after_sync_code=False):
|
||||
self.driver.info("## Recover access (password:%s)" % password, device=False)
|
||||
|
||||
if not after_sync_code:
|
||||
@@ -274,8 +271,6 @@ class SignInView(BaseView):
|
||||
self.use_recovery_phrase_button.click()
|
||||
self.passphrase_edit_box.send_keys(passphrase)
|
||||
self.continue_button.click_until_presence_of_element(self.profile_title_input)
|
||||
if not after_sync_code:
|
||||
self.set_profile(username, set_image)
|
||||
self.set_password(password)
|
||||
self.chats_tab.wait_for_visibility_of_element(30)
|
||||
self.driver.info("## Multiaccount is recovered successfully!", device=False)
|
||||
@@ -366,8 +361,10 @@ class SignInView(BaseView):
|
||||
def get_user_profile_by_name(self, username: str):
|
||||
self.driver.info("Getting username card by '%s'" % username)
|
||||
expected_element = UserProfileElement(self.driver, username=username)
|
||||
return expected_element if expected_element.is_element_displayed(10) else self.driver.fail(
|
||||
"User %s is not found!" % username)
|
||||
if expected_element.is_element_displayed(10):
|
||||
return expected_element
|
||||
else:
|
||||
raise NoSuchElementException(msg="User %s is not found!" % username)
|
||||
|
||||
def get_user_profile_by_index(self, index: int):
|
||||
self.driver.info("Getting username card by index %s" % index)
|
||||
|
||||
@@ -801,6 +801,7 @@
|
||||
"do-not-quit": "Do not quit the application or turn off your device. Doing so will lead to data corruption, loss of your Status profile and the inability to use Status.",
|
||||
|
||||
"do-not-share": "Do not share",
|
||||
"documents": "Documents",
|
||||
"done": "Done",
|
||||
"dont-ask": "Don't ask me again",
|
||||
"dont-auto-recalculate-network": "Don't auto recalculate {{network}}",
|
||||
@@ -1037,6 +1038,9 @@
|
||||
"favourite-description": "Your favourite websites will appear here",
|
||||
"favourites": "Favourites",
|
||||
"favourites-empty": "Addresses added to favourites will appear here",
|
||||
"feature-unavailable": "Feature unavailable",
|
||||
"feature-unavailable-for-keycard-description": "It’s not currently supported for Keycard users.",
|
||||
"feature-unavailable-info": "If you'd like this feature on mobile, feel free to ",
|
||||
"featured": "Featured",
|
||||
"feb": "Feb",
|
||||
"fee-cap": "Fee cap",
|
||||
@@ -1113,6 +1117,7 @@
|
||||
"getting-started-generate-keys-on-keycard-description": "A Keycard is a physical card (similar to a credit card) that securely stores your Status keys. Using a Keycard adds an extra layer of security to your digital assets and identity. This option creates a new Ethereum address.",
|
||||
"getting-started-with-status": "Getting started with Status",
|
||||
"gif": "GIF",
|
||||
"github-repos": "GitHub repos",
|
||||
"give-a-short-description": "Give a short description",
|
||||
"give-a-short-description-community": "Give it a short description",
|
||||
"give-permissions-camera": "Give permission\nto access camera",
|
||||
@@ -1930,7 +1935,7 @@
|
||||
"password-creation-max-length-hint": "Maximum 100 characters",
|
||||
"password-creation-placeholder-1": "Type password",
|
||||
"password-creation-placeholder-2": "Repeat password",
|
||||
"password-creation-subtitle": "To log in to Status and sign transactions",
|
||||
"password-creation-subtitle": "This password can't be recovered",
|
||||
"password-creation-tips-1": "Lower case",
|
||||
"password-creation-tips-2": "Upper case",
|
||||
"password-creation-tips-3": "Numbers",
|
||||
@@ -2719,6 +2724,7 @@
|
||||
"update-to-see-sticker": "Update to latest version to see a nice sticker here!",
|
||||
"updates-to-tos": "Updates to Terms of Use",
|
||||
"updates-to-tos-desc": "Before you continue, please review the Terms of Use and confirm you take full responsibility for how you use the app.",
|
||||
"upvote-it": "upvote it",
|
||||
"url": "URL",
|
||||
"usage-data-shared-from-all-profiles": "Usage data will be shared from all profiles added to device. ",
|
||||
"usd-currency": "USD",
|
||||
@@ -2868,6 +2874,7 @@
|
||||
"we-will-receive-from-all-profiles": "We will receive from all profiles:",
|
||||
"we-will-receive-from-the-current-profile": "We will receive from the current profile:",
|
||||
"web-view-error": "Unable to load page",
|
||||
"website": "Website",
|
||||
"websites": "Websites",
|
||||
"webview-camera-permission-requests": "Webview camera permission requests",
|
||||
"webview-camera-permission-requests-subtitle": "When enabled, websites and dapps can ask to use your camera",
|
||||
|
||||