diff --git a/STATUS_GO_SHA256 b/STATUS_GO_SHA256 index 4449fb0ae69c..3021b50de5e0 100644 --- a/STATUS_GO_SHA256 +++ b/STATUS_GO_SHA256 @@ -1,3 +1,3 @@ ## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh ` instead -1bhwwmypb64kf180kp634jwfppd3h6yda3qyh2icj3lz7y10pgvp +0759c9hpzgvr37d90h2sfnf1hwhvz7zhn4qcz71ayafnc9d3fmff diff --git a/STATUS_GO_VERSION b/STATUS_GO_VERSION index 1b0c69ee3b15..fc550cdb78e2 100644 --- a/STATUS_GO_VERSION +++ b/STATUS_GO_VERSION @@ -1,3 +1,3 @@ ## DO NOT EDIT THIS FILE BY HAND. USE `scripts/update-status-go.sh ` instead -v0.27.0-beta.1 +v0.29.0-beta.1 diff --git a/android/app/src/main/res/drawable-hdpi/bell.png b/android/app/src/main/res/drawable-hdpi/bell.png new file mode 100644 index 000000000000..76ee86e8680e Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/bell.png differ diff --git a/android/app/src/main/res/drawable-hdpi/fingerprint.png b/android/app/src/main/res/drawable-hdpi/fingerprint.png new file mode 100644 index 000000000000..17137fe9699e Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/fingerprint.png differ diff --git a/android/app/src/main/res/drawable-hdpi/keycard_logo.png b/android/app/src/main/res/drawable-hdpi/keycard_logo.png new file mode 100644 index 000000000000..0546b5458bc6 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/keycard_logo.png differ diff --git a/android/app/src/main/res/drawable-mdpi/bell.png b/android/app/src/main/res/drawable-mdpi/bell.png new file mode 100644 index 000000000000..986123f365c1 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/bell.png differ diff --git a/android/app/src/main/res/drawable-mdpi/fingerprint.png b/android/app/src/main/res/drawable-mdpi/fingerprint.png new file mode 100644 index 000000000000..7120503e075f Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/fingerprint.png differ diff --git a/android/app/src/main/res/drawable-mdpi/keycard_logo.png b/android/app/src/main/res/drawable-mdpi/keycard_logo.png new file mode 100644 index 000000000000..a1ff5a743464 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/keycard_logo.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/bell.png b/android/app/src/main/res/drawable-xhdpi/bell.png new file mode 100644 index 000000000000..4f4602ebaf1c Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/bell.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/fingerprint.png b/android/app/src/main/res/drawable-xhdpi/fingerprint.png new file mode 100644 index 000000000000..af1c6a23c35d Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/fingerprint.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/keycard_logo.png b/android/app/src/main/res/drawable-xhdpi/keycard_logo.png new file mode 100644 index 000000000000..8b0ed150cdc5 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/keycard_logo.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/bell.png b/android/app/src/main/res/drawable-xxhdpi/bell.png new file mode 100644 index 000000000000..bc17c822ad45 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/bell.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/fingerprint.png b/android/app/src/main/res/drawable-xxhdpi/fingerprint.png new file mode 100644 index 000000000000..16dea45157fc Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/fingerprint.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/keycard_logo.png b/android/app/src/main/res/drawable-xxhdpi/keycard_logo.png new file mode 100644 index 000000000000..0a0a5cc60248 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/keycard_logo.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/bell.png b/android/app/src/main/res/drawable-xxxhdpi/bell.png new file mode 100644 index 000000000000..d2e5fc415713 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/bell.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/fingerprint.png b/android/app/src/main/res/drawable-xxxhdpi/fingerprint.png new file mode 100644 index 000000000000..d27788ec135e Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/fingerprint.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/keycard_logo.png b/android/app/src/main/res/drawable-xxxhdpi/keycard_logo.png new file mode 100644 index 000000000000..722f3568c183 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/keycard_logo.png differ diff --git a/ios/StatusIm/Images.xcassets/bell.imageset/Contents.json b/ios/StatusIm/Images.xcassets/bell.imageset/Contents.json new file mode 100644 index 000000000000..17224e6add66 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/bell.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bell_1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bell_2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "bell_3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/bell.imageset/bell_1x.png b/ios/StatusIm/Images.xcassets/bell.imageset/bell_1x.png new file mode 100644 index 000000000000..986123f365c1 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/bell.imageset/bell_1x.png differ diff --git a/ios/StatusIm/Images.xcassets/bell.imageset/bell_2x.png b/ios/StatusIm/Images.xcassets/bell.imageset/bell_2x.png new file mode 100644 index 000000000000..4f4602ebaf1c Binary files /dev/null and b/ios/StatusIm/Images.xcassets/bell.imageset/bell_2x.png differ diff --git a/ios/StatusIm/Images.xcassets/bell.imageset/bell_3x.png b/ios/StatusIm/Images.xcassets/bell.imageset/bell_3x.png new file mode 100644 index 000000000000..bc17c822ad45 Binary files /dev/null and b/ios/StatusIm/Images.xcassets/bell.imageset/bell_3x.png differ diff --git a/ios/StatusIm/Images.xcassets/fingerprint.imageset/Contents.json b/ios/StatusIm/Images.xcassets/fingerprint.imageset/Contents.json new file mode 100644 index 000000000000..af6a125a0444 --- /dev/null +++ b/ios/StatusIm/Images.xcassets/fingerprint.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "fingerprint_1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "fingerprint_2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "fingerprint_3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_1x.png b/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_1x.png new file mode 100644 index 000000000000..7120503e075f Binary files /dev/null and b/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_1x.png differ diff --git a/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_2x.png b/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_2x.png new file mode 100644 index 000000000000..af1c6a23c35d Binary files /dev/null and b/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_2x.png differ diff --git a/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_3x.png b/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_3x.png new file mode 100644 index 000000000000..16dea45157fc Binary files /dev/null and b/ios/StatusIm/Images.xcassets/fingerprint.imageset/fingerprint_3x.png differ diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java index d37453e180f7..1b00185f3c2a 100644 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java @@ -660,6 +660,44 @@ public void run() { StatusThreadPoolExecutor.getInstance().execute(r); } + @ReactMethod + public void newOnboarding(final Integer n, final Integer mnemonicLength, final Callback callback) { + Log.d(TAG, "newOnboarding"); + if (!checkAvailability()) { + callback.invoke(false); + return; + } + Runnable r = new Runnable() { + @Override + public void run() { + String res = Statusgo.newOnboarding(n, mnemonicLength); + + callback.invoke(res); + } + }; + + StatusThreadPoolExecutor.getInstance().execute(r); + } + + @ReactMethod + public void importOnboardingAccount(final String id, final String password, final Callback callback) { + Log.d(TAG, "importOnboardingAccount"); + if (!checkAvailability()) { + callback.invoke(false); + return; + } + Runnable r = new Runnable() { + @Override + public void run() { + String res = Statusgo.importOnboardingAccount(id, password); + + callback.invoke(res); + } + }; + + StatusThreadPoolExecutor.getInstance().execute(r); + } + private String createIdentifier() { return UUID.randomUUID().toString(); } diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.m b/modules/react-native-status/ios/RCTStatus/RCTStatus.m index 77c3d7931713..d8fc175a8d6b 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.m +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.m @@ -335,6 +335,29 @@ - (void)handleSignal:(NSString *)signal callback(@[result]); } +//////////////////////////////////////////////////////////////////// recoverAccount +RCT_EXPORT_METHOD(newOnboarding:(NSInteger)n + password:(NSInteger)mnemonicLength + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"NewOnboarding() method called"); +#endif + NSString *result = StatusgoNewOnboarding(n, mnemonicLength); + callback(@[result]); +} + +//////////////////////////////////////////////////////////////////// recoverAccount +RCT_EXPORT_METHOD(importOnboardingAccount:(NSString *)id + password:(NSString *)password + callback:(RCTResponseSenderBlock)callback) { +#if DEBUG + NSLog(@"NewOnboarding() method called"); +#endif + NSString *result = StatusgoImportOnboardingAccount(id, password); + callback(@[result]); +} + + //////////////////////////////////////////////////////////////////// login RCT_EXPORT_METHOD(login:(NSString *)address password:(NSString *)password @@ -473,6 +496,7 @@ - (void)handleSignal:(NSString *)signal RCT_EXPORT_METHOD(clearCookies) { NSHTTPCookie *cookie; NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + for (cookie in [storage cookies]) { [storage deleteCookie:cookie]; } diff --git a/resources/images/ui/intro1.png b/resources/images/ui/intro1.png new file mode 100644 index 000000000000..2dc713333e92 Binary files /dev/null and b/resources/images/ui/intro1.png differ diff --git a/resources/images/ui/intro2.png b/resources/images/ui/intro2.png new file mode 100644 index 000000000000..b6b967ea87b5 Binary files /dev/null and b/resources/images/ui/intro2.png differ diff --git a/resources/images/ui/intro3.png b/resources/images/ui/intro3.png new file mode 100644 index 000000000000..885733f73b04 Binary files /dev/null and b/resources/images/ui/intro3.png differ diff --git a/resources/images/ui/sample-key.png b/resources/images/ui/sample-key.png new file mode 100644 index 000000000000..6ba485e18a80 Binary files /dev/null and b/resources/images/ui/sample-key.png differ diff --git a/src/status_im/accounts/create/core.cljs b/src/status_im/accounts/create/core.cljs index c95645a761de..c62311506647 100644 --- a/src/status_im/accounts/create/core.cljs +++ b/src/status_im/accounts/create/core.cljs @@ -17,7 +17,8 @@ [status-im.utils.identicon :as identicon] [status-im.utils.signing-phrase.core :as signing-phrase] [status-im.utils.types :as types] - [taoensso.timbre :as log] + [status-im.utils.utils :as utils] + [clojure.set :refer [map-invert]] [status-im.utils.fx :as fx] [status-im.node.core :as node] [status-im.ui.screens.mobile-network-settings.events :as mobile-network] @@ -26,25 +27,50 @@ (defn get-signing-phrase [cofx] (assoc cofx :signing-phrase (signing-phrase/generate))) +(def step-kw-to-num + {:generate-key 1 + :choose-key 2 + :select-key-storage 3 + :create-code 4 + :confirm-code 5 + :enable-fingerprint 6 + :enable-notifications 7}) + +(defn dec-step [step] + (let [inverted (map-invert step-kw-to-num)] + (inverted (dec (step-kw-to-num step))))) + +(defn inc-step [step] + (let [inverted (map-invert step-kw-to-num)] + (inverted (inc (step-kw-to-num step))))) + (defn get-status [cofx] (assoc cofx :status (rand-nth statuses/data))) -(defn create-account! [password] - (status/create-account - password - #(re-frame/dispatch [:accounts.create.callback/create-account-success (types/json->clj %) password]))) +(defn create-account! [{:keys [id password]}] + (if id + (status/import-onboarding-account + id + password + #(re-frame/dispatch [:accounts.create.callback/create-account-success (types/json->clj %) password])) + (status/create-account + password + #(re-frame/dispatch [:accounts.create.callback/create-account-success (types/json->clj %) password])))) ;;;; Handlers (defn create-account - [{:keys [db random-guid-generator] :as cofx}] + [{:keys [db] :as cofx}] (fx/merge cofx {:db (-> db (update :accounts/create assoc + :id (get-in db [:intro-wizard :selected-id]) + :password (or (get-in db [:accounts/create :password]) + (get-in db [:intro-wizard :key-code])) :step :account-creating :error nil) (assoc :node/on-ready :create-account - :accounts/new-installation-id (random-guid-generator)))} + :accounts/new-installation-id (random/guid)))} (node/initialize nil))) (fx/defn add-account @@ -59,44 +85,6 @@ {:db (assoc-in db [:accounts/accounts address] enriched-account) :data-store/base-tx [(accounts-store/save-account-tx enriched-account)]})) -(fx/defn on-account-created - [{:keys [signing-phrase - status - db] :as cofx} - {:keys [pubkey address mnemonic installation-id - keycard-instance-uid keycard-key-uid keycard-pairing keycard-paired-on]} - password - {:keys [seed-backed-up? login? new-account?] :or {login? true}}] - (let [normalized-address (utils.hex/normalize-hex address) - account {:public-key pubkey - :installation-id (or installation-id (get-in db [:accounts/new-installation-id])) - :address normalized-address - :name (gfycat/generate-gfy pubkey) - :status status - :signed-up? true - :desktop-notifications? false - :photo-path (identicon/identicon pubkey) - :signing-phrase signing-phrase - :seed-backed-up? seed-backed-up? - :mnemonic mnemonic - :keycard-instance-uid keycard-instance-uid - :keycard-key-uid keycard-key-uid - :keycard-pairing keycard-pairing - :keycard-paired-on keycard-paired-on - :settings (constants/default-account-settings) - :syncing-on-mobile-network? false - :remember-syncing-choice? false - :new-account? new-account?}] - (log/debug "account-created") - (when-not (string/blank? pubkey) - (fx/merge cofx - {:db (assoc db :accounts/login {:address normalized-address - :password password - :processing true})} - (add-account account) - (when login? - (accounts.login/user-login true)))))) - (defn reset-account-creation [{db :db}] {:db (update db :accounts/create assoc :step :enter-password @@ -145,6 +133,172 @@ (dissoc :password :password-confirm :name :error)))} (navigation/navigate-to-cofx :create-account nil))) +(fx/defn intro-wizard + {:events [:accounts.create.ui/intro-wizard]} + [{:keys [db] :as cofx}] + (fx/merge {:db (assoc db :intro-wizard {:step :generate-key :encrypt-with-password? true})} + (navigation/navigate-to-cofx :intro-wizard nil))) + +(fx/defn intro-step-back + {:events [:intro-wizard/step-back-pressed]} + [{:keys [db] :as cofx}] + (let [step (get-in db [:intro-wizard :step])] + (if (not= :generate-key step) + (fx/merge {:db (cond-> (assoc-in db [:intro-wizard :step] (dec-step step)) + (#{:create-code :confirm-code} step) + (assoc-in [:intro-wizard :key-code] nil) + (= step :confirm-code) + (assoc-in [:intro-wizard :confirm-failure?] false))} + (navigation/navigate-to-cofx :intro-wizard nil)) + + (fx/merge {:db (dissoc db :intro-wizard)} + (navigation/navigate-to-clean :intro nil))))) + +(fx/defn exit-wizard [{:keys [db] :as cofx}] + (fx/merge {:db (dissoc db :intro-wizard) + :notifications/request-notifications-permissions nil} + (navigation/navigate-to-cofx :home nil))) + +(fx/defn init-key-generation [{:keys [db] :as cofx}] + {:db (assoc-in db [:intro-wizard :generating-keys?] true) + :intro-wizard/new-onboarding {:n 5 :mnemonic-length 12}}) + +(fx/defn on-confirm-failure [{:keys [db] :as cofx}] + (do + (utils/vibrate) + {:db (assoc-in db [:intro-wizard :confirm-failure?] true)})) + +(defn confirm-failure? [db] + (let [step (get-in db [:intro-wizard :step])] + (and (= step :confirm-code) + (not (:accounts/login db)) + (get-in db [:intro-wizard :encrypt-with-password?]) + (not= (get-in db [:intro-wizard :stored-key-code]) (get-in db [:intro-wizard :key-code]))))) + +(fx/defn store-key-code [{:keys [db] :as cofx}] + {:db (update db :intro-wizard + assoc :stored-key-code (get-in db [:intro-wizard :key-code]) + :key-code nil + :step :confirm-code)}) + +(fx/defn intro-step-forward + {:events [:intro-wizard/step-forward-pressed]} + [{:keys [db] :as cofx} {:keys [skip?] :as opts}] + (let [step (get-in db [:intro-wizard :step])] + (cond (= step :enable-notifications) + (exit-wizard cofx) + + (= step :generate-key) + (init-key-generation cofx) + + (confirm-failure? db) + (on-confirm-failure cofx) + + (= step :create-code) + (store-key-code cofx) + + :else (fx/merge {:db (assoc-in db [:intro-wizard :step] + (inc-step step))} + (when (and (= step :confirm-code) + (not (:accounts/login db))) + (create-account cofx)))))) + +(fx/defn on-account-created + [{:keys [signing-phrase + status + db] :as cofx} + {:keys [pubkey address mnemonic installation-id + keycard-instance-uid keycard-key-uid keycard-pairing keycard-paired-on] :as result} + password + {:keys [seed-backed-up? login? new-account?] :or {login? true}}] + (let [normalized-address (utils.hex/normalize-hex address) + account {:public-key pubkey + :installation-id (or installation-id (get-in db [:accounts/new-installation-id])) + :address normalized-address + :name (gfycat/generate-gfy pubkey) + :status status + :signed-up? true + :desktop-notifications? false + :photo-path (identicon/identicon pubkey) + :signing-phrase signing-phrase + :seed-backed-up? seed-backed-up? + :mnemonic mnemonic + :keycard-instance-uid keycard-instance-uid + :keycard-key-uid keycard-key-uid + :keycard-pairing keycard-pairing + :keycard-paired-on keycard-paired-on + :settings (constants/default-account-settings) + :syncing-on-mobile-network? false + :remember-syncing-choice? false + :new-account? new-account?}] + (when-not (string/blank? pubkey) + (fx/merge cofx + {:db (assoc db :accounts/login {:address normalized-address + :password password + :processing true})} + (add-account account) + (when login? + (accounts.login/user-login true)) + (intro-step-forward {}))))) + +(re-frame/reg-fx + :intro-wizard/new-onboarding + (fn [{:keys [n mnemonic-length]}] + (status/new-onboarding n mnemonic-length + #(re-frame/dispatch [:intro-wizard/on-keys-generated (types/json->clj %)])))) + +(fx/defn on-keys-generated + {:events [:intro-wizard/on-keys-generated]} + [{:keys [db] :as cofx} result] + (fx/merge + {:db (update db :intro-wizard + (fn [data] + (-> data + (dissoc :generating-keys?) + (assoc :accounts (:accounts result) + :selected-storage-type :default + :selected-id (-> result :accounts first :id) + :step :choose-key))))} + (navigation/navigate-to-cofx :intro-wizard nil))) + +(fx/defn on-key-selected + {:events [:intro-wizard/on-key-selected]} + [{:keys [db] :as cofx} id] + {:db (assoc-in db [:intro-wizard :selected-id] id)}) + +(fx/defn on-key-storage-selected + {:events [:intro-wizard/on-key-storage-selected]} + [{:keys [db] :as cofx} storage-type] + {:db (assoc-in db [:intro-wizard :selected-storage-type] storage-type)}) + +(fx/defn on-encrypt-with-password-pressed + {:events [:intro-wizard/on-encrypt-with-password-pressed]} + [{:keys [db] :as cofx}] + {:db (assoc-in db [:intro-wizard :encrypt-with-password?] true)}) + +(fx/defn on-learn-more-pressed + {:events [:intro-wizard/on-learn-more-pressed]} + [{:keys [db] :as cofx}] + {:db (assoc-in db [:intro-wizard :show-learn-more?] true)}) + +(defn get-new-key-code [current-code sym encrypt-with-password?] + (cond (or (= sym :remove) (= sym "Backspace")) + (subs current-code 0 (dec (count current-code))) + (and (not encrypt-with-password?) (= (count current-code) 6)) + current-code + (= (count sym) 1) + (str current-code sym) + :else current-code)) + +(fx/defn code-symbol-pressed + {:events [:intro-wizard/code-symbol-pressed]} + [{:keys [db] :as cofx} sym] + (let [encrypt-with-password? (get-in db [:intro-wizard :encrypt-with-password?]) + new-key-code (get-new-key-code (get-in db [:intro-wizard :key-code]) sym encrypt-with-password?)] + {:db (-> db + (assoc-in [:intro-wizard :key-code] new-key-code) + (assoc-in [:intro-wizard :confirm-failure?] false))})) + ;;;; COFX (re-frame/reg-cofx diff --git a/src/status_im/init/core.cljs b/src/status_im/init/core.cljs index 5ec82672c7c8..f1dceae90fa0 100644 --- a/src/status_im/init/core.cljs +++ b/src/status_im/init/core.cljs @@ -166,6 +166,7 @@ :keys [accounts/accounts accounts/create networks/networks network network-status peers-count peers-summary view-id navigation-stack mailserver/mailservers + intro-wizard desktop/desktop hardwallet custom-fleets supported-biometric-auth device-UUID semaphores accounts/login] :node/keys [status on-ready] @@ -177,6 +178,7 @@ :view-id view-id :navigation-stack navigation-stack :node/status status + :intro-wizard intro-wizard :node/on-ready on-ready :accounts/create create :desktop/desktop (merge desktop (:desktop/desktop app-db)) @@ -201,20 +203,19 @@ (= view-id :create-account) (assoc-in [:accounts/create :step] :enter-name))})) -(defn login-only-events [cofx address stored-pns] +(defn login-only-events [{:keys [db] :as cofx} address stored-pns] (fx/merge cofx - (cond-> - {:notifications/request-notifications-permissions nil} - - platform/ios? - ;; on ios navigation state might be not initialized yet when - ;; navigate-to call happens. - ;; That's why it should be delayed a bit. - ;; TODO(rasom): revisit this later and find better solution - (assoc :dispatch-later - [{:ms 1 - :dispatch [:navigate-to :home]}])) - (when-not platform/ios? + (when-not (:intro-wizard db) + (cond-> {:notifications/request-notifications-permissions nil} + platform/ios? + ;; on ios navigation state might be not initialized yet when + ;; navigate-to call happens. + ;; That's why it should be delayed a bit. + ;; TODO(rasom): revisit this later and find better solution + (assoc :dispatch-later + [{:ms 1 + :dispatch [:navigate-to :home]}]))) + (when-not (or (:intro-wizard db) platform/ios?) (navigation/navigate-to-cofx :home nil)) (notifications/process-stored-event address stored-pns) (when platform/desktop? diff --git a/src/status_im/native_module/core.cljs b/src/status_im/native_module/core.cljs index 32f779cfc5c2..dedc9b386ebb 100644 --- a/src/status_im/native_module/core.cljs +++ b/src/status_im/native_module/core.cljs @@ -22,6 +22,12 @@ (defn recover-account [passphrase password callback] (native-module/recover-account passphrase password callback)) +(defn new-onboarding [n mnemonic-length callback] + (native-module/new-onboarding n mnemonic-length callback)) + +(defn import-onboarding-account [id password callback] + (native-module/import-onboarding-account id password callback)) + (defn login [address password callback] (native-module/login address password callback)) diff --git a/src/status_im/native_module/impl/module.cljs b/src/status_im/native_module/impl/module.cljs index fb6c2ea9708b..c247878a3f6d 100644 --- a/src/status_im/native_module/impl/module.cljs +++ b/src/status_im/native_module/impl/module.cljs @@ -61,6 +61,14 @@ (when (and @node-started (status)) (.recoverAccount (status) passphrase password on-result))) +(defn new-onboarding [n mnemonic-length on-result] + (when true #_(and @node-started (status)) + (.newOnboarding (status) n mnemonic-length on-result))) + +(defn import-onboarding-account [id password on-result] + (when true #_(and @node-started (status)) + (.importOnboardingAccount (status) id password on-result))) + (defn login [address password on-result] (when (and @node-started (status)) (.login (status) address password on-result))) diff --git a/src/status_im/react_native/resources.cljs b/src/status_im/react_native/resources.cljs index 2d8c84fe6ccb..0e2b4381682c 100644 --- a/src/status_im/react_native/resources.cljs +++ b/src/status_im/react_native/resources.cljs @@ -6,6 +6,10 @@ :empty-recent (js-require/js-require "./resources/images/ui/empty-recent.png") :analytics-image (js-require/js-require "./resources/images/ui/analytics-image.png") :welcome-image (js-require/js-require "./resources/images/ui/welcome-image.png") + :intro1 (js-require/js-require "./resources/images/ui/intro1.png") + :intro2 (js-require/js-require "./resources/images/ui/intro2.png") + :intro3 (js-require/js-require "./resources/images/ui/intro3.png") + :sample-key (js-require/js-require "./resources/images/ui/sample-key.png") :lock (js-require/js-require "./resources/images/ui/lock.png") :tribute-to-talk (js-require/js-require "./resources/images/ui/tribute-to-talk.png") :wallet-welcome (js-require/js-require "./resources/images/ui/wallet-welcome.png") diff --git a/src/status_im/signals/core.cljs b/src/status_im/signals/core.cljs index a5fd597c7215..b8e2117e009c 100644 --- a/src/status_im/signals/core.cljs +++ b/src/status_im/signals/core.cljs @@ -37,7 +37,7 @@ [address password (:realm-error db)]})) :create-account (fn [_] - {:accounts.create/create-account (:password create)}) + {:accounts.create/create-account (select-keys create [:id :password])}) :recover-account (fn [{:keys [db]}] (let [{:keys [password passphrase]} (:accounts/recover db)] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index db032799dd0b..ae82e5d44f23 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -176,6 +176,9 @@ (reg-root-key-sub :signing/sign :signing/sign) (reg-root-key-sub :signing/edit-fee :signing/edit-fee) +;;intro-wizard +(reg-root-key-sub :intro-wizard :intro-wizard) + ;;GENERAL ============================================================================================================== (re-frame/reg-sub diff --git a/src/status_im/ui/components/typography.cljs b/src/status_im/ui/components/typography.cljs index a5ab3795380c..ece92fee6d76 100644 --- a/src/status_im/ui/components/typography.cljs +++ b/src/status_im/ui/components/typography.cljs @@ -70,15 +70,17 @@ (assoc style :font-family default-font-family) (-> style (assoc :font-family - (str default-font-family "-" - (case font-weight - "400" (when-not (= font-style :italic) - "Regular") - "500" "Medium" - "600" "SemiBold" - "700" "Bold") - (when (= font-style :italic) - "Italic"))) + (if (= (:font-family style) "monospace") + (if platform/ios? "Menlo-Regular" "monospace") + (str default-font-family "-" + (case font-weight + "400" (when-not (= font-style :italic) + "Regular") + "500" "Medium" + "600" "SemiBold" + "700" "Bold") + (when (= font-style :italic) + "Italic")))) (dissoc :font-weight :font-style))))) (defn get-nested-style diff --git a/src/status_im/ui/screens/about_app/styles.cljs b/src/status_im/ui/screens/about_app/styles.cljs index 3d55e62df8bc..96256305f3dc 100644 --- a/src/status_im/ui/screens/about_app/styles.cljs +++ b/src/status_im/ui/screens/about_app/styles.cljs @@ -17,3 +17,9 @@ (def about-title-text {:font-size 20}) + +(def learn-more-title + {:typography :title-bold}) + +(def learn-more-text + {:color colors/gray}) diff --git a/src/status_im/ui/screens/about_app/views.cljs b/src/status_im/ui/screens/about_app/views.cljs index 987e3826be81..814c3b50dc78 100644 --- a/src/status_im/ui/screens/about_app/views.cljs +++ b/src/status_im/ui/screens/about_app/views.cljs @@ -1,11 +1,14 @@ (ns status-im.ui.screens.about-app.views - (:require-macros [status-im.utils.views :as views]) + (:require-macros [status-im.utils.views :as views] + [status-im.utils.views :refer [defview letsubs]]) (:require [status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.react :as react] [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.screens.about-app.styles :as styles] [status-im.i18n :as i18n] [status-im.transport.utils :as transport.utils] + [status-im.ui.components.colors :as colors] [status-im.ui.screens.profile.components.views :as profile.components] [re-frame.core :as re-frame])) @@ -20,6 +23,19 @@ nil 4)) +(defview learn-more-sheet [] + (letsubs [{:keys [title content]} [:bottom-sheet/options]] + [react/view {:style {:padding 16}} + [react/view {:style {:align-items :center :flex-direction :row :margin-bottom 16}} + [vector-icons/icon :main-icons/info {:color colors/blue + :container-style {:margin-right 13}}] + [react/text {:style styles/learn-more-title} title]] + [react/text {:style styles/learn-more-text} content]])) + +(def learn-more + {:content learn-more-sheet + :content-height 180}) + (defn peer-view [{:keys [enode]}] (let [[enode-id ip-address port] (transport.utils/extract-url-components enode)] ^{:key enode} diff --git a/src/status_im/ui/screens/home/styles.cljs b/src/status_im/ui/screens/home/styles.cljs index 7d9330bb7e1d..7870f854d313 100644 --- a/src/status_im/ui/screens/home/styles.cljs +++ b/src/status_im/ui/screens/home/styles.cljs @@ -170,6 +170,13 @@ (def welcome-view {:flex 1}) +(def action-button-container + {:position :absolute + :align-items :center + :bottom (+ tabs.styles/tabs-diff 6) + :width 40 + :height 40}) + (def welcome-image-container {:align-items :center :margin-top 42}) @@ -185,13 +192,6 @@ :margin-horizontal 32 :color colors/gray}) -(def action-button-container - {:position :absolute - :align-items :center - :bottom (+ tabs.styles/tabs-diff 6) - :width 40 - :height 40}) - (def action-button {:width 40 :height 40 diff --git a/src/status_im/ui/screens/intro/styles.cljs b/src/status_im/ui/screens/intro/styles.cljs index df7fd58c67fe..1a977ca572ad 100644 --- a/src/status_im/ui/screens/intro/styles.cljs +++ b/src/status_im/ui/screens/intro/styles.cljs @@ -4,30 +4,100 @@ (def intro-view {:flex 1 + :justify-content :flex-end :padding-horizontal 30}) (def intro-logo-container - {:flex 1 - :align-items :center + {:align-items :center :justify-content :center}) -(def intro-logo - {:size 111}) +(defn dot-selector [n] + (let [diameter 6 + interval 10] + {:flex-direction :row + :justify-content :space-between + :align-items :center + :height diameter + :width (+ diameter (* (+ diameter interval) + (dec n)))})) -(defstyle intro-text - {:text-align :center - :font-weight "700" - :font-size 24}) +(defn dot [color selected?] + {:background-color (if selected? + color + (colors/alpha color 0.2)) + :width 6 + :height 6 + :border-radius 3}) -(def intro-text-description - {:margin-top 8 - :margin-bottom 16 +(def welcome-image-container + {:align-items :center + :margin-top 42}) + +(def wizard-title + {:typography :header :text-align :center - :color colors/gray}) + :margin-bottom 16}) + +(def wizard-text + {:color colors/gray + :text-align :center}) + +(def welcome-text + {:typography :header + :margin-top 32 + :text-align :center}) + +(def welcome-text-bottom-note + {:typography :caption + :color colors/gray + :text-align :center}) + +(defn list-item [selected?] + {:flex-direction :row + :align-items :center + :padding-left 16 + :padding-right 10 + :background-color (if selected? colors/blue-light colors/white) + :padding-vertical 10}) + +(def account-image + {:width 40 + :height 40 + :border-radius 20 + :border-width 1 + :border-color (colors/alpha colors/black 0.1)}) + +(def welcome-text-description + {:margin-top 8 + :text-align :center + :margin-horizontal 32 + :color colors/gray}) + +(def intro-logo + {:size 111}) + +(def password-text-input + {:typography :header}) (def buttons-container - {:align-items :center}) + {:align-items :center + :margin-top 32}) + +(def bottom-button + {:padding-horizontal 24 + :justify-content :center + :align-items :center + :flex-direction :row}) (def bottom-button-container - {:margin-bottom 6 - :margin-top 38}) + {:margin-bottom 24 + :margin-top 16}) + +(def bottom-arrow + {:flex-direction :row + :justify-content :flex-end + :align-self :stretch + :padding-top 16 + :border-top-width 1 + :border-top-color colors/gray-lighter + :margin-right 20}) diff --git a/src/status_im/ui/screens/intro/views.cljs b/src/status_im/ui/screens/intro/views.cljs index f5753e67acc1..4a3c728e70ef 100644 --- a/src/status_im/ui/screens/intro/views.cljs +++ b/src/status_im/ui/screens/intro/views.cljs @@ -2,28 +2,295 @@ (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [status-im.ui.components.react :as react] [re-frame.core :as re-frame] + [status-im.react-native.resources :as resources] + [status-im.privacy-policy.core :as privacy-policy] + [status-im.accounts.create.core :refer [step-kw-to-num]] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.utils.identicon :as identicon] + [status-im.ui.components.radio :as radio] + [taoensso.timbre :as log] + [status-im.utils.gfycat.core :as gfy] + [status-im.ui.components.colors :as colors] + [reagent.core :as r] + [status-im.ui.components.toolbar.actions :as actions] [status-im.ui.components.common.common :as components.common] [status-im.ui.screens.intro.styles :as styles] + [status-im.ui.components.toolbar.view :as toolbar] [status-im.i18n :as i18n] - [status-im.ui.components.status-bar.view :as status-bar] - [status-im.ui.screens.privacy-policy.views :as privacy-policy])) + [status-im.ui.components.status-bar.view :as status-bar])) + +(defn dots-selector [{:keys [on-press n selected color]}] + [react/view {:style (styles/dot-selector n)} + (doall + (for [i (range n)] + ^{:key i} + [react/view {:style (styles/dot color (selected i))}]))]) + +(defn intro-viewer [slides window-width] + (let [margin 24 + view-width (- window-width (* 2 margin)) + scroll-x (r/atom 0) + scroll-view-ref (atom nil) + max-width (* view-width (dec (count slides)))] + (fn [] + [react/view {:style {:margin-horizontal 32 + :align-items :center + :justify-content :flex-end}} + [react/scroll-view {:horizontal true + :paging-enabled true + :ref #(reset! scroll-view-ref %) + :shows-vertical-scroll-indicator false + :shows-horizontal-scroll-indicator false + :pinch-gesture-enabled false + :on-scroll #(let [x (.-nativeEvent.contentOffset.x %)] + (reset! scroll-x x)) + :style {:width view-width + :margin-vertical 32}} + (for [s slides] + ^{:key (:title s)} + [react/view {:style {:width view-width + :padding-horizontal 16}} + [react/view {:style styles/intro-logo-container} + [components.common/image-contain + {:container-style {}} + {:image (:image s) :width view-width :height view-width}]] + [react/i18n-text {:style styles/wizard-title :key (:title s)}] + [react/i18n-text {:style styles/wizard-text + :key (:text s)}]])] + (let [selected (hash-set (/ @scroll-x view-width))] + [dots-selector {:selected selected :n (count slides) + :color colors/blue}])]))) (defview intro [] - [react/view {:style styles/intro-view} - [status-bar/status-bar {:flat? true}] - [react/view {:style styles/intro-logo-container} - [components.common/logo styles/intro-logo]] - [react/i18n-text {:style styles/intro-text - :key :intro-text}] - [react/view - [react/i18n-text {:style styles/intro-text-description - :key :intro-text-description}]] - [react/view styles/buttons-container - [components.common/button {:button-style {:flex-direction :row} - :on-press #(re-frame/dispatch [:accounts.create.ui/create-new-account-button-pressed]) - :label (i18n/label :t/create-account)}] - [react/view styles/bottom-button-container - [components.common/button {:on-press #(re-frame/dispatch [:accounts.recover.ui/recover-account-button-pressed]) - :label (i18n/label :t/already-have-account) - :background? false}]] - [privacy-policy/privacy-policy-button]]]) + (letsubs [window-width [:dimensions/window-width]] + [react/view {:style styles/intro-view} + [status-bar/status-bar {:flat? true}] + [intro-viewer [{:image (:intro1 resources/ui) + :title :intro-title1 + :text :intro-text1} + {:image (:intro2 resources/ui) + :title :intro-title2 + :text :intro-text2} + {:image (:intro3 resources/ui) + :title :intro-title3 + :text :intro-text3}] window-width] + [react/view styles/buttons-container + [components.common/button {:button-style (assoc styles/bottom-button :margin-bottom 16) + :on-press #(re-frame/dispatch [:accounts.create.ui/intro-wizard]) + :label (i18n/label :t/get-started)}] + [components.common/button {:button-style (assoc styles/bottom-button :margin-bottom 24) + :on-press #(re-frame/dispatch [:accounts.recover.ui/recover-account-button-pressed]) + :label (i18n/label :t/access-key) + :background? false}] + [react/nested-text + {:style styles/welcome-text-bottom-note} + (i18n/label :t/intro-privacy-policy-note1) + [{:style (assoc styles/welcome-text-bottom-note :color colors/blue) + :on-press privacy-policy/open-privacy-policy-link!} + (i18n/label :t/intro-privacy-policy-note2)]]]])) + +(defn generate-key [] + [components.common/image-contain + {:container-style {:margin-horizontal 80}} + {:image (resources/get-image :sample-key) + :width 154 :height 140}]) + +(defn choose-key [{:keys [accounts selected-id] :as wizard-state} view-height] + [react/scroll-view {:content-container-style {:flex 1 + :justify-content :flex-end + ;; We have to align top account entry + ;; with top key storage entry on the next screen + :margin-bottom (if (< view-height 600) + -20 + (/ view-height 12))}} + (for [acc accounts] + (let [selected? (= (:id acc) selected-id)] + ^{:key (:pubkey acc)} + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:intro-wizard/on-key-selected (:id acc)])} + [react/view {:style (styles/list-item selected?)} + + [react/image {:source {:uri (identicon/identicon (:pubkey acc))} + :style styles/account-image}] + [react/view {:style {:margin-horizontal 16 :flex 1 :justify-content :space-between}} + [react/text {:style (assoc styles/wizard-text :text-align :left + :color colors/black + :font-weight "500") + :number-of-lines 1 + :ellipsize-mode :middle} + (gfy/generate-gfy (:pubkey acc))] + [react/text {:style (assoc styles/wizard-text + :text-align :left + :font-family "monospace") + :number-of-lines 1 + :ellipsize-mode :middle} + (:pubkey acc)]] + [radio/radio selected?]]]))]) + +(defn storage-entry [{:keys [type icon title desc]} selected-storage-type] + (let [selected? (= type selected-storage-type)] + [react/view + [react/view {:style {:padding-top 14 :padding-bottom 4}} + [react/text {:style (assoc styles/wizard-text :text-align :left :margin-left 16)} + (i18n/label type)]] + [react/touchable-highlight + {:on-press #(re-frame/dispatch [:intro-wizard/on-key-storage-selected type])} + [react/view (assoc (styles/list-item selected?) + :align-items :flex-start + :padding-top 20 + :padding-bottom 12) + [vector-icons/icon icon {:color (if selected? colors/blue colors/gray) + :width 24 :height 24}] + [react/view {:style {:margin-horizontal 16 :flex 1}} + [react/text {:style (assoc styles/wizard-text :font-weight "500" :color colors/black :text-align :left)} + (i18n/label title)] + [react/view {:style {:min-height 4 :max-height 4}}] + [react/text {:style (assoc styles/wizard-text :text-align :left)} + (i18n/label desc)]] + [radio/radio selected?]]]])) + +(defn select-key-storage [{:keys [selected-storage-type] :as wizard-state} view-height] + (let [storage-types [{:type :default + :icon :main-icons/mobile + :title :this-device + :desc :this-device-desc} + {:type :advanced + :icon :main-icons/keycard-logo + :title :keycard + :desc :keycard-desc}]] + [react/view {:style {:flex 1 + :justify-content :flex-end + ;; We have to align top storage entry + ;; with top account entry on the previous screen + :margin-bottom (+ (- 300 232) (if (< view-height 600) + -20 + (/ view-height 12)))}} + [storage-entry (first storage-types) selected-storage-type] + [react/view {:style {:min-height 16 :max-height 16}}] + [storage-entry (second storage-types) selected-storage-type]])) + +(defn password-container [confirm-failure?] + [react/view {:style {:flex 1 + :justify-content :space-between + :align-items :center :margin-horizontal 16}} + [react/view {:style {:justify-content :center :flex 1}} + [react/text {:style (assoc styles/wizard-text :color colors/red + :margin-bottom 16)} + (if confirm-failure? (i18n/label :t/password_error1) " ")] + + [react/text-input {:secure-text-entry true + :auto-focus true + :text-align :center + :placeholder "" + :style styles/password-text-input + :on-key-press #(re-frame/dispatch [:intro-wizard/code-symbol-pressed (.-key (.-nativeEvent %))])}]] + [react/text {:style (assoc styles/wizard-text :margin-bottom 16)} (i18n/label :t/password-description)]]) + +(defn create-code [{:keys [confirm-failure?] :as wizard-state}] + [password-container confirm-failure?]) + +(defn confirm-code [{:keys [confirm-failure?] :as wizard-state}] + [password-container confirm-failure?]) + +(defn enable-fingerprint [] + [vector-icons/icon :main-icons/fingerprint + {:container-style {:align-items :center + :justify-content :center} + :width 76 :height 84}]) + +(defn enable-notifications [] + [vector-icons/icon :main-icons/bell {:container-style {:align-items :center + :justify-content :center} + :width 66 :height 64}]) + +(defn bottom-bar [{:keys [step generating-keys? encrypt-with-password?] :as wizard-state}] + [react/view {:style {:margin-bottom (if (or (#{:choose-key :select-key-storage} step) + (and (#{:create-code :confirm-code} step) + encrypt-with-password?)) + 20 + 32) + :align-items :center}} + (cond generating-keys? + [react/activity-indicator {:animating true + :size :large}] + (#{:generate-key :enable-fingerprint :enable-notifications} step) + (let [label-kw (case step + :generate-key :generate-a-key + :enable-fingerprint :intro-wizard-title6 + :enable-notifications :intro-wizard-title7)] + [components.common/button {:button-style styles/bottom-button + :on-press #(re-frame/dispatch + [:intro-wizard/step-forward-pressed]) + :label (i18n/label label-kw)}]) + (and (#{:create-code :confirm-code} step) + (not encrypt-with-password?)) + [components.common/button {:button-style styles/bottom-button + :label (i18n/label :t/encrypt-with-password) + :on-press #(re-frame/dispatch [:intro-wizard/on-encrypt-with-password-pressed]) + :background? false}] + + :else + [react/view {:style styles/bottom-arrow} + [components.common/bottom-button {:on-press #(re-frame/dispatch + [:intro-wizard/step-forward-pressed]) + :forward? true}]]) + (when (#{:enable-fingerprint :enable-notifications} step) + [components.common/button {:button-style (assoc styles/bottom-button :margin-top 20) + :label (i18n/label :t/maybe-later) + :on-press #(re-frame/dispatch [:intro-wizard/step-forward-pressed {:skip? true}]) + :background? false}]) + (when (= :generate-key step) + [react/text {:style (assoc styles/wizard-text :margin-top 20)} + (i18n/label (if generating-keys? :t/generating-keys + :t/this-will-take-few-seconds))])]) + +(defn top-bar [{:keys [step encrypt-with-password?]}] + (let [hide-subtitle? (or (= step :confirm-code) + (and (#{:create-code :confirm-code} step) encrypt-with-password?))] + [react/view {:style {:margin-top 16 + :margin-horizontal 32}} + + [react/text {:style (cond-> styles/wizard-title + hide-subtitle? + (assoc :margin-bottom 0))} + (i18n/label (keyword (str "intro-wizard-title" (when (and (#{:create-code :confirm-code} step) encrypt-with-password?) + "-alt") (step-kw-to-num step))))] + (cond (#{:choose-key :select-key-storage} step) + ; Use nested text for the "Learn more" link + [react/nested-text {:style styles/wizard-text} + (str (i18n/label (keyword (str "intro-wizard-text" (step-kw-to-num step)))) " ") + [{:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet :learn-more + {:title (i18n/label (if (= step :choose-key) :t/about-names-title :t/about-key-storage-title)) + :content (i18n/label (if (= step :choose-key) :t/about-names-content :t/about-key-storage-content))}]) + :style {:color colors/blue}} + (i18n/label :learn-more)]] + (not hide-subtitle?) + [react/text {:style styles/wizard-text} + (i18n/label (keyword (str "intro-wizard-text" (step-kw-to-num step))))] + :else nil)])) + +(defview wizard [] + (letsubs [{:keys [step generating-keys?] :as wizard-state} [:intro-wizard] + {view-height :height} [:dimensions/window]] + [react/keyboard-avoiding-view {:style {:flex 1}} + [toolbar/toolbar + {:style {:border-bottom-width 0 + :margin-top 0}} + (when-not (#{:enable-fingerprint :enable-notifications} step) + (toolbar/nav-button + (actions/back #(re-frame/dispatch + [:intro-wizard/step-back-pressed])))) + nil] + [react/view {:style {:flex 1 + :justify-content :space-between}} + [top-bar wizard-state] + (case step + :generate-key [generate-key] + :choose-key [choose-key wizard-state view-height] + :select-key-storage [select-key-storage wizard-state view-height] + :create-code [create-code wizard-state] + :confirm-code [confirm-code wizard-state] + :enable-fingerprint [enable-fingerprint] + :enable-notifications [enable-notifications] + nil nil) + [bottom-bar wizard-state]]])) diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index b02bd512e079..ef4836d45542 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -252,7 +252,7 @@ [react/view {:style styles/advanced-button-container-background} [react/view {:style styles/advanced-button-row} [react/text {:style styles/advanced-button-label} - (i18n/label :t/wallet-advanced)] + (i18n/label :t/advanced)] [icons/icon (if advanced? :main-icons/dropdown-up :main-icons/dropdown) {:color colors/blue}]]]]] (when advanced? [advanced-settings params on-show supported-biometric-auth])])) diff --git a/src/status_im/ui/screens/routing/intro_login_stack.cljs b/src/status_im/ui/screens/routing/intro_login_stack.cljs index 6a8285816c77..bf761de0879f 100644 --- a/src/status_im/ui/screens/routing/intro_login_stack.cljs +++ b/src/status_im/ui/screens/routing/intro_login_stack.cljs @@ -8,6 +8,7 @@ :recover :accounts :intro + :intro-wizard :hardwallet-authentication-method :hardwallet-connect :enter-pin-login @@ -37,6 +38,6 @@ (defn intro-stack [] (-> (login-stack :intro) - (update :screens conj :intro) + (update :screens conj :intro :intro-wizard) (assoc :name :intro-stack) (assoc :config {:initialRouteName :intro}))) diff --git a/src/status_im/ui/screens/routing/screens.cljs b/src/status_im/ui/screens/routing/screens.cljs index eb5659a9905d..9e01aeace6cd 100644 --- a/src/status_im/ui/screens/routing/screens.cljs +++ b/src/status_im/ui/screens/routing/screens.cljs @@ -152,6 +152,7 @@ :currency-settings currency-settings/currency-settings :backup-seed profile.seed/backup-seed :tribute-to-talk tr-to-talk/tribute-to-talk + :intro-wizard intro/wizard :reset-card hardwallet.settings/reset-card :keycard-settings hardwallet.settings/keycard-settings :mobile-network-settings mobile-network-settings/mobile-network-settings diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index dfccaeed2b25..cbad05548fa1 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -3,6 +3,7 @@ (:require [re-frame.core :refer [dispatch]] [status-im.utils.platform :refer [android?]] [status-im.utils.universal-links.core :as utils.universal-links] + [status-im.ui.screens.about-app.views :as about-app] [status-im.ui.components.react :as react] [status-im.ui.components.bottom-sheet.core :as bottom-sheet] [status-im.utils.navigation :as navigation] @@ -45,6 +46,9 @@ (= view :public-chat-actions) (merge home.sheet/public-chat-actions) + (= view :learn-more) + (merge about-app/learn-more) + (= view :private-chat-actions) (merge home.sheet/private-chat-actions) diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index a83a4d08761a..5aad69e82025 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -87,4 +87,4 @@ :scroll scroll :chain chain :all-tokens all-tokens - :network-status network-status}])) \ No newline at end of file + :network-status network-status}])) diff --git a/src/status_im/utils/utils.cljs b/src/status_im/utils/utils.cljs index b6610604b0a7..bcfa70529f66 100644 --- a/src/status_im/utils/utils.cljs +++ b/src/status_im/utils/utils.cljs @@ -19,6 +19,9 @@ (when on-dismiss (clj->js {:cancelable false}))))) +(defn vibrate [] + (.vibrate (.-Vibration rn-dependencies/react-native))) + (re-frame/reg-fx :utils/show-popup (fn [{:keys [title content on-dismiss]}] diff --git a/test/cljs/status_im/test/accounts/create/core.cljs b/test/cljs/status_im/test/accounts/create/core.cljs index ded8fdb2a7d8..7191b984e3d3 100644 --- a/test/cljs/status_im/test/accounts/create/core.cljs +++ b/test/cljs/status_im/test/accounts/create/core.cljs @@ -1,5 +1,6 @@ (ns status-im.test.accounts.create.core (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.utils.utils :as utils] [status-im.accounts.create.core :as models])) (deftest on-account-created @@ -11,23 +12,65 @@ :mnemonic "hello world"} "password" true)] - (is (= (:db result) - {:accounts/login {:address "7e92236392a850980d00d0cd2a4b92886bd7fe7b", :password "password", :processing true}, - :accounts/accounts {"7e92236392a850980d00d0cd2a4b92886bd7fe7b" - {:address "7e92236392a850980d00d0cd2a4b92886bd7fe7b", :mnemonic "hello world", :signing-phrase "", - :signed-up? true, :name "Dark Woozy Alligatorsnappingturtle", :desktop-notifications? false, - :settings {:wallet {:visible-tokens {:testnet #{:STT :HND}, - :mainnet #{:SNT}, - :rinkeby #{:MOKSHA :KDO}, :xdai #{}, :poa #{}}}}, - :networks nil, - :photo-path "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX////YjowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRS2MAAABAHRSTlP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmfXxgAABnNJREFUeNoBaAaX+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAQEBAQAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAABAQEBAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAQEAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoRUBAbwwC1cAAAAASUVORK5CYII=", - :seed-backed-up? true, - :network "mainnet_rpc", - :public-key "04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56", - :installation-id ""}}, - :network "mainnet_rpc", - :node/status :starting})) (is (= (keys result) - [:db - :node/start - :data-store/base-tx])))) + [:db :accounts.login/clear-web-data :data-store/change-account :data-store/base-tx])))) + +(deftest intro-step-back + (testing "Back from choose-key" + (let [db {:intro-wizard {:step :choose-key}} + result (get-in (models/intro-step-back {:db db}) [:db :intro-wizard])] + (is (= result {:step :generate-key})))) + + (testing "Back from create-code" + (let [db {:intro-wizard {:step :create-code :key-code "qwerty"}} + result (get-in (models/intro-step-back {:db db}) [:db :intro-wizard])] + (is (= result {:step :select-key-storage :key-code nil})))) + + (testing "Back from confirm-code" + (let [db {:intro-wizard {:step :confirm-code :confirm-failure? true}} + result (get-in (models/intro-step-back {:db db}) [:db :intro-wizard])] + (is (= result {:step :create-code :key-code nil :confirm-failure? false}))))) + +(deftest intro-step-forward + (testing "Forward from choose-key" + (let [db {:intro-wizard {:step :choose-key}} + ;; In this case intro-step-forward returns fx/merge result which is an fn + ;; to be invoked on cofx + result (get-in ((models/intro-step-forward {:db db}) {:db db}) [:db :intro-wizard])] + (is (= result {:step :select-key-storage})))) + + (testing "Forward from generate-key" + (let [db {:intro-wizard {:step :generate-key}} + result ((models/intro-step-forward {:db db}) {:db db})] + (is (= result {:db {:intro-wizard {:step :generate-key :generating-keys? true}} + :intro-wizard/new-onboarding {:n 5 :mnemonic-length 12}})))) + + (testing "Forward from create-code" + (let [db {:intro-wizard {:step :create-code :key-code "qwerty"}} + result (get-in ((models/intro-step-forward {:db db}) {:db db}) [:db :intro-wizard])] + (is (= result {:step :confirm-code :key-code nil :stored-key-code "qwerty"})))) + + (testing "Forward from confirm-code (failure case)" + (with-redefs [utils/vibrate (fn [] "vibrating")] + (let [db {:intro-wizard {:step :confirm-code :key-code "abcdef" :encrypt-with-password? true :stored-key-code "qwerty"}} + result (get-in ((models/intro-step-forward {:db db}) {:db db}) [:db :intro-wizard])] + (is (= result {:step :confirm-code :key-code "abcdef" :confirm-failure? true + :encrypt-with-password? true + :stored-key-code "qwerty"})))))) + +(deftest on-keys-generated + (testing "Test merging of generated keys into app-db" + (let [db {:intro-wizard {:step :generate-key :generating-keys true}} + accounts [{:id "0x01"} + {:id "0x02"} + {:id "0x03"} + {:id "0x04"} + {:id "0x05"}] + result (get-in (models/on-keys-generated {:db db} {:accounts accounts}) [:db :intro-wizard])] + (is (= result) {:step :choose-key :accounts accounts :selected-storage-type :default :selected-id (-> accounts first :id)})))) + +(deftest get-new-key-code + (testing "Add new character to keycode" + (is (= "abcd" (models/get-new-key-code "abc" "d" true)))) + (testing "Remove trailing character from keycode" + (is (= "ab" (models/get-new-key-code "abc" :remove true))))) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index 9fc76a3609b3..78f865df8397 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -1,5 +1,6 @@ (ns status-im.test.runner (:require [doo.runner :refer-macros [doo-tests]] + [status-im.test.accounts.create.core] [status-im.test.accounts.recover.core] [status-im.test.browser.core] [status-im.test.browser.permissions] @@ -81,6 +82,7 @@ (set! goog.DEBUG false) (doo-tests + 'status-im.test.accounts.create.core 'status-im.test.accounts.recover.core 'status-im.test.browser.core 'status-im.test.browser.permissions @@ -151,4 +153,4 @@ 'status-im.test.utils.utils 'status-im.test.wallet.subs 'status-im.test.wallet.transactions - 'status-im.test.wallet.transactions.subs) \ No newline at end of file + 'status-im.test.wallet.transactions.subs) diff --git a/translations/el.json b/translations/el.json index 82d59b065021..e89bec621bee 100644 --- a/translations/el.json +++ b/translations/el.json @@ -7,7 +7,7 @@ "amount": "Ποσό", "open": "Άνοιγμα", "close-app-title": "Προειδοποίηση!", - "wallet-advanced": "Προχωρημένη", + "advanced": "Προχωρημένη", "members-active": { "one": "1 μέλος", "other": "{{count}} μέλη", diff --git a/translations/en.json b/translations/en.json index b664bf06f5ae..39fdbf26b4d0 100644 --- a/translations/en.json +++ b/translations/en.json @@ -151,6 +151,41 @@ "other": "{{count}} members" }, "intro-message1": "Welcome to Status!\nTap this message to set your password and get started.", + "intro-title1": "Private, secure communication", + "intro-text1": "An open source platform to securely chat and transact on the Ethereum blockchain", + "intro-title2": "Secure crypto wallet", + "intro-text2": "Your account has been set up. Please dont forget to backup your recovery phrase in your profile", + "intro-title3": "Decentralized apps", + "intro-text3": "Your account has been set up. Please dont forget to backup your recovery phrase in your profile", + "intro-privacy-policy-note1": "Status does not collect, share or sell any personal data. By continuing you agree with the ", + "intro-privacy-policy-note2": "privacy policy", + "intro-wizard-title1": "Get yourself a key first", + "intro-wizard-text1": "Your identity is secure by design. You get a locally generated cryptographic keypair", + "intro-wizard-title2": "Choose a key and name", + "intro-wizard-text2": "This name is your identity in Status. It can’t be changed once you choose one. ", + "intro-wizard-title3": "Select key storage", + "intro-wizard-text3": "Your key is stored locally. There is no copy. Only you have access.", + "intro-wizard-title4": "Create a 6-digit code", + "intro-wizard-title-alt4": "Create a password", + "intro-wizard-text4": "Secure and encrypt your key", + "intro-wizard-title5": "Confirm the code", + "intro-wizard-title-alt5": "Confirm your password", + "intro-wizard-title6": "Enable fingerprint", + "intro-wizard-text6": "Make it easy to sign and send transactions by enambling fingerprint signing", + "intro-wizard-title7": "Enable notifications", + "intro-wizard-text7": "Status will notify you about new messages. You can edit your notification preferences later in settings", + "generate-a-key": "Generate a key", + "generating-keys": "Generating keys...", + "you-will-need-this-code": "You'll need this code to open Status and sign transactions", + "this-device": "This device", + "this-device-desc": "Your key will be encrypted and securely stored", + "keycard-desc": "Android only. You will need to get a Keycard first", + "about-names-title": "About the names", + "about-names-content": "Your identity is secure and private by design. You get a locally generated cryptographic keypair. The name and image are a readable version of this. They are unique. Nobody can pretend to be you. Nobody sees your name unless you provide it.", + "about-key-storage-title": "About key storage", + "about-key-storage-content": "Status will never access your private key. Be sure to backup your Seed phrase. If you lose your phone it is the only way to access your keys.", + "encrypt-with-password": "Encrypt with password", + "maybe-later": "Maybe later", "not-implemented": "!not implemented", "new-contact": "New contact", "datetime-second": { @@ -249,7 +284,7 @@ "group-chat-admin-added": "*{{member}}* has been made admin", "group-chat-no-contacts": "You don't have any contacts yet.\nInvite your friends to start chatting", "agree-by-continuing": "By continuing you agree\n to our ", - "wallet-advanced": "Advanced", + "advanced": "Advanced", "currency-display-name-sos": "Somalia Shilling", "currency-display-name-zar": "South Africa Rand", "offline-messaging": "Mailserver", @@ -649,7 +684,7 @@ "wallet-asset": "Asset", "close-app-content": "The app will stop and close. When you reopen it, the selected network will be used", "logout-app-content": "The account will be logged out. When you log in again, the selected network will be used", - "password-description": "You'll need this password to open the app and confirm transactions.", + "password-description": "At least 6 characters. You'll need this password to open Status and confirm transactions", "currency-display-name-afn": "Afghanistan Afghani", "word-n-description": "In order to check if you have backed up your recovery phrase correctly, enter the word #{{number}} above.", "topic-name-error": "Use only lowercase letters (a to z), numbers & dashes (-). Do not use contact codes", @@ -704,6 +739,7 @@ "transactions-history": "Transaction history", "fetching-messages": "Fetching messages... ({{requests-left}} requests left)", "password_error1": "Passwords don't match.", + "passcode-error": "Passcodes don't match.", "your-contact-code": "Granting access authorizes this DApp to retrieve your contact code", "password-placeholder": "At least 6 characters", "clear-history-action": "Clear", @@ -917,6 +953,7 @@ "view-my-wallet": "View my wallet", "share-my-profile": "Share my profile", "get-started": "Get started", + "access-key": "Access key", "tribute-to-talk": "Tribute to talk", "tribute-to-talk-desc": "Monetize your attention by requiring SNT for new people to start a chat", "tribute-to-talk-set-snt-amount": "Set the amount of SNT required for new people to start a chat", diff --git a/translations/es_419.json b/translations/es_419.json index 46115c79683f..757a996dcbb3 100644 --- a/translations/es_419.json +++ b/translations/es_419.json @@ -647,7 +647,7 @@ "wallet": "Billetera", "wallet-add-asset": "Agregar activo", "wallet-address-from-clipboard": "Usar la dirección desde el portapapeles", - "wallet-advanced": "Avanzado", + "advanced": "Avanzado", "wallet-asset": "Activo", "wallet-assets": "Activos", "wallet-backup-recovery-description": "Esto te ayudará a mantener tus activos seguros", diff --git a/translations/fa.json b/translations/fa.json index 0c5fe9d7ff7e..f0e35b215c86 100644 --- a/translations/fa.json +++ b/translations/fa.json @@ -652,7 +652,7 @@ "wallet": "کیف پول", "wallet-add-asset": "افزودن دارایی جدید", "wallet-address-from-clipboard": "از آدرسی که در کلیپ بورد ذخیره کردم استفاده کن", - "wallet-advanced": "پیشرفته", + "advanced": "پیشرفته", "wallet-asset": "دارایی", "wallet-assets": "دارایی ها", "wallet-backup-recovery-description": "این به شما کمک می کند که دارایی خود را امن نگه دارید", diff --git a/translations/ja.json b/translations/ja.json index 755ceee1b040..d4e3185c3640 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -7,7 +7,7 @@ "amount": "金額", "open": "開く", "close-app-title": "警告!", - "wallet-advanced": "高度な", + "advanced": "高度な", "members-active": { "one": "1人がアクティブ", "other": "{{count}}人がアクティブ", diff --git a/translations/ko.json b/translations/ko.json index df9648a56209..6498d17dbfc5 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -988,7 +988,7 @@ "wallet": "지갑", "wallet-add-asset": "자산 추가", "wallet-address-from-clipboard": "클립보드에서 가져오기", - "wallet-advanced": "고급 설정", + "advanced": "고급 설정", "wallet-asset": "자산", "wallet-assets": "자산", "wallet-backup-recovery-description": "자산을 안전하게 보호하세요", diff --git a/translations/ms.json b/translations/ms.json index 714f4a4ff045..2f8e4a5e19ba 100644 --- a/translations/ms.json +++ b/translations/ms.json @@ -701,7 +701,7 @@ "wallet": "Dompet", "wallet-add-asset": "Tambah aset", "wallet-address-from-clipboard": "Gunakan Alamat Daripada Papan Klip", - "wallet-advanced": "Lanjutan", + "advanced": "Lanjutan", "wallet-asset": "Aset", "wallet-assets": "Aset", "wallet-backup-recovery-description": "Ini akan membantu anda memastikan aset anda selamat", diff --git a/translations/ne.json b/translations/ne.json index cb04497f694b..88ddee18eaeb 100644 --- a/translations/ne.json +++ b/translations/ne.json @@ -672,7 +672,7 @@ "wallet": "वालेट", "wallet-add-asset": "सम्पत्ति थप्नुहोस्", "wallet-address-from-clipboard": "Gunakan Alamat Daripada Papan Klip", - "wallet-advanced": "Lanjutan", + "advanced": "Lanjutan", "wallet-asset": "Aset", "wallet-assets": "Aset", "wallet-backup-recovery-description": "यसले तपाईंको सम्पत्ती सुरक्षित राख्न तपाईंलाई सहयोग गर्नेछ", diff --git a/translations/pl.json b/translations/pl.json index dd77d755e164..461e1394fd94 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -631,7 +631,7 @@ "wallet": "Portfel", "wallet-add-asset": "Dodaj aktywo", "wallet-address-from-clipboard": "Użyj adresu ze schowka", - "wallet-advanced": "Zaawansowane", + "advanced": "Zaawansowane", "wallet-asset": "Aktywo", "wallet-assets": "Aktywa", "wallet-backup-recovery-description": "Pomoże Ci to zachować bezpieczeństwo Twoich zasobów", diff --git a/translations/ru.json b/translations/ru.json index c07f82edd9eb..348a7cc304d1 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -669,7 +669,7 @@ "wallet": "Кошелек", "wallet-add-asset": "Добавить актив", "wallet-address-from-clipboard": "Использовать Адрес Из Буфера Обмена", - "wallet-advanced": "Дополнительные параметры", + "advanced": "Дополнительные параметры", "wallet-asset": "Актив", "wallet-assets": "Активы", "wallet-backup-recovery-description": "Это поможет сохранить Ваши активы в безопасности", diff --git a/translations/zh_Hans_CN.json b/translations/zh_Hans_CN.json index 3c825054293a..2609d3e83f63 100644 --- a/translations/zh_Hans_CN.json +++ b/translations/zh_Hans_CN.json @@ -697,7 +697,7 @@ "wallet": "钱包", "wallet-add-asset": "添加资产", "wallet-address-from-clipboard": "使用剪贴板中的地址", - "wallet-advanced": "高级", + "advanced": "高级", "wallet-asset": "资产", "wallet-assets": "资产", "wallet-backup-recovery-description": "这有助于您保护资产安全",