Onboarding setup wizard
New onboarding e2e tests updates New onboarding e2e fix 2 Signed-off-by: Vitaliy Vlasov <siphiuel@gmail.com>
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 675 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 481 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 793 B |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 1.4 KiB |
|
@ -187,6 +187,7 @@ var TopLevel = {
|
|||
"hide" : function () {},
|
||||
"i18n" : function () {},
|
||||
"ignoreWarnings" : function () {},
|
||||
"importOnboardingAccount": function () {},
|
||||
"in" : function () {},
|
||||
"index" : function () {},
|
||||
"indexOf" : function () {},
|
||||
|
@ -465,6 +466,7 @@ var TopLevel = {
|
|||
"StackActions" : function () {},
|
||||
"start" : function () {},
|
||||
"startNode" : function () {},
|
||||
"startOnboarding": function () {},
|
||||
"state" : function () {},
|
||||
"Status" : function () {},
|
||||
"status" : function () {},
|
||||
|
@ -518,6 +520,7 @@ var TopLevel = {
|
|||
"verifyPin" : function () {},
|
||||
"Version" : function () {},
|
||||
"version" : function () {},
|
||||
"vibrate" : function () {},
|
||||
"View" : function () {},
|
||||
"warn" : function () {},
|
||||
"Web3" : function () {},
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.3 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 10 KiB |
|
@ -660,6 +660,44 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
|||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void startOnboarding(final Integer n, final Integer mnemonicLength, final Callback callback) {
|
||||
Log.d(TAG, "startOnboarding");
|
||||
if (!checkAvailability()) {
|
||||
callback.invoke(false);
|
||||
return;
|
||||
}
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String res = Statusgo.startOnboarding(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();
|
||||
}
|
||||
|
|
|
@ -335,6 +335,29 @@ RCT_EXPORT_METHOD(recoverAccount:(NSString *)passphrase
|
|||
callback(@[result]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// startOnboarding
|
||||
RCT_EXPORT_METHOD(startOnboarding:(NSInteger)n
|
||||
password:(NSInteger)mnemonicLength
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"StartOnboarding() method called");
|
||||
#endif
|
||||
NSString *result = StatusgoStartOnboarding(n, mnemonicLength);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// importOnboardingAccount
|
||||
RCT_EXPORT_METHOD(importOnboardingAccount:(NSString *)id
|
||||
password:(NSString *)password
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"ImportOnboardingAccount() method called");
|
||||
#endif
|
||||
NSString *result = StatusgoImportOnboardingAccount(id, password);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////// login
|
||||
RCT_EXPORT_METHOD(login:(NSString *)address
|
||||
password:(NSString *)password
|
||||
|
@ -449,6 +472,7 @@ RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) {
|
|||
RCT_EXPORT_METHOD(clearCookies) {
|
||||
NSHTTPCookie *cookie;
|
||||
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
||||
|
||||
for (cookie in [storage cookies]) {
|
||||
[storage deleteCookie:cookie];
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 55 KiB |
|
@ -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,26 +27,57 @@
|
|||
(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}]
|
||||
(fx/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(update :accounts/create assoc
|
||||
:step :account-creating
|
||||
:error nil)
|
||||
(assoc :node/on-ready :create-account
|
||||
:accounts/new-installation-id (random-guid-generator)))}
|
||||
(node/initialize nil)))
|
||||
[{:keys [db] :as cofx}]
|
||||
(if (:intro-wizard db)
|
||||
(fx/merge
|
||||
cofx
|
||||
{:accounts.create/create-account {:id (get-in db [:intro-wizard :selected-id])
|
||||
:password (or (get-in db [:accounts/create :password])
|
||||
(get-in db [:intro-wizard :key-code]))}})
|
||||
(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)))}
|
||||
(node/initialize nil))))
|
||||
|
||||
(fx/defn add-account
|
||||
"Takes db and new account, creates map of effects describing adding account to database and realm"
|
||||
|
@ -59,44 +91,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 +139,179 @@
|
|||
(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
|
||||
:weak-password? true
|
||||
:encrypt-with-password? true}
|
||||
:accounts/new-installation-id (random/guid))}
|
||||
(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)
|
||||
(update :intro-wizard assoc :weak-password? true :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}]
|
||||
(fx/merge
|
||||
{:db (-> db
|
||||
(assoc-in [:intro-wizard :generating-keys?] true)
|
||||
(assoc :node/on-ready :start-onboarding))}
|
||||
(node/initialize nil)))
|
||||
|
||||
(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}]
|
||||
(let [key-code (get-in db [:intro-wizard :key-code])]
|
||||
{:db (update db :intro-wizard
|
||||
assoc :stored-key-code 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))
|
||||
(when (:intro-wizard db)
|
||||
(intro-step-forward {}))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:intro-wizard/start-onboarding
|
||||
(fn [{:keys [n mnemonic-length]}]
|
||||
(status/start-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} new-key-code]
|
||||
(let [encrypt-with-password? (get-in db [:intro-wizard :encrypt-with-password?])]
|
||||
{:db (update db :intro-wizard assoc :key-code new-key-code
|
||||
:confirm-failure? false
|
||||
:weak-password? (< (count new-key-code) 6))}))
|
||||
|
||||
;;;; COFX
|
||||
|
||||
(re-frame/reg-cofx
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
(defn recover-account [passphrase password callback]
|
||||
(native-module/recover-account passphrase password callback))
|
||||
|
||||
(defn start-onboarding [n mnemonic-length callback]
|
||||
(native-module/start-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))
|
||||
|
||||
|
|
|
@ -61,6 +61,14 @@
|
|||
(when (and @node-started (status))
|
||||
(.recoverAccount (status) passphrase password on-result)))
|
||||
|
||||
(defn start-onboarding [n mnemonic-length on-result]
|
||||
(when (and @node-started (status))
|
||||
(.startOnboarding (status) n mnemonic-length on-result)))
|
||||
|
||||
(defn import-onboarding-account [id password on-result]
|
||||
(when (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)))
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -37,14 +37,17 @@
|
|||
[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)]
|
||||
{:accounts.recover/recover-account
|
||||
[(security/mask-data passphrase) password]}))
|
||||
:create-keycard-account
|
||||
(hardwallet/create-keycard-account)))))
|
||||
(hardwallet/create-keycard-account)
|
||||
:start-onboarding
|
||||
(fn []
|
||||
{:intro-wizard/start-onboarding {:n 5 :mnemonic-length 12}})))))
|
||||
|
||||
(fx/defn status-node-stopped
|
||||
[{db :db}]
|
||||
|
|
|
@ -178,6 +178,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -4,30 +4,102 @@
|
|||
|
||||
(def intro-view
|
||||
{:flex 1
|
||||
:padding-horizontal 30})
|
||||
:justify-content :flex-end
|
||||
:padding-horizontal 30
|
||||
:margin-bottom 12})
|
||||
|
||||
(def intro-logo-container
|
||||
{:flex 1
|
||||
:align-items :center
|
||||
{:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(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)))}))
|
||||
|
||||
(defn dot [color selected?]
|
||||
{:background-color (if selected?
|
||||
color
|
||||
(colors/alpha color 0.2))
|
||||
:width 6
|
||||
:height 6
|
||||
:border-radius 3})
|
||||
|
||||
(def welcome-image-container
|
||||
{:align-items :center
|
||||
:margin-top 42})
|
||||
|
||||
(def wizard-title
|
||||
{:typography :header
|
||||
:text-align :center
|
||||
: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})
|
||||
|
||||
(defstyle intro-text
|
||||
{:text-align :center
|
||||
:font-weight "700"
|
||||
:font-size 24})
|
||||
|
||||
(def intro-text-description
|
||||
{:margin-top 8
|
||||
:margin-bottom 16
|
||||
:text-align :center
|
||||
:color colors/gray})
|
||||
(defn password-text-input [width]
|
||||
{:typography :header
|
||||
:width width})
|
||||
|
||||
(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})
|
||||
|
|
|
@ -2,28 +2,297 @@
|
|||
(: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? view-width]
|
||||
(let [horizontal-margin 16]
|
||||
[react/view {:style {:flex 1
|
||||
:justify-content :space-between
|
||||
:align-items :center :margin-horizontal horizontal-margin}}
|
||||
[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 (- view-width (* 2 horizontal-margin)))
|
||||
:on-change-text #(re-frame/dispatch [:intro-wizard/code-symbol-pressed %])}]]
|
||||
[react/text {:style (assoc styles/wizard-text :margin-bottom 16)} (i18n/label :t/password-description)]]))
|
||||
|
||||
(defn create-code [{:keys [confirm-failure?] :as wizard-state} view-width]
|
||||
[password-container confirm-failure? view-width])
|
||||
|
||||
(defn confirm-code [{:keys [confirm-failure?] :as wizard-state} view-width]
|
||||
[password-container confirm-failure? view-width])
|
||||
|
||||
(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? weak-password? 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])
|
||||
:disabled? (and (= step :create-code) weak-password?)
|
||||
: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 view-width :width} [: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 view-width]
|
||||
:confirm-code [confirm-code wizard-state view-width]
|
||||
:enable-fingerprint [enable-fingerprint]
|
||||
:enable-notifications [enable-notifications]
|
||||
nil nil)
|
||||
[bottom-bar wizard-state]]]))
|
||||
|
|
|
@ -253,7 +253,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])]))
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
:recover
|
||||
:accounts
|
||||
:intro
|
||||
:intro-wizard
|
||||
:hardwallet-authentication-method
|
||||
:hardwallet-connect
|
||||
:enter-pin-login
|
||||
|
@ -52,6 +53,7 @@
|
|||
(-> (login-stack :intro)
|
||||
(update :screens conj
|
||||
:intro
|
||||
:intro-wizard
|
||||
:keycard-onboarding-intro
|
||||
:keycard-onboarding-start
|
||||
:keycard-onboarding-puk-code
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
:recover recover/recover
|
||||
:accounts accounts/accounts
|
||||
:intro intro/intro
|
||||
:intro-wizard intro/wizard
|
||||
:hardwallet-authentication-method hardwallet.authentication/hardwallet-authentication-method
|
||||
:hardwallet-connect hardwallet.connect/hardwallet-connect
|
||||
:hardwallet-connect-settings hardwallet.connect/hardwallet-connect
|
||||
|
|
|
@ -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]
|
||||
|
@ -46,6 +47,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)
|
||||
|
||||
|
|
|
@ -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]}]
|
||||
|
|
|
@ -41,7 +41,18 @@ class TestCreateAccount(SingleDeviceTestCase):
|
|||
if sign_in.ok_button.is_element_displayed():
|
||||
sign_in.ok_button.click()
|
||||
sign_in.other_accounts_button.click()
|
||||
sign_in.create_user()
|
||||
sign_in.create_account_button.click()
|
||||
sign_in.password_input.set_value(common_password)
|
||||
sign_in.next_button.click()
|
||||
sign_in.confirm_password_input.set_value(common_password)
|
||||
sign_in.next_button.click()
|
||||
|
||||
sign_in.element_by_text_part('Display name').wait_for_element(60)
|
||||
username = 'user_%s' % get_current_time()
|
||||
sign_in.name_input.set_value(username)
|
||||
|
||||
sign_in.next_button.click()
|
||||
sign_in.get_started_button.click()
|
||||
if sign_in.get_public_key() == public_key:
|
||||
pytest.fail('New account was not created')
|
||||
|
||||
|
|
|
@ -13,12 +13,13 @@ class TestSignIn(SingleDeviceTestCase):
|
|||
@marks.critical
|
||||
def test_login_with_new_account(self):
|
||||
sign_in = SignInView(self.driver)
|
||||
username = 'test_user'
|
||||
sign_in.create_user(username=username)
|
||||
sign_in.create_user()
|
||||
profile = sign_in.profile_button.click()
|
||||
default_username = profile.default_username_text.text
|
||||
self.driver.close_app()
|
||||
self.driver.launch_app()
|
||||
sign_in.accept_agreements()
|
||||
if not sign_in.element_by_text(username).is_element_displayed():
|
||||
if not sign_in.element_by_text(default_username).is_element_displayed():
|
||||
self.errors.append('Username is not shown while login')
|
||||
sign_in.sign_in()
|
||||
if not sign_in.home_button.is_element_displayed():
|
||||
|
|
|
@ -230,7 +230,7 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase):
|
|||
username_1 = 'user_%s' % get_current_time()
|
||||
message_before_block_1, message_before_block_2 = "Before block from %s" % device_1.driver.number, "Before block from %s" % device_2.driver.number
|
||||
message_after_block_2 = "After block from %s" % device_2.driver.number
|
||||
home_1, home_2 = device_1.create_user(username=username_1), device_2.recover_access(basic_user['passphrase'])
|
||||
home_1, home_2 = device_1.create_user(), device_2.recover_access(basic_user['passphrase'])
|
||||
|
||||
# device 1, device 2: join to public chat and send several messages
|
||||
chat_name = device_1.get_public_chat_name()
|
||||
|
|
|
@ -15,8 +15,7 @@ class TestPublicChatMultipleDevice(MultipleDeviceTestCase):
|
|||
def test_public_chat_messaging(self):
|
||||
self.create_drivers(2)
|
||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
||||
username_1, username_2 = 'user_1', 'user_2'
|
||||
home_1, home_2 = device_1.create_user(username=username_1), device_2.create_user(username=username_2)
|
||||
home_1, home_2 = device_1.create_user(), device_2.create_user()
|
||||
profile_1 = home_1.profile_button.click()
|
||||
default_username_1 = profile_1.default_username_text.text
|
||||
profile_1.home_button.click()
|
||||
|
|
|
@ -6,20 +6,32 @@ from views.base_view import BaseView
|
|||
|
||||
|
||||
class AccountButton(BaseButton):
|
||||
|
||||
def __init__(self, driver):
|
||||
super(AccountButton, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//*[contains(@text,'0x')]")
|
||||
|
||||
|
||||
class PasswordInput(BaseEditBox):
|
||||
|
||||
def __init__(self, driver):
|
||||
super(PasswordInput, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//android.widget.TextView[@text='Password']"
|
||||
"/following-sibling::android.view.ViewGroup/android.widget.EditText")
|
||||
|
||||
|
||||
class CreatePasswordInput(BaseEditBox):
|
||||
def __init__(self, driver):
|
||||
super(CreatePasswordInput, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//android.widget.TextView[@text='Create a password']"
|
||||
"/following-sibling::android.widget.EditText")
|
||||
|
||||
|
||||
class ConfirmYourPasswordInput(BaseEditBox):
|
||||
def __init__(self, driver):
|
||||
super(ConfirmYourPasswordInput, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//android.widget.TextView[@text='Confirm your password']"
|
||||
"/following-sibling::android.widget.EditText")
|
||||
|
||||
|
||||
class SignInButton(BaseButton):
|
||||
|
||||
def __init__(self, driver):
|
||||
|
@ -48,12 +60,30 @@ class CreateAccountButton(BaseButton):
|
|||
self.locator = self.Locator.xpath_selector("//*[@text='Create account' or @text='Create new account']")
|
||||
|
||||
|
||||
class GenerateKeyButton(BaseButton):
|
||||
def __init__(self, driver):
|
||||
super(GenerateKeyButton, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//*[@text='Generate a key']")
|
||||
|
||||
|
||||
class IHaveAccountButton(RecoverAccessButton):
|
||||
def __init__(self, driver):
|
||||
super(IHaveAccountButton, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//*[@text='I already have an account']")
|
||||
|
||||
|
||||
class AccessKeyButton(RecoverAccessButton):
|
||||
def __init__(self, driver):
|
||||
super(AccessKeyButton, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//*[@text='Access key']")
|
||||
|
||||
|
||||
class MaybeLaterButton(BaseButton):
|
||||
def __init__(self, driver):
|
||||
super(MaybeLaterButton, self).__init__(driver)
|
||||
self.locator = self.Locator.xpath_selector("//*[@text='Maybe later']")
|
||||
|
||||
|
||||
class AddExistingAccountButton(RecoverAccessButton):
|
||||
def __init__(self, driver):
|
||||
super(AddExistingAccountButton, self).__init__(driver)
|
||||
|
@ -106,25 +136,35 @@ class SignInView(BaseView):
|
|||
# new design
|
||||
self.create_account_button = CreateAccountButton(self.driver)
|
||||
self.i_have_account_button = IHaveAccountButton(self.driver)
|
||||
self.access_key_button = AccessKeyButton(self.driver)
|
||||
self.generate_key_button = GenerateKeyButton(self.driver)
|
||||
self.add_existing_account_button = AddExistingAccountButton(self.driver)
|
||||
self.confirm_password_input = ConfirmPasswordInput(self.driver)
|
||||
self.create_password_input = CreatePasswordInput(self.driver)
|
||||
self.confirm_your_password_input = ConfirmYourPasswordInput(self.driver)
|
||||
self.maybe_later_button = MaybeLaterButton(self.driver)
|
||||
self.name_input = NameInput(self.driver)
|
||||
self.other_accounts_button = OtherAccountsButton(self.driver)
|
||||
self.privacy_policy_link = PrivacyPolicyLink(self.driver)
|
||||
|
||||
def create_user(self, username: str = '', password=common_password):
|
||||
self.create_account_button.click()
|
||||
self.password_input.set_value(password)
|
||||
self.next_button.click()
|
||||
self.confirm_password_input.set_value(password)
|
||||
self.next_button.click()
|
||||
|
||||
self.element_by_text_part('Display name').wait_for_element(60)
|
||||
username = username if username else 'user_%s' % get_current_time()
|
||||
self.name_input.set_value(username)
|
||||
|
||||
self.next_button.click()
|
||||
def create_user(self, password=common_password):
|
||||
self.get_started_button.click()
|
||||
self.generate_key_button.click()
|
||||
self.next_button.click()
|
||||
self.next_button.click()
|
||||
self.create_password_input.set_value(password)
|
||||
self.next_button.click()
|
||||
self.confirm_your_password_input.set_value(password)
|
||||
self.next_button.click()
|
||||
self.maybe_later_button.click()
|
||||
self.maybe_later_button.click()
|
||||
|
||||
# self.element_by_text_part('Display name').wait_for_element(60)
|
||||
# username = username if username else 'user_%s' % get_current_time()
|
||||
# self.name_input.set_value(username)
|
||||
|
||||
# self.next_button.click()
|
||||
# self.get_started_button.click()
|
||||
return self.get_home_view()
|
||||
|
||||
def recover_access(self, passphrase: str, password: str = common_password):
|
||||
|
@ -132,7 +172,7 @@ class SignInView(BaseView):
|
|||
self.other_accounts_button.click()
|
||||
recover_access_view = self.add_existing_account_button.click()
|
||||
else:
|
||||
recover_access_view = self.i_have_account_button.click()
|
||||
recover_access_view = self.access_key_button.click()
|
||||
recover_access_view.passphrase_input.click()
|
||||
recover_access_view.passphrase_input.set_value(passphrase)
|
||||
recover_access_view.password_input.click()
|
||||
|
|
|
@ -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 :weak-password? true}))))
|
||||
|
||||
(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 :weak-password? true})))))
|
||||
|
||||
(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 (= (select-keys (:db result) [:intro-wizard :node/on-ready]) {:intro-wizard {:step :generate-key :generating-keys? true}
|
||||
:node/on-ready :start-onboarding}))))
|
||||
|
||||
(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)))))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"amount": "Ποσό",
|
||||
"open": "Άνοιγμα",
|
||||
"close-app-title": "Προειδοποίηση!",
|
||||
"wallet-advanced": "Προχωρημένη",
|
||||
"advanced": "Προχωρημένη",
|
||||
"members-active": {
|
||||
"one": "1 μέλος",
|
||||
"other": "{{count}} μέλη",
|
||||
|
|
|
@ -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 enabling 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",
|
||||
|
@ -919,6 +955,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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -652,7 +652,7 @@
|
|||
"wallet": "کیف پول",
|
||||
"wallet-add-asset": "افزودن دارایی جدید",
|
||||
"wallet-address-from-clipboard": "از آدرسی که در کلیپ بورد ذخیره کردم استفاده کن",
|
||||
"wallet-advanced": "پیشرفته",
|
||||
"advanced": "پیشرفته",
|
||||
"wallet-asset": "دارایی",
|
||||
"wallet-assets": "دارایی ها",
|
||||
"wallet-backup-recovery-description": "این به شما کمک می کند که دارایی خود را امن نگه دارید",
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"amount": "金額",
|
||||
"open": "開く",
|
||||
"close-app-title": "警告!",
|
||||
"wallet-advanced": "高度な",
|
||||
"advanced": "高度な",
|
||||
"members-active": {
|
||||
"one": "1人がアクティブ",
|
||||
"other": "{{count}}人がアクティブ",
|
||||
|
|
|
@ -988,7 +988,7 @@
|
|||
"wallet": "지갑",
|
||||
"wallet-add-asset": "자산 추가",
|
||||
"wallet-address-from-clipboard": "클립보드에서 가져오기",
|
||||
"wallet-advanced": "고급 설정",
|
||||
"advanced": "고급 설정",
|
||||
"wallet-asset": "자산",
|
||||
"wallet-assets": "자산",
|
||||
"wallet-backup-recovery-description": "자산을 안전하게 보호하세요",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": "यसले तपाईंको सम्पत्ती सुरक्षित राख्न तपाईंलाई सहयोग गर्नेछ",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -669,7 +669,7 @@
|
|||
"wallet": "Кошелек",
|
||||
"wallet-add-asset": "Добавить актив",
|
||||
"wallet-address-from-clipboard": "Использовать Адрес Из Буфера Обмена",
|
||||
"wallet-advanced": "Дополнительные параметры",
|
||||
"advanced": "Дополнительные параметры",
|
||||
"wallet-asset": "Актив",
|
||||
"wallet-assets": "Активы",
|
||||
"wallet-backup-recovery-description": "Это поможет сохранить Ваши активы в безопасности",
|
||||
|
|
|
@ -697,7 +697,7 @@
|
|||
"wallet": "钱包",
|
||||
"wallet-add-asset": "添加资产",
|
||||
"wallet-address-from-clipboard": "使用剪贴板中的地址",
|
||||
"wallet-advanced": "高级",
|
||||
"advanced": "高级",
|
||||
"wallet-asset": "资产",
|
||||
"wallet-assets": "资产",
|
||||
"wallet-backup-recovery-description": "这有助于您保护资产安全",
|
||||
|
|