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 () {},
|
"hide" : function () {},
|
||||||
"i18n" : function () {},
|
"i18n" : function () {},
|
||||||
"ignoreWarnings" : function () {},
|
"ignoreWarnings" : function () {},
|
||||||
|
"importOnboardingAccount": function () {},
|
||||||
"in" : function () {},
|
"in" : function () {},
|
||||||
"index" : function () {},
|
"index" : function () {},
|
||||||
"indexOf" : function () {},
|
"indexOf" : function () {},
|
||||||
|
@ -465,6 +466,7 @@ var TopLevel = {
|
||||||
"StackActions" : function () {},
|
"StackActions" : function () {},
|
||||||
"start" : function () {},
|
"start" : function () {},
|
||||||
"startNode" : function () {},
|
"startNode" : function () {},
|
||||||
|
"startOnboarding": function () {},
|
||||||
"state" : function () {},
|
"state" : function () {},
|
||||||
"Status" : function () {},
|
"Status" : function () {},
|
||||||
"status" : function () {},
|
"status" : function () {},
|
||||||
|
@ -518,6 +520,7 @@ var TopLevel = {
|
||||||
"verifyPin" : function () {},
|
"verifyPin" : function () {},
|
||||||
"Version" : function () {},
|
"Version" : function () {},
|
||||||
"version" : function () {},
|
"version" : function () {},
|
||||||
|
"vibrate" : function () {},
|
||||||
"View" : function () {},
|
"View" : function () {},
|
||||||
"warn" : function () {},
|
"warn" : function () {},
|
||||||
"Web3" : 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);
|
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() {
|
private String createIdentifier() {
|
||||||
return UUID.randomUUID().toString();
|
return UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,6 +335,29 @@ RCT_EXPORT_METHOD(recoverAccount:(NSString *)passphrase
|
||||||
callback(@[result]);
|
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
|
//////////////////////////////////////////////////////////////////// login
|
||||||
RCT_EXPORT_METHOD(login:(NSString *)address
|
RCT_EXPORT_METHOD(login:(NSString *)address
|
||||||
password:(NSString *)password
|
password:(NSString *)password
|
||||||
|
@ -449,6 +472,7 @@ RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) {
|
||||||
RCT_EXPORT_METHOD(clearCookies) {
|
RCT_EXPORT_METHOD(clearCookies) {
|
||||||
NSHTTPCookie *cookie;
|
NSHTTPCookie *cookie;
|
||||||
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
||||||
|
|
||||||
for (cookie in [storage cookies]) {
|
for (cookie in [storage cookies]) {
|
||||||
[storage deleteCookie:cookie];
|
[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.identicon :as identicon]
|
||||||
[status-im.utils.signing-phrase.core :as signing-phrase]
|
[status-im.utils.signing-phrase.core :as signing-phrase]
|
||||||
[status-im.utils.types :as types]
|
[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.utils.fx :as fx]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
[status-im.ui.screens.mobile-network-settings.events :as mobile-network]
|
[status-im.ui.screens.mobile-network-settings.events :as mobile-network]
|
||||||
|
@ -26,26 +27,57 @@
|
||||||
(defn get-signing-phrase [cofx]
|
(defn get-signing-phrase [cofx]
|
||||||
(assoc cofx :signing-phrase (signing-phrase/generate)))
|
(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]
|
(defn get-status [cofx]
|
||||||
(assoc cofx :status (rand-nth statuses/data)))
|
(assoc cofx :status (rand-nth statuses/data)))
|
||||||
|
|
||||||
(defn create-account! [password]
|
(defn create-account! [{:keys [id password]}]
|
||||||
(status/create-account
|
(if id
|
||||||
password
|
(status/import-onboarding-account
|
||||||
#(re-frame/dispatch [:accounts.create.callback/create-account-success (types/json->clj %) password])))
|
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
|
;;;; Handlers
|
||||||
(defn create-account
|
(defn create-account
|
||||||
[{:keys [db random-guid-generator] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge
|
(if (:intro-wizard db)
|
||||||
cofx
|
(fx/merge
|
||||||
{:db (-> db
|
cofx
|
||||||
(update :accounts/create assoc
|
{:accounts.create/create-account {:id (get-in db [:intro-wizard :selected-id])
|
||||||
:step :account-creating
|
:password (or (get-in db [:accounts/create :password])
|
||||||
:error nil)
|
(get-in db [:intro-wizard :key-code]))}})
|
||||||
(assoc :node/on-ready :create-account
|
(fx/merge
|
||||||
:accounts/new-installation-id (random-guid-generator)))}
|
cofx
|
||||||
(node/initialize nil)))
|
{: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
|
(fx/defn add-account
|
||||||
"Takes db and new account, creates map of effects describing adding account to database and realm"
|
"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)
|
{:db (assoc-in db [:accounts/accounts address] enriched-account)
|
||||||
:data-store/base-tx [(accounts-store/save-account-tx 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}]
|
(defn reset-account-creation [{db :db}]
|
||||||
{:db (update db :accounts/create assoc
|
{:db (update db :accounts/create assoc
|
||||||
:step :enter-password
|
:step :enter-password
|
||||||
|
@ -145,6 +139,179 @@
|
||||||
(dissoc :password :password-confirm :name :error)))}
|
(dissoc :password :password-confirm :name :error)))}
|
||||||
(navigation/navigate-to-cofx :create-account nil)))
|
(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
|
;;;; COFX
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
(re-frame/reg-cofx
|
||||||
|
|
|
@ -166,6 +166,7 @@
|
||||||
:keys [accounts/accounts accounts/create networks/networks network
|
:keys [accounts/accounts accounts/create networks/networks network
|
||||||
network-status peers-count peers-summary view-id navigation-stack
|
network-status peers-count peers-summary view-id navigation-stack
|
||||||
mailserver/mailservers
|
mailserver/mailservers
|
||||||
|
intro-wizard
|
||||||
desktop/desktop hardwallet custom-fleets supported-biometric-auth
|
desktop/desktop hardwallet custom-fleets supported-biometric-auth
|
||||||
device-UUID semaphores accounts/login]
|
device-UUID semaphores accounts/login]
|
||||||
:node/keys [status on-ready]
|
:node/keys [status on-ready]
|
||||||
|
@ -177,6 +178,7 @@
|
||||||
:view-id view-id
|
:view-id view-id
|
||||||
:navigation-stack navigation-stack
|
:navigation-stack navigation-stack
|
||||||
:node/status status
|
:node/status status
|
||||||
|
:intro-wizard intro-wizard
|
||||||
:node/on-ready on-ready
|
:node/on-ready on-ready
|
||||||
:accounts/create create
|
:accounts/create create
|
||||||
:desktop/desktop (merge desktop (:desktop/desktop app-db))
|
:desktop/desktop (merge desktop (:desktop/desktop app-db))
|
||||||
|
@ -201,20 +203,19 @@
|
||||||
(= view-id :create-account)
|
(= view-id :create-account)
|
||||||
(assoc-in [:accounts/create :step] :enter-name))}))
|
(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
|
(fx/merge cofx
|
||||||
(cond->
|
(when-not (:intro-wizard db)
|
||||||
{:notifications/request-notifications-permissions nil}
|
(cond-> {:notifications/request-notifications-permissions nil}
|
||||||
|
platform/ios?
|
||||||
platform/ios?
|
;; on ios navigation state might be not initialized yet when
|
||||||
;; on ios navigation state might be not initialized yet when
|
;; navigate-to call happens.
|
||||||
;; navigate-to call happens.
|
;; That's why it should be delayed a bit.
|
||||||
;; That's why it should be delayed a bit.
|
;; TODO(rasom): revisit this later and find better solution
|
||||||
;; TODO(rasom): revisit this later and find better solution
|
(assoc :dispatch-later
|
||||||
(assoc :dispatch-later
|
[{:ms 1
|
||||||
[{:ms 1
|
:dispatch [:navigate-to :home]}])))
|
||||||
:dispatch [:navigate-to :home]}]))
|
(when-not (or (:intro-wizard db) platform/ios?)
|
||||||
(when-not platform/ios?
|
|
||||||
(navigation/navigate-to-cofx :home nil))
|
(navigation/navigate-to-cofx :home nil))
|
||||||
(notifications/process-stored-event address stored-pns)
|
(notifications/process-stored-event address stored-pns)
|
||||||
(when platform/desktop?
|
(when platform/desktop?
|
||||||
|
|
|
@ -22,6 +22,12 @@
|
||||||
(defn recover-account [passphrase password callback]
|
(defn recover-account [passphrase password callback]
|
||||||
(native-module/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]
|
(defn login [address password callback]
|
||||||
(native-module/login address password callback))
|
(native-module/login address password callback))
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,14 @@
|
||||||
(when (and @node-started (status))
|
(when (and @node-started (status))
|
||||||
(.recoverAccount (status) passphrase password on-result)))
|
(.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]
|
(defn login [address password on-result]
|
||||||
(when (and @node-started (status))
|
(when (and @node-started (status))
|
||||||
(.login (status) address password on-result)))
|
(.login (status) address password on-result)))
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
:empty-recent (js-require/js-require "./resources/images/ui/empty-recent.png")
|
:empty-recent (js-require/js-require "./resources/images/ui/empty-recent.png")
|
||||||
:analytics-image (js-require/js-require "./resources/images/ui/analytics-image.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")
|
: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")
|
:lock (js-require/js-require "./resources/images/ui/lock.png")
|
||||||
:tribute-to-talk (js-require/js-require "./resources/images/ui/tribute-to-talk.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")
|
:wallet-welcome (js-require/js-require "./resources/images/ui/wallet-welcome.png")
|
||||||
|
|
|
@ -37,14 +37,17 @@
|
||||||
[address password (:realm-error db)]}))
|
[address password (:realm-error db)]}))
|
||||||
:create-account
|
:create-account
|
||||||
(fn [_]
|
(fn [_]
|
||||||
{:accounts.create/create-account (:password create)})
|
{:accounts.create/create-account (select-keys create [:id :password])})
|
||||||
:recover-account
|
:recover-account
|
||||||
(fn [{:keys [db]}]
|
(fn [{:keys [db]}]
|
||||||
(let [{:keys [password passphrase]} (:accounts/recover db)]
|
(let [{:keys [password passphrase]} (:accounts/recover db)]
|
||||||
{:accounts.recover/recover-account
|
{:accounts.recover/recover-account
|
||||||
[(security/mask-data passphrase) password]}))
|
[(security/mask-data passphrase) password]}))
|
||||||
:create-keycard-account
|
: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
|
(fx/defn status-node-stopped
|
||||||
[{db :db}]
|
[{db :db}]
|
||||||
|
|
|
@ -178,6 +178,9 @@
|
||||||
(reg-root-key-sub :signing/sign :signing/sign)
|
(reg-root-key-sub :signing/sign :signing/sign)
|
||||||
(reg-root-key-sub :signing/edit-fee :signing/edit-fee)
|
(reg-root-key-sub :signing/edit-fee :signing/edit-fee)
|
||||||
|
|
||||||
|
;;intro-wizard
|
||||||
|
(reg-root-key-sub :intro-wizard :intro-wizard)
|
||||||
|
|
||||||
;;GENERAL ==============================================================================================================
|
;;GENERAL ==============================================================================================================
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
|
|
|
@ -70,15 +70,17 @@
|
||||||
(assoc style :font-family default-font-family)
|
(assoc style :font-family default-font-family)
|
||||||
(-> style
|
(-> style
|
||||||
(assoc :font-family
|
(assoc :font-family
|
||||||
(str default-font-family "-"
|
(if (= (:font-family style) "monospace")
|
||||||
(case font-weight
|
(if platform/ios? "Menlo-Regular" "monospace")
|
||||||
"400" (when-not (= font-style :italic)
|
(str default-font-family "-"
|
||||||
"Regular")
|
(case font-weight
|
||||||
"500" "Medium"
|
"400" (when-not (= font-style :italic)
|
||||||
"600" "SemiBold"
|
"Regular")
|
||||||
"700" "Bold")
|
"500" "Medium"
|
||||||
(when (= font-style :italic)
|
"600" "SemiBold"
|
||||||
"Italic")))
|
"700" "Bold")
|
||||||
|
(when (= font-style :italic)
|
||||||
|
"Italic"))))
|
||||||
(dissoc :font-weight :font-style)))))
|
(dissoc :font-weight :font-style)))))
|
||||||
|
|
||||||
(defn get-nested-style
|
(defn get-nested-style
|
||||||
|
|
|
@ -17,3 +17,9 @@
|
||||||
|
|
||||||
(def about-title-text
|
(def about-title-text
|
||||||
{:font-size 20})
|
{: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
|
(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]
|
(:require [status-im.ui.components.toolbar.view :as toolbar]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.status-bar.view :as status-bar]
|
[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.ui.screens.about-app.styles :as styles]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.transport.utils :as transport.utils]
|
[status-im.transport.utils :as transport.utils]
|
||||||
|
[status-im.ui.components.colors :as colors]
|
||||||
[status-im.ui.screens.profile.components.views :as profile.components]
|
[status-im.ui.screens.profile.components.views :as profile.components]
|
||||||
[re-frame.core :as re-frame]))
|
[re-frame.core :as re-frame]))
|
||||||
|
|
||||||
|
@ -20,6 +23,19 @@
|
||||||
nil
|
nil
|
||||||
4))
|
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]}]
|
(defn peer-view [{:keys [enode]}]
|
||||||
(let [[enode-id ip-address port] (transport.utils/extract-url-components enode)]
|
(let [[enode-id ip-address port] (transport.utils/extract-url-components enode)]
|
||||||
^{:key enode}
|
^{:key enode}
|
||||||
|
|
|
@ -4,30 +4,102 @@
|
||||||
|
|
||||||
(def intro-view
|
(def intro-view
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:padding-horizontal 30})
|
:justify-content :flex-end
|
||||||
|
:padding-horizontal 30
|
||||||
|
:margin-bottom 12})
|
||||||
|
|
||||||
(def intro-logo-container
|
(def intro-logo-container
|
||||||
{:flex 1
|
{:align-items :center
|
||||||
:align-items :center
|
|
||||||
:justify-content :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
|
(def intro-logo
|
||||||
{:size 111})
|
{:size 111})
|
||||||
|
|
||||||
(defstyle intro-text
|
(defn password-text-input [width]
|
||||||
{:text-align :center
|
{:typography :header
|
||||||
:font-weight "700"
|
:width width})
|
||||||
:font-size 24})
|
|
||||||
|
|
||||||
(def intro-text-description
|
|
||||||
{:margin-top 8
|
|
||||||
:margin-bottom 16
|
|
||||||
:text-align :center
|
|
||||||
:color colors/gray})
|
|
||||||
|
|
||||||
(def buttons-container
|
(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
|
(def bottom-button-container
|
||||||
{:margin-bottom 6
|
{:margin-bottom 24
|
||||||
:margin-top 38})
|
: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-macros [status-im.utils.views :refer [defview letsubs]])
|
||||||
(:require [status-im.ui.components.react :as react]
|
(:require [status-im.ui.components.react :as react]
|
||||||
[re-frame.core :as re-frame]
|
[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.components.common.common :as components.common]
|
||||||
[status-im.ui.screens.intro.styles :as styles]
|
[status-im.ui.screens.intro.styles :as styles]
|
||||||
|
[status-im.ui.components.toolbar.view :as toolbar]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.ui.components.status-bar.view :as status-bar]
|
[status-im.ui.components.status-bar.view :as status-bar]))
|
||||||
[status-im.ui.screens.privacy-policy.views :as privacy-policy]))
|
|
||||||
|
(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 []
|
(defview intro []
|
||||||
[react/view {:style styles/intro-view}
|
(letsubs [window-width [:dimensions/window-width]]
|
||||||
[status-bar/status-bar {:flat? true}]
|
[react/view {:style styles/intro-view}
|
||||||
[react/view {:style styles/intro-logo-container}
|
[status-bar/status-bar {:flat? true}]
|
||||||
[components.common/logo styles/intro-logo]]
|
[intro-viewer [{:image (:intro1 resources/ui)
|
||||||
[react/i18n-text {:style styles/intro-text
|
:title :intro-title1
|
||||||
:key :intro-text}]
|
:text :intro-text1}
|
||||||
[react/view
|
{:image (:intro2 resources/ui)
|
||||||
[react/i18n-text {:style styles/intro-text-description
|
:title :intro-title2
|
||||||
:key :intro-text-description}]]
|
:text :intro-text2}
|
||||||
[react/view styles/buttons-container
|
{:image (:intro3 resources/ui)
|
||||||
[components.common/button {:button-style {:flex-direction :row}
|
:title :intro-title3
|
||||||
:on-press #(re-frame/dispatch [:accounts.create.ui/create-new-account-button-pressed])
|
:text :intro-text3}] window-width]
|
||||||
:label (i18n/label :t/create-account)}]
|
[react/view styles/buttons-container
|
||||||
[react/view styles/bottom-button-container
|
[components.common/button {:button-style (assoc styles/bottom-button :margin-bottom 16)
|
||||||
[components.common/button {:on-press #(re-frame/dispatch [:accounts.recover.ui/recover-account-button-pressed])
|
:on-press #(re-frame/dispatch [:accounts.create.ui/intro-wizard])
|
||||||
:label (i18n/label :t/already-have-account)
|
:label (i18n/label :t/get-started)}]
|
||||||
:background? false}]]
|
[components.common/button {:button-style (assoc styles/bottom-button :margin-bottom 24)
|
||||||
[privacy-policy/privacy-policy-button]]])
|
: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-container-background}
|
||||||
[react/view {:style styles/advanced-button-row}
|
[react/view {:style styles/advanced-button-row}
|
||||||
[react/text {:style styles/advanced-button-label}
|
[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}]]]]]
|
[icons/icon (if advanced? :main-icons/dropdown-up :main-icons/dropdown) {:color colors/blue}]]]]]
|
||||||
(when advanced?
|
(when advanced?
|
||||||
[advanced-settings params on-show supported-biometric-auth])]))
|
[advanced-settings params on-show supported-biometric-auth])]))
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
:recover
|
:recover
|
||||||
:accounts
|
:accounts
|
||||||
:intro
|
:intro
|
||||||
|
:intro-wizard
|
||||||
:hardwallet-authentication-method
|
:hardwallet-authentication-method
|
||||||
:hardwallet-connect
|
:hardwallet-connect
|
||||||
:enter-pin-login
|
:enter-pin-login
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
(-> (login-stack :intro)
|
(-> (login-stack :intro)
|
||||||
(update :screens conj
|
(update :screens conj
|
||||||
:intro
|
:intro
|
||||||
|
:intro-wizard
|
||||||
:keycard-onboarding-intro
|
:keycard-onboarding-intro
|
||||||
:keycard-onboarding-start
|
:keycard-onboarding-start
|
||||||
:keycard-onboarding-puk-code
|
:keycard-onboarding-puk-code
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
:recover recover/recover
|
:recover recover/recover
|
||||||
:accounts accounts/accounts
|
:accounts accounts/accounts
|
||||||
:intro intro/intro
|
:intro intro/intro
|
||||||
|
:intro-wizard intro/wizard
|
||||||
:hardwallet-authentication-method hardwallet.authentication/hardwallet-authentication-method
|
:hardwallet-authentication-method hardwallet.authentication/hardwallet-authentication-method
|
||||||
:hardwallet-connect hardwallet.connect/hardwallet-connect
|
:hardwallet-connect hardwallet.connect/hardwallet-connect
|
||||||
:hardwallet-connect-settings hardwallet.connect/hardwallet-connect
|
:hardwallet-connect-settings hardwallet.connect/hardwallet-connect
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
(:require [re-frame.core :refer [dispatch]]
|
(:require [re-frame.core :refer [dispatch]]
|
||||||
[status-im.utils.platform :refer [android?]]
|
[status-im.utils.platform :refer [android?]]
|
||||||
[status-im.utils.universal-links.core :as utils.universal-links]
|
[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.react :as react]
|
||||||
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
|
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
|
||||||
[status-im.utils.navigation :as navigation]
|
[status-im.utils.navigation :as navigation]
|
||||||
|
@ -46,6 +47,9 @@
|
||||||
(= view :public-chat-actions)
|
(= view :public-chat-actions)
|
||||||
(merge home.sheet/public-chat-actions)
|
(merge home.sheet/public-chat-actions)
|
||||||
|
|
||||||
|
(= view :learn-more)
|
||||||
|
(merge about-app/learn-more)
|
||||||
|
|
||||||
(= view :private-chat-actions)
|
(= view :private-chat-actions)
|
||||||
(merge home.sheet/private-chat-actions)
|
(merge home.sheet/private-chat-actions)
|
||||||
|
|
||||||
|
|
|
@ -87,4 +87,4 @@
|
||||||
:scroll scroll
|
:scroll scroll
|
||||||
:chain chain
|
:chain chain
|
||||||
:all-tokens all-tokens
|
:all-tokens all-tokens
|
||||||
:network-status network-status}]))
|
:network-status network-status}]))
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
(when on-dismiss
|
(when on-dismiss
|
||||||
(clj->js {:cancelable false})))))
|
(clj->js {:cancelable false})))))
|
||||||
|
|
||||||
|
(defn vibrate []
|
||||||
|
#_(.vibrate (.-Vibration rn-dependencies/react-native)))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:utils/show-popup
|
:utils/show-popup
|
||||||
(fn [{:keys [title content on-dismiss]}]
|
(fn [{:keys [title content on-dismiss]}]
|
||||||
|
|
|
@ -41,7 +41,18 @@ class TestCreateAccount(SingleDeviceTestCase):
|
||||||
if sign_in.ok_button.is_element_displayed():
|
if sign_in.ok_button.is_element_displayed():
|
||||||
sign_in.ok_button.click()
|
sign_in.ok_button.click()
|
||||||
sign_in.other_accounts_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:
|
if sign_in.get_public_key() == public_key:
|
||||||
pytest.fail('New account was not created')
|
pytest.fail('New account was not created')
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,13 @@ class TestSignIn(SingleDeviceTestCase):
|
||||||
@marks.critical
|
@marks.critical
|
||||||
def test_login_with_new_account(self):
|
def test_login_with_new_account(self):
|
||||||
sign_in = SignInView(self.driver)
|
sign_in = SignInView(self.driver)
|
||||||
username = 'test_user'
|
sign_in.create_user()
|
||||||
sign_in.create_user(username=username)
|
profile = sign_in.profile_button.click()
|
||||||
|
default_username = profile.default_username_text.text
|
||||||
self.driver.close_app()
|
self.driver.close_app()
|
||||||
self.driver.launch_app()
|
self.driver.launch_app()
|
||||||
sign_in.accept_agreements()
|
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')
|
self.errors.append('Username is not shown while login')
|
||||||
sign_in.sign_in()
|
sign_in.sign_in()
|
||||||
if not sign_in.home_button.is_element_displayed():
|
if not sign_in.home_button.is_element_displayed():
|
||||||
|
|
|
@ -230,7 +230,7 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase):
|
||||||
username_1 = 'user_%s' % get_current_time()
|
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_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
|
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
|
# device 1, device 2: join to public chat and send several messages
|
||||||
chat_name = device_1.get_public_chat_name()
|
chat_name = device_1.get_public_chat_name()
|
||||||
|
|
|
@ -15,8 +15,7 @@ class TestPublicChatMultipleDevice(MultipleDeviceTestCase):
|
||||||
def test_public_chat_messaging(self):
|
def test_public_chat_messaging(self):
|
||||||
self.create_drivers(2)
|
self.create_drivers(2)
|
||||||
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
|
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(), device_2.create_user()
|
||||||
home_1, home_2 = device_1.create_user(username=username_1), device_2.create_user(username=username_2)
|
|
||||||
profile_1 = home_1.profile_button.click()
|
profile_1 = home_1.profile_button.click()
|
||||||
default_username_1 = profile_1.default_username_text.text
|
default_username_1 = profile_1.default_username_text.text
|
||||||
profile_1.home_button.click()
|
profile_1.home_button.click()
|
||||||
|
|
|
@ -6,20 +6,32 @@ from views.base_view import BaseView
|
||||||
|
|
||||||
|
|
||||||
class AccountButton(BaseButton):
|
class AccountButton(BaseButton):
|
||||||
|
|
||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
super(AccountButton, self).__init__(driver)
|
super(AccountButton, self).__init__(driver)
|
||||||
self.locator = self.Locator.xpath_selector("//*[contains(@text,'0x')]")
|
self.locator = self.Locator.xpath_selector("//*[contains(@text,'0x')]")
|
||||||
|
|
||||||
|
|
||||||
class PasswordInput(BaseEditBox):
|
class PasswordInput(BaseEditBox):
|
||||||
|
|
||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
super(PasswordInput, self).__init__(driver)
|
super(PasswordInput, self).__init__(driver)
|
||||||
self.locator = self.Locator.xpath_selector("//android.widget.TextView[@text='Password']"
|
self.locator = self.Locator.xpath_selector("//android.widget.TextView[@text='Password']"
|
||||||
"/following-sibling::android.view.ViewGroup/android.widget.EditText")
|
"/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):
|
class SignInButton(BaseButton):
|
||||||
|
|
||||||
def __init__(self, driver):
|
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']")
|
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):
|
class IHaveAccountButton(RecoverAccessButton):
|
||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
super(IHaveAccountButton, self).__init__(driver)
|
super(IHaveAccountButton, self).__init__(driver)
|
||||||
self.locator = self.Locator.xpath_selector("//*[@text='I already have an account']")
|
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):
|
class AddExistingAccountButton(RecoverAccessButton):
|
||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
super(AddExistingAccountButton, self).__init__(driver)
|
super(AddExistingAccountButton, self).__init__(driver)
|
||||||
|
@ -106,25 +136,35 @@ class SignInView(BaseView):
|
||||||
# new design
|
# new design
|
||||||
self.create_account_button = CreateAccountButton(self.driver)
|
self.create_account_button = CreateAccountButton(self.driver)
|
||||||
self.i_have_account_button = IHaveAccountButton(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.add_existing_account_button = AddExistingAccountButton(self.driver)
|
||||||
self.confirm_password_input = ConfirmPasswordInput(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.name_input = NameInput(self.driver)
|
||||||
self.other_accounts_button = OtherAccountsButton(self.driver)
|
self.other_accounts_button = OtherAccountsButton(self.driver)
|
||||||
self.privacy_policy_link = PrivacyPolicyLink(self.driver)
|
self.privacy_policy_link = PrivacyPolicyLink(self.driver)
|
||||||
|
|
||||||
def create_user(self, username: str = '', password=common_password):
|
def create_user(self, 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()
|
|
||||||
self.get_started_button.click()
|
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()
|
return self.get_home_view()
|
||||||
|
|
||||||
def recover_access(self, passphrase: str, password: str = common_password):
|
def recover_access(self, passphrase: str, password: str = common_password):
|
||||||
|
@ -132,7 +172,7 @@ class SignInView(BaseView):
|
||||||
self.other_accounts_button.click()
|
self.other_accounts_button.click()
|
||||||
recover_access_view = self.add_existing_account_button.click()
|
recover_access_view = self.add_existing_account_button.click()
|
||||||
else:
|
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.click()
|
||||||
recover_access_view.passphrase_input.set_value(passphrase)
|
recover_access_view.passphrase_input.set_value(passphrase)
|
||||||
recover_access_view.password_input.click()
|
recover_access_view.password_input.click()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(ns status-im.test.accounts.create.core
|
(ns status-im.test.accounts.create.core
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||||
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.accounts.create.core :as models]))
|
[status-im.accounts.create.core :as models]))
|
||||||
|
|
||||||
(deftest on-account-created
|
(deftest on-account-created
|
||||||
|
@ -11,23 +12,65 @@
|
||||||
:mnemonic "hello world"}
|
:mnemonic "hello world"}
|
||||||
"password"
|
"password"
|
||||||
true)]
|
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)
|
(is (= (keys result)
|
||||||
[:db
|
[:db :accounts.login/clear-web-data :data-store/change-account :data-store/base-tx]))))
|
||||||
:node/start
|
|
||||||
: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
|
(ns status-im.test.runner
|
||||||
(:require [doo.runner :refer-macros [doo-tests]]
|
(:require [doo.runner :refer-macros [doo-tests]]
|
||||||
|
[status-im.test.accounts.create.core]
|
||||||
[status-im.test.accounts.recover.core]
|
[status-im.test.accounts.recover.core]
|
||||||
[status-im.test.browser.core]
|
[status-im.test.browser.core]
|
||||||
[status-im.test.browser.permissions]
|
[status-im.test.browser.permissions]
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
(set! goog.DEBUG false)
|
(set! goog.DEBUG false)
|
||||||
|
|
||||||
(doo-tests
|
(doo-tests
|
||||||
|
'status-im.test.accounts.create.core
|
||||||
'status-im.test.accounts.recover.core
|
'status-im.test.accounts.recover.core
|
||||||
'status-im.test.browser.core
|
'status-im.test.browser.core
|
||||||
'status-im.test.browser.permissions
|
'status-im.test.browser.permissions
|
||||||
|
@ -151,4 +153,4 @@
|
||||||
'status-im.test.utils.utils
|
'status-im.test.utils.utils
|
||||||
'status-im.test.wallet.subs
|
'status-im.test.wallet.subs
|
||||||
'status-im.test.wallet.transactions
|
'status-im.test.wallet.transactions
|
||||||
'status-im.test.wallet.transactions.subs)
|
'status-im.test.wallet.transactions.subs)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"amount": "Ποσό",
|
"amount": "Ποσό",
|
||||||
"open": "Άνοιγμα",
|
"open": "Άνοιγμα",
|
||||||
"close-app-title": "Προειδοποίηση!",
|
"close-app-title": "Προειδοποίηση!",
|
||||||
"wallet-advanced": "Προχωρημένη",
|
"advanced": "Προχωρημένη",
|
||||||
"members-active": {
|
"members-active": {
|
||||||
"one": "1 μέλος",
|
"one": "1 μέλος",
|
||||||
"other": "{{count}} μέλη",
|
"other": "{{count}} μέλη",
|
||||||
|
|
|
@ -151,6 +151,41 @@
|
||||||
"other": "{{count}} members"
|
"other": "{{count}} members"
|
||||||
},
|
},
|
||||||
"intro-message1": "Welcome to Status!\nTap this message to set your password and get started.",
|
"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",
|
"not-implemented": "!not implemented",
|
||||||
"new-contact": "New contact",
|
"new-contact": "New contact",
|
||||||
"datetime-second": {
|
"datetime-second": {
|
||||||
|
@ -249,7 +284,7 @@
|
||||||
"group-chat-admin-added": "*{{member}}* has been made admin",
|
"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",
|
"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 ",
|
"agree-by-continuing": "By continuing you agree\n to our ",
|
||||||
"wallet-advanced": "Advanced",
|
"advanced": "Advanced",
|
||||||
"currency-display-name-sos": "Somalia Shilling",
|
"currency-display-name-sos": "Somalia Shilling",
|
||||||
"currency-display-name-zar": "South Africa Rand",
|
"currency-display-name-zar": "South Africa Rand",
|
||||||
"offline-messaging": "Mailserver",
|
"offline-messaging": "Mailserver",
|
||||||
|
@ -649,7 +684,7 @@
|
||||||
"wallet-asset": "Asset",
|
"wallet-asset": "Asset",
|
||||||
"close-app-content": "The app will stop and close. When you reopen it, the selected network will be used",
|
"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",
|
"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",
|
"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.",
|
"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",
|
"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",
|
"transactions-history": "Transaction history",
|
||||||
"fetching-messages": "Fetching messages... ({{requests-left}} requests left)",
|
"fetching-messages": "Fetching messages... ({{requests-left}} requests left)",
|
||||||
"password_error1": "Passwords don't match.",
|
"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",
|
"your-contact-code": "Granting access authorizes this DApp to retrieve your contact code",
|
||||||
"password-placeholder": "At least 6 characters",
|
"password-placeholder": "At least 6 characters",
|
||||||
"clear-history-action": "Clear",
|
"clear-history-action": "Clear",
|
||||||
|
@ -919,6 +955,7 @@
|
||||||
"view-my-wallet": "View my wallet",
|
"view-my-wallet": "View my wallet",
|
||||||
"share-my-profile": "Share my profile",
|
"share-my-profile": "Share my profile",
|
||||||
"get-started": "Get started",
|
"get-started": "Get started",
|
||||||
|
"access-key": "Access key",
|
||||||
"tribute-to-talk": "Tribute to talk",
|
"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-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",
|
"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": "Billetera",
|
||||||
"wallet-add-asset": "Agregar activo",
|
"wallet-add-asset": "Agregar activo",
|
||||||
"wallet-address-from-clipboard": "Usar la dirección desde el portapapeles",
|
"wallet-address-from-clipboard": "Usar la dirección desde el portapapeles",
|
||||||
"wallet-advanced": "Avanzado",
|
"advanced": "Avanzado",
|
||||||
"wallet-asset": "Activo",
|
"wallet-asset": "Activo",
|
||||||
"wallet-assets": "Activos",
|
"wallet-assets": "Activos",
|
||||||
"wallet-backup-recovery-description": "Esto te ayudará a mantener tus activos seguros",
|
"wallet-backup-recovery-description": "Esto te ayudará a mantener tus activos seguros",
|
||||||
|
|
|
@ -652,7 +652,7 @@
|
||||||
"wallet": "کیف پول",
|
"wallet": "کیف پول",
|
||||||
"wallet-add-asset": "افزودن دارایی جدید",
|
"wallet-add-asset": "افزودن دارایی جدید",
|
||||||
"wallet-address-from-clipboard": "از آدرسی که در کلیپ بورد ذخیره کردم استفاده کن",
|
"wallet-address-from-clipboard": "از آدرسی که در کلیپ بورد ذخیره کردم استفاده کن",
|
||||||
"wallet-advanced": "پیشرفته",
|
"advanced": "پیشرفته",
|
||||||
"wallet-asset": "دارایی",
|
"wallet-asset": "دارایی",
|
||||||
"wallet-assets": "دارایی ها",
|
"wallet-assets": "دارایی ها",
|
||||||
"wallet-backup-recovery-description": "این به شما کمک می کند که دارایی خود را امن نگه دارید",
|
"wallet-backup-recovery-description": "این به شما کمک می کند که دارایی خود را امن نگه دارید",
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"amount": "金額",
|
"amount": "金額",
|
||||||
"open": "開く",
|
"open": "開く",
|
||||||
"close-app-title": "警告!",
|
"close-app-title": "警告!",
|
||||||
"wallet-advanced": "高度な",
|
"advanced": "高度な",
|
||||||
"members-active": {
|
"members-active": {
|
||||||
"one": "1人がアクティブ",
|
"one": "1人がアクティブ",
|
||||||
"other": "{{count}}人がアクティブ",
|
"other": "{{count}}人がアクティブ",
|
||||||
|
|
|
@ -988,7 +988,7 @@
|
||||||
"wallet": "지갑",
|
"wallet": "지갑",
|
||||||
"wallet-add-asset": "자산 추가",
|
"wallet-add-asset": "자산 추가",
|
||||||
"wallet-address-from-clipboard": "클립보드에서 가져오기",
|
"wallet-address-from-clipboard": "클립보드에서 가져오기",
|
||||||
"wallet-advanced": "고급 설정",
|
"advanced": "고급 설정",
|
||||||
"wallet-asset": "자산",
|
"wallet-asset": "자산",
|
||||||
"wallet-assets": "자산",
|
"wallet-assets": "자산",
|
||||||
"wallet-backup-recovery-description": "자산을 안전하게 보호하세요",
|
"wallet-backup-recovery-description": "자산을 안전하게 보호하세요",
|
||||||
|
|
|
@ -701,7 +701,7 @@
|
||||||
"wallet": "Dompet",
|
"wallet": "Dompet",
|
||||||
"wallet-add-asset": "Tambah aset",
|
"wallet-add-asset": "Tambah aset",
|
||||||
"wallet-address-from-clipboard": "Gunakan Alamat Daripada Papan Klip",
|
"wallet-address-from-clipboard": "Gunakan Alamat Daripada Papan Klip",
|
||||||
"wallet-advanced": "Lanjutan",
|
"advanced": "Lanjutan",
|
||||||
"wallet-asset": "Aset",
|
"wallet-asset": "Aset",
|
||||||
"wallet-assets": "Aset",
|
"wallet-assets": "Aset",
|
||||||
"wallet-backup-recovery-description": "Ini akan membantu anda memastikan aset anda selamat",
|
"wallet-backup-recovery-description": "Ini akan membantu anda memastikan aset anda selamat",
|
||||||
|
|
|
@ -672,7 +672,7 @@
|
||||||
"wallet": "वालेट",
|
"wallet": "वालेट",
|
||||||
"wallet-add-asset": "सम्पत्ति थप्नुहोस्",
|
"wallet-add-asset": "सम्पत्ति थप्नुहोस्",
|
||||||
"wallet-address-from-clipboard": "Gunakan Alamat Daripada Papan Klip",
|
"wallet-address-from-clipboard": "Gunakan Alamat Daripada Papan Klip",
|
||||||
"wallet-advanced": "Lanjutan",
|
"advanced": "Lanjutan",
|
||||||
"wallet-asset": "Aset",
|
"wallet-asset": "Aset",
|
||||||
"wallet-assets": "Aset",
|
"wallet-assets": "Aset",
|
||||||
"wallet-backup-recovery-description": "यसले तपाईंको सम्पत्ती सुरक्षित राख्न तपाईंलाई सहयोग गर्नेछ",
|
"wallet-backup-recovery-description": "यसले तपाईंको सम्पत्ती सुरक्षित राख्न तपाईंलाई सहयोग गर्नेछ",
|
||||||
|
|
|
@ -631,7 +631,7 @@
|
||||||
"wallet": "Portfel",
|
"wallet": "Portfel",
|
||||||
"wallet-add-asset": "Dodaj aktywo",
|
"wallet-add-asset": "Dodaj aktywo",
|
||||||
"wallet-address-from-clipboard": "Użyj adresu ze schowka",
|
"wallet-address-from-clipboard": "Użyj adresu ze schowka",
|
||||||
"wallet-advanced": "Zaawansowane",
|
"advanced": "Zaawansowane",
|
||||||
"wallet-asset": "Aktywo",
|
"wallet-asset": "Aktywo",
|
||||||
"wallet-assets": "Aktywa",
|
"wallet-assets": "Aktywa",
|
||||||
"wallet-backup-recovery-description": "Pomoże Ci to zachować bezpieczeństwo Twoich zasobów",
|
"wallet-backup-recovery-description": "Pomoże Ci to zachować bezpieczeństwo Twoich zasobów",
|
||||||
|
|
|
@ -669,7 +669,7 @@
|
||||||
"wallet": "Кошелек",
|
"wallet": "Кошелек",
|
||||||
"wallet-add-asset": "Добавить актив",
|
"wallet-add-asset": "Добавить актив",
|
||||||
"wallet-address-from-clipboard": "Использовать Адрес Из Буфера Обмена",
|
"wallet-address-from-clipboard": "Использовать Адрес Из Буфера Обмена",
|
||||||
"wallet-advanced": "Дополнительные параметры",
|
"advanced": "Дополнительные параметры",
|
||||||
"wallet-asset": "Актив",
|
"wallet-asset": "Актив",
|
||||||
"wallet-assets": "Активы",
|
"wallet-assets": "Активы",
|
||||||
"wallet-backup-recovery-description": "Это поможет сохранить Ваши активы в безопасности",
|
"wallet-backup-recovery-description": "Это поможет сохранить Ваши активы в безопасности",
|
||||||
|
|
|
@ -697,7 +697,7 @@
|
||||||
"wallet": "钱包",
|
"wallet": "钱包",
|
||||||
"wallet-add-asset": "添加资产",
|
"wallet-add-asset": "添加资产",
|
||||||
"wallet-address-from-clipboard": "使用剪贴板中的地址",
|
"wallet-address-from-clipboard": "使用剪贴板中的地址",
|
||||||
"wallet-advanced": "高级",
|
"advanced": "高级",
|
||||||
"wallet-asset": "资产",
|
"wallet-asset": "资产",
|
||||||
"wallet-assets": "资产",
|
"wallet-assets": "资产",
|
||||||
"wallet-backup-recovery-description": "这有助于您保护资产安全",
|
"wallet-backup-recovery-description": "这有助于您保护资产安全",
|
||||||
|
|