Merge pull request #201 from status-im/feature/recovery-screen-#198

added recover screen and updated bindings
This commit is contained in:
Roman Volosovskyi 2016-08-27 14:37:56 +03:00 committed by GitHub
commit ee3f6368c3
22 changed files with 513 additions and 169 deletions

View File

@ -139,7 +139,7 @@ dependencies {
compile project(':react-native-image-crop-picker') compile project(':react-native-image-crop-picker')
compile project(':react-native-webview-bridge') compile project(':react-native-webview-bridge')
//compile(name:'statusgo-android-16', ext:'aar') //compile(name:'statusgo-android-16', ext:'aar')
compile(group: 'status-im', name: 'status-go', version: 'unlock', ext: 'aar') compile(group: 'status-im', name: 'status-go', version: '0.1.0-574f67', ext: 'aar')
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"]) compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
} }

View File

@ -20,11 +20,7 @@ class GethModule extends ReactContextBaseJavaModule implements LifecycleEventLis
private GethConnector geth = null; private GethConnector geth = null;
private HashMap<String, Callback> startNodeCallbacks = new HashMap<>(); private HashMap<String, Callback> callbacks = new HashMap<>();
private HashMap<String, Callback> createAccountCallbacks = new HashMap<>();
private HashMap<String, Callback> unlockAccountCallbacks = new HashMap<>();
private HashMap<String, Callback> transactionCallbacks = new HashMap<>();
GethModule(ReactApplicationContext reactContext) { GethModule(ReactApplicationContext reactContext) {
super(reactContext); super(reactContext);
@ -83,33 +79,34 @@ class GethModule extends ReactContextBaseJavaModule implements LifecycleEventLis
Bundle data = message.getData(); Bundle data = message.getData();
String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER); String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER);
Log.d(TAG, "callback identifier: " + callbackIdentifier); Log.d(TAG, "callback identifier: " + callbackIdentifier);
Callback callback; Callback callback = callbacks.remove(callbackIdentifier);
if (callback == null) {
Log.d(TAG, "Could not find callback: " + callbackIdentifier);
}
switch (message.what) { switch (message.what) {
case GethMessages.MSG_NODE_STARTED: case GethMessages.MSG_NODE_STARTED:
Log.d(TAG, "handle startNodeCallbacks size: " + startNodeCallbacks.size());
callback = startNodeCallbacks.remove(callbackIdentifier);
if (callback != null) { if (callback != null) {
callback.invoke(true); callback.invoke(true);
} else {
Log.d(TAG, "Could not find callback: " + callbackIdentifier);
} }
break; break;
case GethMessages.MSG_NODE_STOPPED: case GethMessages.MSG_NODE_STOPPED:
break; break;
case GethMessages.MSG_ACCOUNT_CREATED: case GethMessages.MSG_ACCOUNT_CREATED:
callback = createAccountCallbacks.remove(callbackIdentifier); if (callback != null) {
callback.invoke(data.getString("data"));
}
break;
case GethMessages.MSG_ACCOUNT_RECOVERED:
if (callback != null) { if (callback != null) {
callback.invoke(data.getString("data")); callback.invoke(data.getString("data"));
} }
break; break;
case GethMessages.MSG_LOGGED_IN: case GethMessages.MSG_LOGGED_IN:
callback = unlockAccountCallbacks.remove(callbackIdentifier);
if (callback != null) { if (callback != null) {
callback.invoke(data.getString("result")); callback.invoke(data.getString("result"));
} }
break; break;
case GethMessages.MSG_TRANSACTION_COMPLETED: case GethMessages.MSG_TRANSACTION_COMPLETED:
callback = transactionCallbacks.remove(callbackIdentifier);
String result = data.getString("result"); String result = data.getString("result");
Log.d(TAG, "Send result: " + result + (callback == null)); Log.d(TAG, "Send result: " + result + (callback == null));
if (callback != null) { if (callback != null) {
@ -144,9 +141,7 @@ class GethModule extends ReactContextBaseJavaModule implements LifecycleEventLis
} }
String callbackIdentifier = createIdentifier(); String callbackIdentifier = createIdentifier();
Log.d(TAG, "Created callback identifier: " + callbackIdentifier); callbacks.put(callbackIdentifier, callback);
startNodeCallbacks.put(callbackIdentifier, callback);
Log.d(TAG, "startNodeCallbacks size: " + startNodeCallbacks.size());
geth.startNode(callbackIdentifier); geth.startNode(callbackIdentifier);
} }
@ -167,7 +162,7 @@ class GethModule extends ReactContextBaseJavaModule implements LifecycleEventLis
} }
String callbackIdentifier = createIdentifier(); String callbackIdentifier = createIdentifier();
unlockAccountCallbacks.put(callbackIdentifier, callback); callbacks.put(callbackIdentifier, callback);
geth.login(callbackIdentifier, address, password); geth.login(callbackIdentifier, address, password);
} }
@ -188,17 +183,38 @@ class GethModule extends ReactContextBaseJavaModule implements LifecycleEventLis
} }
String callbackIdentifier = createIdentifier(); String callbackIdentifier = createIdentifier();
createAccountCallbacks.put(callbackIdentifier, callback); callbacks.put(callbackIdentifier, callback);
geth.createAccount(callbackIdentifier, password); geth.createAccount(callbackIdentifier, password);
} }
@ReactMethod
public void recoverAccount(String passphrase, String password, Callback callback) {
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
callback.invoke("Activity doesn't exist");
return;
}
if (geth == null) {
callback.invoke("Geth connector is null");
return;
}
String callbackIdentifier = createIdentifier();
callbacks.put(callbackIdentifier, callback);
geth.recoverAccount(callbackIdentifier, passphrase, password);
}
private String createIdentifier() { private String createIdentifier() {
return UUID.randomUUID().toString(); return UUID.randomUUID().toString();
} }
@ReactMethod @ReactMethod
public void completeTransaction(String hash, Callback callback) { public void completeTransaction(String hash, String password, Callback callback) {
Activity currentActivity = getCurrentActivity(); Activity currentActivity = getCurrentActivity();
if (currentActivity == null) { if (currentActivity == null) {
@ -213,9 +229,9 @@ class GethModule extends ReactContextBaseJavaModule implements LifecycleEventLis
Log.d(TAG, "Complete transaction: " + hash); Log.d(TAG, "Complete transaction: " + hash);
String callbackIdentifier = createIdentifier(); String callbackIdentifier = createIdentifier();
transactionCallbacks.put(callbackIdentifier, callback); callbacks.put(callbackIdentifier, callback);
geth.completeTransaction(callbackIdentifier, hash); geth.completeTransaction(callbackIdentifier, hash, password);
} }
private static Callback signalEventCallback; private static Callback signalEventCallback;

View File

@ -71,10 +71,26 @@ public class GethConnector extends ServiceConnector {
} }
} }
public void completeTransaction(String callbackIdentifier, String hash){ public void recoverAccount(String callbackIdentifier, String passphrase, String password) {
if (checkBound()) {
Bundle data = new Bundle();
data.putString("passphrase", passphrase);
data.putString("password", password);
Message msg = createMessage(callbackIdentifier, GethMessages.MSG_RECOVER_ACCOUNT, data);
try {
serviceMessenger.send(msg);
} catch (RemoteException e) {
Log.e(TAG, "Exception sending message(recoverAccount) to service: ", e);
}
}
}
public void completeTransaction(String callbackIdentifier, String hash, String password){
if (checkBound()) { if (checkBound()) {
Bundle data = new Bundle(); Bundle data = new Bundle();
data.putString("hash", hash); data.putString("hash", hash);
data.putString("password", password);
Message msg = createMessage(callbackIdentifier, GethMessages.MSG_COMPLETE_TRANSACTION, data); Message msg = createMessage(callbackIdentifier, GethMessages.MSG_COMPLETE_TRANSACTION, data);
try { try {
serviceMessenger.send(msg); serviceMessenger.send(msg);

View File

@ -43,6 +43,16 @@ public class GethMessages {
*/ */
public static final int MSG_ACCOUNT_CREATED = 8; public static final int MSG_ACCOUNT_CREATED = 8;
/**
* Create an account
*/
static final int MSG_RECOVER_ACCOUNT = 9;
/**
* Account created event
*/
public static final int MSG_ACCOUNT_RECOVERED = 10;
/** /**
* Account complete transaction event * Account complete transaction event
*/ */

View File

@ -95,6 +95,10 @@ public class GethService extends Service {
createAccount(message); createAccount(message);
break; break;
case GethMessages.MSG_RECOVER_ACCOUNT:
recoverAccount(message);
break;
case GethMessages.MSG_LOGIN: case GethMessages.MSG_LOGIN:
login(message); login(message);
break; break;
@ -194,8 +198,7 @@ public class GethService extends Service {
private void createAccount(Message message) { private void createAccount(Message message) {
Bundle data = message.getData(); Bundle data = message.getData();
String password = data.getString("password"); String password = data.getString("password");
// TODO: remove second argument Log.d(TAG, "Creating account: " + password);
Log.d(TAG, "Creating account: " + password + " - " + dataFolder);
String jsonData = Statusgo.CreateAccount(password); String jsonData = Statusgo.CreateAccount(password);
Log.d(TAG, "Created account: " + jsonData); Log.d(TAG, "Created account: " + jsonData);
@ -204,13 +207,25 @@ public class GethService extends Service {
createAndSendReply(message, GethMessages.MSG_ACCOUNT_CREATED, replyData); createAndSendReply(message, GethMessages.MSG_ACCOUNT_CREATED, replyData);
} }
private void recoverAccount(Message message) {
Bundle data = message.getData();
String passphrase = data.getString("passphrase");
String password = data.getString("password");
Log.d(TAG, "Recovering account: " + passphrase + " - " + password);
String jsonData = Statusgo.RecoverAccount(password, passphrase);
Log.d(TAG, "Recovered account: " + jsonData);
Bundle replyData = new Bundle();
replyData.putString("data", jsonData);
createAndSendReply(message, GethMessages.MSG_ACCOUNT_RECOVERED, replyData);
}
private void login(Message message) { private void login(Message message) {
Bundle data = message.getData(); Bundle data = message.getData();
String address = data.getString("address"); String address = data.getString("address");
String password = data.getString("password"); String password = data.getString("password");
// TODO: remove third argument String result = Statusgo.Login(address, password);
String result = Statusgo.UnlockAccount(address, password, 0); Log.d(TAG, "Loggedin account: " + result);
Log.d(TAG, "Unlocked account: " + result);
Bundle replyData = new Bundle(); Bundle replyData = new Bundle();
replyData.putString("result", result); replyData.putString("result", result);
@ -220,9 +235,10 @@ public class GethService extends Service {
private void completeTransaction(Message message){ private void completeTransaction(Message message){
Bundle data = message.getData(); Bundle data = message.getData();
String hash = data.getString("hash"); String hash = data.getString("hash");
String password = data.getString("password");
Log.d(TAG, "Before CompleteTransaction: " + hash); Log.d(TAG, "Before CompleteTransaction: " + hash);
String result = Statusgo.CompleteTransaction(hash); String result = Statusgo.CompleteTransaction(hash, password);
Log.d(TAG, "After CompleteTransaction: " + result); Log.d(TAG, "After CompleteTransaction: " + result);
Bundle replyData = new Bundle(); Bundle replyData = new Bundle();

View File

@ -1,5 +1,5 @@
(ns status-im.accounts.handlers (ns status-im.accounts.handlers
(:require [status-im.models.accounts :as accounts] (:require [status-im.models.accounts :as accounts-model]
[re-frame.core :refer [register-handler after dispatch dispatch-sync debug]] [re-frame.core :refer [register-handler after dispatch dispatch-sync debug]]
[status-im.utils.logging :as log] [status-im.utils.logging :as log]
[status-im.protocol.api :as api] [status-im.protocol.api :as api]
@ -14,13 +14,14 @@
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[status-im.constants :refer [content-type-command-request]] [status-im.constants :refer [content-type-command-request]]
status-im.accounts.login.handlers status-im.accounts.login.handlers
status-im.accounts.recover.handlers
[clojure.string :as str] [clojure.string :as str]
[status-im.utils.datetime :as time] [status-im.utils.datetime :as time]
[status-im.utils.handlers :as u])) [status-im.utils.handlers :as u]))
(defn save-account [_ [_ account]] (defn save-account [_ [_ account]]
(accounts/save-accounts [account] true)) (accounts-model/save-accounts [account] true))
(register-handler (register-handler
:add-account :add-account
@ -55,7 +56,7 @@
(defn save-account-to-realm! (defn save-account-to-realm!
[{:keys [current-account-id accounts]} _] [{:keys [current-account-id accounts]} _]
(accounts/save-accounts [(get accounts current-account-id)] true)) (accounts-model/save-accounts [(get accounts current-account-id)] true))
(defn send-account-update (defn send-account-update
[{:keys [current-account-id accounts]} _] [{:keys [current-account-id accounts]} _]
@ -82,40 +83,17 @@
(when needs-update? (when needs-update?
(dispatch [:account-update])))))) (dispatch [:account-update]))))))
(defn initialize-account [{:keys [accounts] :as db} address] (defn set-current-account
(let [is-login-screen? (= (:view-id db) :login)] [{:keys [accounts] :as db} [_ address]]
(dispatch [:set :login {}])
(dispatch [:set :current-account-id address])
(let [key (:public-key (accounts address))] (let [key (:public-key (accounts address))]
(dispatch [:set :current-public-key key])) (-> db
(dispatch [:initialize-account address]) (assoc :current-account-id address)
(when is-login-screen? (dispatch [:navigate-to-clean default-view])))) (assoc :current-public-key key))))
(defn logged-in [db address] (register-handler :set-current-account set-current-account)
(let [is-login-screen? (= (:view-id db) :login)
new-account? (not is-login-screen?)]
(log/debug "Logged in: ")
(realm/change-account-realm address new-account?
#(if (nil? %)
(initialize-account db address)
(log/debug "Error changing acount realm: " %)))))
(register-handler
:login-account
(u/side-effect!
(fn [db [_ address password]]
(geth/login address password
(fn [result]
(let [data (json->clj result)
error (:error data)
success (zero? (count error))]
(log/debug "Logged in account: ")
(if success
(logged-in db address)
(dispatch [:set-in [:login :error] error]))))))))
(defn load-accounts! [db _] (defn load-accounts! [db _]
(let [accounts (->> (accounts/get-accounts) (let [accounts (->> (accounts-model/get-accounts)
(map (fn [{:keys [address] :as account}] (map (fn [{:keys [address] :as account}]
[address account])) [address account]))
(into {}))] (into {}))]

View File

@ -1,6 +1,11 @@
(ns status-im.accounts.login.handlers (ns status-im.accounts.login.handlers
(:require [re-frame.core :refer [register-handler after dispatch]] (:require [re-frame.core :refer [register-handler after dispatch]]
[status-im.utils.handlers :as u])) [status-im.utils.handlers :as u]
[status-im.utils.logging :as log]
[status-im.utils.types :refer [json->clj]]
[status-im.db :refer [default-view]]
[status-im.persistence.realm.core :as realm]
[status-im.components.geth :as geth]))
(defn set-login-from-qr (defn set-login-from-qr
@ -8,3 +13,47 @@
(assoc db :login (merge login login-info))) (assoc db :login (merge login login-info)))
(register-handler :set-login-from-qr set-login-from-qr) (register-handler :set-login-from-qr set-login-from-qr)
(defn initialize-account
[address new-account?]
(dispatch [:set :login {}])
(dispatch [:set-current-account address])
(dispatch [:initialize-account address])
(when new-account?
(do
(dispatch [:navigate-to-clean :accounts])
(dispatch [:navigate-to default-view]))))
(register-handler
:change-realm-account
(u/side-effect!
(fn [db [_ address new-account? callback]]
(realm/change-account-realm address new-account?
#(callback % address new-account?)))))
(defn on-account-changed
[error address new-account?]
(if (nil? error)
(initialize-account address true)
(log/debug "Error changing acount realm: " error)))
(defn logged-in
[db address]
(let [is-login-screen? (= (:view-id db) :login)
new-account? (not is-login-screen?)]
(log/debug "Logged in: ")
(dispatch [:change-realm-account address new-account? on-account-changed])))
(register-handler
:login-account
(u/side-effect!
(fn [db [_ address password]]
(geth/login address password
(fn [result]
(let [data (json->clj result)
error (:error data)
success (zero? (count error))]
(log/debug "Logged in account: ")
(if success
(logged-in db address)
(dispatch [:set-in [:login :error] error]))))))))

View File

@ -81,14 +81,6 @@
[address-input (or address "")] [address-input (or address "")]
[password-input error]]] [password-input error]]]
[view st/bottom-actions-container [view st/bottom-actions-container
(when (= keyboard-height 0)
[view st/recover-button-container
[touchable-highlight
{:on-press #()}
[view st/recover-button
[text {:style st/recover-button-text
:platform-specific platform-specific}
(label :t/recover-access)]]]])
[view st/connect-button-container [view st/connect-button-container
[touchable-highlight [touchable-highlight
{:on-press #(dispatch [:login-account address password])} {:on-press #(dispatch [:login-account address password])}

View File

@ -34,20 +34,6 @@
:right 0 :right 0
:bottom 0}) :bottom 0})
(def recover-button-container
{:flex 1})
(def recover-button
{:flex 1
:alignItems :center
:paddingVertical 16
:paddingHorizontal 28})
(def recover-button-text
{:flex 1
:color color-white
:fontSize 16})
(def connect-button-container (def connect-button-container
{:flex 1}) {:flex 1})

View File

@ -0,0 +1,37 @@
(ns status-im.accounts.recover.handlers
(:require [re-frame.core :refer [register-handler after dispatch dispatch-sync]]
[status-im.components.geth :as geth]
[status-im.utils.handlers :as u]
[status-im.utils.types :refer [json->clj]]
[status-im.utils.identicon :refer [identicon]]
[status-im.chat.sign-up :as sign-up-service]
[status-im.utils.logging :as log]
[clojure.string :as str]))
(defn on-account-changed
[error address new-account?]
(dispatch [:navigate-to-clean :accounts]))
(defn account-recovered [result password]
(let [_ (log/debug result)
data (json->clj result)
public-key (:pubkey data)
address (:address data)
account {:public-key public-key
:address address
:name address
:photo-path (identicon public-key)}]
(log/debug "account-recovered")
(when (not (str/blank? public-key))
(do
(dispatch [:set-in [:recover :passphrase] ""])
(dispatch [:set-in [:recover :password] ""])
(dispatch [:add-account account])
(dispatch [:navigate-back])))))
(defn recover-account
[{:keys [recover] :as db} [_ passphrase password]]
(geth/recover-account passphrase password (fn [result] (account-recovered result password)))
db)
(register-handler :recover-account recover-account)

View File

@ -0,0 +1,111 @@
(ns status-im.accounts.recover.screen
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view
text
text-input
image
linear-gradient
touchable-highlight]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar :refer [toolbar]]
[status-im.components.text-field.view :refer [text-field]]
[status-im.components.styles :refer [color-purple
color-white
icon-back
icon-search
toolbar-title-container
toolbar-title-text
toolbar-gradient
button-input]]
[status-im.components.react :refer [linear-gradient]]
[status-im.i18n :refer [label]]
[status-im.accounts.recover.styles :as st]
[status-im.accounts.recover.validations :as v]
[cljs.spec :as s]
[clojure.string :as str]
[status-im.utils.logging :as log]))
(defn toolbar-title
[platform-specific]
[view toolbar-title-container
[text {:style toolbar-title-text
:platform-specific platform-specific
:font :medium}
(label :t/recover-from-passphrase)]])
(defview passphrase-input [passphrase]
[error [:get-in [:recover :passphrase-error]]]
(let [error (if (str/blank? passphrase) "" error)
error (if (s/valid? ::v/passphrase passphrase)
error
(label :t/enter-valid-passphrase))]
[view
[text-field
{:value passphrase
:error error
:errorColor "#7099e6"
:label (label :t/passphrase)
:labelColor "#838c93de"
:lineColor "#0000001f"
:inputStyle st/input-style
:wrapperStyle (merge button-input st/address-input-wrapper)
:onChangeText #(dispatch [:set-in [:recover :passphrase] %])}]]))
(defview password-input [password]
[error [:get-in [:recover :password-error]]]
(let [error (if (str/blank? password) "" error)
error (if (s/valid? ::v/password password)
error
(label :t/enter-valid-password))]
[view
[text-field
{:value password
:error error
:errorColor "#7099e6"
:label (label :t/password)
:labelColor "#838c93de"
:lineColor "#0000001f"
:inputStyle st/input-style
:onChangeText #(dispatch [:set-in [:recover :password] %])}]]))
(defview recover [{platform-specific :platform-specific}]
[{:keys [passphrase password passphrase-error password-error]} [:get :recover]]
(let [valid-form? (and
(s/valid? ::v/passphrase passphrase)
(s/valid? ::v/password password))
gradient-colors ["rgba(24, 52, 76, 0.165)"
"rgba(24, 52, 76, 0.085)"
"rgba(24, 52, 76, 0)"]
_ (log/debug passphrase " - " password)]
[view st/screen-container
[status-bar {:platform-specific platform-specific
:type :transparent}]
[toolbar {:background-color :transparent
:nav-action {:image {:source {:uri :icon_back}
:style icon-back}
:handler #(dispatch [:navigate-back])}
:custom-content [toolbar-title platform-specific]
:action {:image {:style icon-search}
:handler #()}}]
[linear-gradient {:locations [0 0.6 1]
:colors gradient-colors
:style toolbar-gradient}]
[view st/recover-explain-container
[text {:style st/recover-explain-text
:platform-specific platform-specific
:font :medium}
(label :t/recover-explain)]]
[view st/form-container
[view st/form-container-inner
[passphrase-input (or passphrase "")]
[password-input (or password "")]]]
[view st/bottom-actions-container
[view st/recover-button-container
[touchable-highlight
{:on-press #(when valid-form?
(dispatch [:recover-account passphrase password]))}
[view (st/recover-button valid-form?)
[text {:style st/recover-button-text
:platform-specific platform-specific}
(label :t/recover)]]]]]]))

View File

@ -0,0 +1,71 @@
(ns status-im.accounts.recover.styles
(:require [status-im.components.styles :refer [title-font
text1-color
color-white
toolbar-background2
online-color]]))
(def screen-container
{:flex 1
:color :white
:background-color color-white})
(def gradient-background
{:position :absolute
:top 0
:right 0
:bottom 0
:left 0})
(def recover-explain-container
{:padding-horizontal 35
:padding-top 20
:justify-content :center})
(def recover-explain-text
{:color "#838c93de"
:font-size 16
:line-height 20
:text-align :center})
(def form-container
{:flex 1
:flex-direction "row"
:justifyContent "center"})
(def form-container-inner
{:flex 1
:padding-bottom 100
:margin-left 16})
(def bottom-actions-container
{:position :absolute
:left 0
:right 0
:bottom 0})
(def recover-button-container
{:flex 1})
(defn recover-button [valid-form?]
{:backgroundColor (if valid-form? "#7099e6" :gray)
:color :white
:flex 1
:alignItems :center
:paddingVertical 16
:paddingHorizontal 28})
(def recover-button-text
{:color color-white
:fontSize 16})
(def input-style
{:color "#323232"
:font-size 12})
(def scan-label
{:color :white})
(def address-input-wrapper
{})

View File

@ -0,0 +1,8 @@
(ns status-im.accounts.recover.validations
(:require [cljs.spec :as s]
[cljsjs.web3]
[status-im.persistence.realm.core :as realm]))
(s/def ::not-empty-string (s/and string? not-empty))
(s/def ::passphrase ::not-empty-string)
(s/def ::password ::not-empty-string)

View File

@ -25,6 +25,7 @@
white-form-text-input]] white-form-text-input]]
[status-im.utils.listview :as lw] [status-im.utils.listview :as lw]
[status-im.accounts.views.account :refer [account-view]] [status-im.accounts.views.account :refer [account-view]]
[status-im.chat.sign-up :as sign-up-service]
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[status-im.accounts.styles :as st] [status-im.accounts.styles :as st]
[status-im.utils.logging :as log])) [status-im.utils.logging :as log]))
@ -78,6 +79,14 @@
:renderRow render-row :renderRow render-row
:style st/account-list :style st/account-list
:contentContainerStyle (st/account-list-content (count accounts))}] :contentContainerStyle (st/account-list-content (count accounts))}]
[view st/bottom-actions-container
[view st/recover-button-container
[touchable-highlight
{:on-press #(dispatch [:navigate-to :recover])}
[view st/recover-button
[text {:style st/recover-button-text
:platform-specific platform-specific}
(label :t/recover-access)]]]]
[view st/add-account-button-container [view st/add-account-button-container
[touchable-highlight {:on-press create-account [touchable-highlight {:on-press create-account
:accessibility-label :create-account} :accessibility-label :create-account}
@ -87,4 +96,5 @@
[text {:style st/add-account-text [text {:style st/add-account-text
:platform-specific platform-specific :platform-specific platform-specific
:font :default} :font :default}
(label :t/add-account)]]]]]])) (label :t/add-account)]]]]
]]]))

View File

@ -76,12 +76,16 @@
:alignItems :center :alignItems :center
:justifyContent :center}) :justifyContent :center})
(def add-account-button-container (def bottom-actions-container
{:position :absolute {:position :absolute
:bottom 16 :left 0
:height 50 :right 0
:left 100 :bottom 0})
:right 100
(def add-account-button-container
{:flex 1
:paddingVertical 16
:paddingHorizontal 28
:justifyContent :center :justifyContent :center
:alignItems :center}) :alignItems :center})
@ -99,3 +103,17 @@
:color :white :color :white
:fontSize 16 :fontSize 16
:marginLeft 8}) :marginLeft 8})
(def recover-button-container
{:flex 1})
(def recover-button
{:flex 1
:alignItems :center
:paddingVertical 16
:paddingHorizontal 28})
(def recover-button-text
{:flex 1
:color color-white
:fontSize 16})

View File

@ -18,6 +18,7 @@
[status-im.discovery.search-results :refer [discovery-search-results]] [status-im.discovery.search-results :refer [discovery-search-results]]
[status-im.chat.screen :refer [chat]] [status-im.chat.screen :refer [chat]]
[status-im.accounts.login.screen :refer [login]] [status-im.accounts.login.screen :refer [login]]
[status-im.accounts.recover.screen :refer [recover]]
[status-im.accounts.screen :refer [accounts]] [status-im.accounts.screen :refer [accounts]]
[status-im.transactions.screen :refer [confirm]] [status-im.transactions.screen :refer [confirm]]
[status-im.chats-list.screen :refer [chats-list]] [status-im.chats-list.screen :refer [chats-list]]
@ -49,7 +50,6 @@
(defn app-root [] (defn app-root []
(let [signed-up (subscribe [:get :signed-up]) (let [signed-up (subscribe [:get :signed-up])
_ (log/debug "signed up: " @signed-up)
view-id (subscribe [:get :view-id]) view-id (subscribe [:get :view-id])
account-id (subscribe [:get :current-account-id]) account-id (subscribe [:get :current-account-id])
keyboard-height (subscribe [:get :keyboard-height])] keyboard-height (subscribe [:get :keyboard-height])]
@ -78,8 +78,10 @@
(let [startup-view (if @account-id (let [startup-view (if @account-id
(if @signed-up (if @signed-up
@view-id @view-id
:chat) (if (= @view-id :accounts)
(if (contains? #{:login :chat} @view-id) :accounts
:chat))
(if (contains? #{:login :chat :recover} @view-id)
@view-id @view-id
:accounts))] :accounts))]
(log/debug startup-view) (log/debug startup-view)
@ -101,6 +103,7 @@
:profile-photo-capture profile-photo-capture :profile-photo-capture profile-photo-capture
:accounts accounts :accounts accounts
:login login :login login
:recover recover
:confirm confirm :confirm confirm
:my-profile my-profile)] :my-profile my-profile)]
[component {:platform-specific {:styles styles [component {:platform-specific {:styles styles

View File

@ -161,9 +161,26 @@
(fn [db [_ {:keys [chat-id msg-id]}]] (fn [db [_ {:keys [chat-id msg-id]}]]
(set-message-shown db chat-id msg-id))) (set-message-shown db chat-id msg-id)))
(defn init-console-chat
[{:keys [chats] :as db} existing-account?]
(let [chat-id "console"
new-chat sign-up-service/console-chat]
(if (chats chat-id)
db
(do
(chats/create-chat new-chat)
(sign-up-service/intro existing-account?)
(when existing-account?
(sign-up-service/start-signup))
(-> db
(assoc :new-chat new-chat)
(update :chats assoc chat-id new-chat)
(update :chats-ids conj chat-id)
(assoc :current-chat-id "console"))))))
(register-handler :init-console-chat (register-handler :init-console-chat
(fn [db [_]] (fn [db _]
(sign-up-service/init db))) (init-console-chat db false)))
(register-handler :save-password (register-handler :save-password
(fn [db [_ password]] (fn [db [_ password]]
@ -221,15 +238,18 @@
[chat-id chat])) [chat-id chat]))
(into {})) (into {}))
ids (set (keys chats))] ids (set (keys chats))]
(-> db (-> db
(assoc :chats chats) (assoc :chats chats)
(assoc :chats-ids ids) (assoc :chats-ids ids)
(dissoc :loaded-chats)))) (dissoc :loaded-chats)
(init-console-chat true))))
(defn load-chats! (defn load-chats!
[db _] [db _]
(assoc db :loaded-chats (chats/chats-list))) (assoc db :loaded-chats (chats/chats-list)))
;TODO: check if its new account / signup status / create console chat
(register-handler :initialize-chats (register-handler :initialize-chats
(after #(dispatch [:load-unviewed-messages!])) (after #(dispatch [:load-unviewed-messages!]))
((enrich initialize-chats) load-chats!)) ((enrich initialize-chats) load-chats!))

View File

@ -24,7 +24,7 @@
:content-type text-content-type :content-type text-content-type
:outgoing true}) :outgoing true})
(defn- set-signed-up [db signed-up] (defn set-signed-up [db signed-up]
(s/put kv/kv-store :signed-up signed-up) (s/put kv/kv-store :signed-up signed-up)
(assoc db :signed-up signed-up)) (assoc db :signed-up signed-up))
@ -94,6 +94,18 @@
(when (= :failed status) (when (= :failed status)
(on-sign-up-response (label :t/incorrect-code))))) (on-sign-up-response (label :t/incorrect-code)))))
(defn start-signup []
(let [msg-id (random/id)]
(dispatch [:received-message
{:msg-id msg-id
:content (command-content
:phone
(label :t/phone-number-required))
:content-type content-type-command-request
:outgoing false
:from "console"
:to "me"}])))
;; -- Saving password ---------------------------------------- ;; -- Saving password ----------------------------------------
(defn save-password [password] (defn save-password [password]
;; TODO validate and save password ;; TODO validate and save password
@ -115,7 +127,7 @@
:new? false}]) :new? false}])
(dispatch [:received-message (dispatch [:received-message
{:msg-id (random/id) {:msg-id (random/id)
:content (label :t/passphrase) :content (label :t/here-is-your-passphrase)
:content-type text-content-type :content-type text-content-type
:outgoing false :outgoing false
:from "console" :from "console"
@ -141,16 +153,9 @@
:to "me" :to "me"
:new? false}]) :new? false}])
;; TODO highlight '!phone' ;; TODO highlight '!phone'
(let [msg-id (random/id)] (start-signup))
(dispatch [:received-message
{:msg-id msg-id
:content (command-content
:phone
(label :t/phone-number-required))
:content-type content-type-command-request
:outgoing false
:from "console"
:to "me"}])))
(def intro-status (def intro-status
{:msg-id "intro-status" {:msg-id "intro-status"
@ -162,7 +167,7 @@
:outgoing false :outgoing false
:to "me"}) :to "me"})
(defn intro [db] (defn intro [logged-in?]
(dispatch [:received-message intro-status]) (dispatch [:received-message intro-status])
(dispatch [:received-message (dispatch [:received-message
{:msg-id "intro-message1" {:msg-id "intro-message1"
@ -171,6 +176,7 @@
:outgoing false :outgoing false
:from "console" :from "console"
:to "me"}]) :to "me"}])
(when-not logged-in?
(dispatch [:received-message (dispatch [:received-message
{:msg-id "intro-message2" {:msg-id "intro-message2"
:content (label :t/intro-message2) :content (label :t/intro-message2)
@ -178,17 +184,16 @@
:outgoing false :outgoing false
:from "console" :from "console"
:to "me"}]) :to "me"}])
(let [msg-id "into-message3"]
(dispatch [:received-message (dispatch [:received-message
{:msg-id msg-id {:msg-id "intro-message3"
:content (command-content :content (command-content
:keypair :keypair
(label :t/keypair-generated)) (label :t/keypair-generated))
:content-type content-type-command-request :content-type content-type-command-request
:outgoing false :outgoing false
:from "console" :from "console"
:to "me"}])) :to "me"}])))
db)
(def console-chat (def console-chat
{:chat-id "console" {:chat-id "console"
@ -203,21 +208,3 @@
:contacts [{:identity "console" :contacts [{:identity "console"
:text-color "#FFFFFF" :text-color "#FFFFFF"
:background-color "#AB7967"}]}) :background-color "#AB7967"}]})
(defn create-chat [handler]
(fn [db]
(let [{:keys [new-chat] :as db'} (handler db)]
(when new-chat
(c/create-chat new-chat))
(dissoc db' :new-chat))))
(def init
(create-chat
(fn [{:keys [chats] :as db}]
(if (chats "console")
db
(-> db
(assoc-in [:chats "console"] console-chat)
(assoc :new-chat console-chat)
(assoc :current-chat-id "console")
(intro))))))

View File

@ -23,11 +23,15 @@
(when geth (when geth
(.createAccount geth password on-result))) (.createAccount geth password on-result)))
(defn recover-account [passphrase password on-result]
(when geth
(.recoverAccount geth passphrase password on-result)))
(defn login [address password on-result] (defn login [address password on-result]
(when geth (when geth
(.login geth address password on-result))) (.login geth address password on-result)))
(defn complete-transaction (defn complete-transaction
[hash callback] [hash password callback]
(when geth (when geth
(.completeTransaction geth hash callback))) (.completeTransaction geth hash password callback)))

View File

@ -112,3 +112,6 @@
(def button-input (def button-input
{:flex 1 {:flex 1
:flexDirection :column}) :flexDirection :column})
(def toolbar-gradient
{:height 4})

View File

@ -12,25 +12,25 @@
[{:keys [transactions-queue] :as db} _] [{:keys [transactions-queue] :as db} _]
(assoc db :transactions transactions-queue)) (assoc db :transactions transactions-queue))
(defn on-unlock [hashes] (defn on-unlock
(fn [result-str] [hashes password]
(let [{:keys [error]} (t/json->clj result-str)]
;; todo: add message about wrong password ;; todo: add message about wrong password
(if (s/blank? error)
(do (do
(dispatch [:set :wrong-password? false]) ;(dispatch [:set :wrong-password? false])
(doseq [hash hashes] (doseq [hash hashes]
(g/complete-transaction (g/complete-transaction
hash hash
password
#(dispatch [:transaction-completed hash %]))) #(dispatch [:transaction-completed hash %])))
(dispatch [:navigate-back])) (dispatch [:navigate-back])))
(dispatch [:set :wrong-password? true]))))) ;(dispatch [:set :wrong-password? true])
(register-handler :accept-transactions (register-handler :accept-transactions
(u/side-effect! (u/side-effect!
(fn [{:keys [transactions current-account-id]} [_ password]] (fn [{:keys [transactions current-account-id]} [_ password]]
(let [hashes (keys transactions)] (let [hashes (keys transactions)]
(g/login current-account-id password (on-unlock hashes)))))) (on-unlock hashes password)))))
(register-handler :deny-transactions (register-handler :deny-transactions
(u/side-effect! (u/side-effect!

View File

@ -63,7 +63,7 @@
"it's me the Console nice to meet you!") "it's me the Console nice to meet you!")
:generate-passphrase (str "I'll generate a passphrase for you so you can restore your " :generate-passphrase (str "I'll generate a passphrase for you so you can restore your "
"access or log in from another device") "access or log in from another device")
:passphrase "Here's your passphrase:" :here-is-your-passphrase "Here's your passphrase:"
:written-down "Make sure you had securely written it down" :written-down "Make sure you had securely written it down"
:phone-number-required (str "Your phone number is also required to use the app. Type the " :phone-number-required (str "Your phone number is also required to use the app. Type the "
"exclamation mark or hit the icon to open the command list " "exclamation mark or hit the icon to open the command list "
@ -72,7 +72,7 @@
"and public exchange with candidates " "and public exchange with candidates "
"in the US presidential election") "in the US presidential election")
:intro-message1 "Hello there! It's Status a Dapp browser in your phone." :intro-message1 "Hello there! It's Status a Dapp browser in your phone."
:intro-message2 (str "Status1 uses a highly secure key-pair authentication type " :intro-message2 (str "Status uses a highly secure key-pair authentication type "
"to provide you a reliable way to access your account") "to provide you a reliable way to access your account")
:keypair-generated (str "A key pair has been generated and saved to your device. " :keypair-generated (str "A key pair has been generated and saved to your device. "
"Create a password to secure your key") "Create a password to secure your key")
@ -153,14 +153,22 @@
;login ;login
:recover-access "Recover access"
:connect "Connect" :connect "Connect"
:address "Address" :address "Address"
:password "Password" :password "Password"
:login "Login" :login "Login"
:wrong-password "Wrong password" :wrong-password "Wrong password"
;recover
:recover-from-passphrase "Recover from passphrase"
:recover-explain "Please enter the passphrase for your password to recover access"
:passphrase "Passphrase"
:recover "Recover"
:enter-valid-passphrase "Please enter a passphrase"
:enter-valid-password "Please enter a password"
;accounts ;accounts
:recover-access "Recover access"
:add-account "Add account" :add-account "Add account"
;validation ;validation
@ -178,4 +186,5 @@
:one-more-item "One more item" :one-more-item "One more item"
:fee "Fee" :fee "Fee"
:value "Value" :value "Value"
}) })