From eb8557dde81bdc8f3f19bf39bc5176abfa52f11b Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Wed, 28 Feb 2018 14:14:59 +0300 Subject: [PATCH] Introduced onboarding sign in Signed-off-by: Andrey Shovkoplyas --- resources/icons/logo.svg | 5 + resources/images/ui/analytics-image.png | Bin 0 -> 6014 bytes resources/images/ui/welcome-image.png | Bin 0 -> 30057 bytes resources/js/bots/console/bot.js | 60 ------- src/status_im/android/core.cljs | 2 - src/status_im/chat/console.cljs | 46 ----- src/status_im/chat/constants.cljs | 8 - src/status_im/chat/events.cljs | 127 ++++++-------- src/status_im/chat/events/console.cljs | 24 +-- .../chat/events/receive_message.cljs | 10 -- src/status_im/chat/screen.cljs | 7 +- src/status_im/chat/subs.cljs | 9 +- src/status_im/chat/views/toolbar_content.cljs | 6 +- .../data_store/realm/schemas/base/core.cljs | 8 +- .../realm/schemas/base/v7/account.cljs | 26 +++ .../realm/schemas/base/v7/core.cljs | 10 ++ src/status_im/react_native/resources.cljs | 8 +- src/status_im/translations/en.cljs | 27 +++ .../ui/components/action_button/styles.cljs | 1 - src/status_im/ui/components/colors.cljs | 15 +- .../ui/components/common/common.cljs | 28 ++- .../ui/components/common/styles.cljs | 59 +++++-- .../ui/components/icons/vector_icons.cljs | 40 +++-- src/status_im/ui/components/react.cljs | 5 +- .../ui/components/status_bar/view.cljs | 6 +- src/status_im/ui/components/styles.cljs | 6 +- .../ui/components/text_input/styles.cljs | 27 +++ .../ui/components/text_input/view.cljs | 20 +++ .../text_input_with_label/animation.cljs | 32 ---- .../text_input_with_label/styles.cljs | 68 -------- .../text_input_with_label/view.cljs | 72 -------- .../ui/components/toolbar/styles.cljs | 22 +-- src/status_im/ui/components/toolbar/view.cljs | 18 +- .../ui/components/tooltip/animations.cljs | 12 ++ .../ui/components/tooltip/styles.cljs | 31 ++++ .../ui/components/tooltip/views.cljs | 17 ++ .../screens/accounts/create/navigation.cljs | 9 + .../ui/screens/accounts/create/styles.cljs | 58 +++++++ .../ui/screens/accounts/create/views.cljs | 85 ++++++++++ src/status_im/ui/screens/accounts/db.cljs | 20 ++- src/status_im/ui/screens/accounts/events.cljs | 46 ++--- .../ui/screens/accounts/login/events.cljs | 45 ++--- .../ui/screens/accounts/login/styles.cljs | 70 ++++---- .../ui/screens/accounts/login/views.cljs | 106 +++++++----- .../ui/screens/accounts/recover/db.cljs | 8 +- .../ui/screens/accounts/recover/events.cljs | 39 ++--- .../ui/screens/accounts/recover/styles.cljs | 11 +- .../ui/screens/accounts/recover/views.cljs | 94 +++++----- src/status_im/ui/screens/accounts/styles.cljs | 78 ++++----- src/status_im/ui/screens/accounts/subs.cljs | 13 +- src/status_im/ui/screens/accounts/views.cljs | 84 +++++---- src/status_im/ui/screens/add_new/views.cljs | 12 +- src/status_im/ui/screens/browser/events.cljs | 6 +- src/status_im/ui/screens/db.cljs | 5 +- .../ui/screens/discover/all_dapps/views.cljs | 3 +- .../discover/recent_statuses/views.cljs | 3 +- src/status_im/ui/screens/events.cljs | 42 ++--- src/status_im/ui/screens/home/styles.cljs | 48 ++++++ src/status_im/ui/screens/home/views.cljs | 50 ++++-- src/status_im/ui/screens/intro/styles.cljs | 43 +++++ src/status_im/ui/screens/intro/views.cljs | 27 +++ src/status_im/ui/screens/navigation.cljs | 19 +-- .../network_settings/add_rpc/views.cljs | 4 +- .../ui/screens/profile/group_chat/styles.cljs | 2 +- .../ui/screens/profile/user/styles.cljs | 2 +- src/status_im/ui/screens/subs.cljs | 11 +- .../ui/screens/usage_data/events.cljs | 10 ++ .../ui/screens/usage_data/styles.cljs | 48 ++++++ .../ui/screens/usage_data/views.cljs | 30 ++++ src/status_im/ui/screens/views.cljs | 160 +++++++++--------- .../screens/wallet/components/animations.cljs | 12 -- .../ui/screens/wallet/components/styles.cljs | 27 --- .../ui/screens/wallet/components/views.cljs | 18 +- .../ui/screens/wallet/send/views.cljs | 3 +- .../screens/wallet/transactions/styles.cljs | 7 +- .../ui/screens/wallet/transactions/views.cljs | 4 +- 76 files changed, 1225 insertions(+), 999 deletions(-) create mode 100644 resources/icons/logo.svg create mode 100644 resources/images/ui/analytics-image.png create mode 100644 resources/images/ui/welcome-image.png create mode 100644 src/status_im/data_store/realm/schemas/base/v7/account.cljs create mode 100644 src/status_im/data_store/realm/schemas/base/v7/core.cljs create mode 100644 src/status_im/ui/components/text_input/styles.cljs create mode 100644 src/status_im/ui/components/text_input/view.cljs delete mode 100644 src/status_im/ui/components/text_input_with_label/animation.cljs delete mode 100644 src/status_im/ui/components/text_input_with_label/styles.cljs delete mode 100644 src/status_im/ui/components/text_input_with_label/view.cljs create mode 100644 src/status_im/ui/components/tooltip/animations.cljs create mode 100644 src/status_im/ui/components/tooltip/styles.cljs create mode 100644 src/status_im/ui/components/tooltip/views.cljs create mode 100644 src/status_im/ui/screens/accounts/create/navigation.cljs create mode 100644 src/status_im/ui/screens/accounts/create/styles.cljs create mode 100644 src/status_im/ui/screens/accounts/create/views.cljs create mode 100644 src/status_im/ui/screens/intro/styles.cljs create mode 100644 src/status_im/ui/screens/intro/views.cljs create mode 100644 src/status_im/ui/screens/usage_data/events.cljs create mode 100644 src/status_im/ui/screens/usage_data/styles.cljs create mode 100644 src/status_im/ui/screens/usage_data/views.cljs delete mode 100644 src/status_im/ui/screens/wallet/components/animations.cljs diff --git a/resources/icons/logo.svg b/resources/icons/logo.svg new file mode 100644 index 0000000000..aa3fcd1986 --- /dev/null +++ b/resources/icons/logo.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources/images/ui/analytics-image.png b/resources/images/ui/analytics-image.png new file mode 100644 index 0000000000000000000000000000000000000000..61b06b97dd8b054f24b8a765085e356daf0ac2bb GIT binary patch literal 6014 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 literal 0 HcmV?d00001 diff --git a/resources/images/ui/welcome-image.png b/resources/images/ui/welcome-image.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8ca6fe5904e33213cdba095233761977fa9a4f GIT binary patch literal 30057 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 QWdHyG07*qoM6N<$f($YmP5=M^ literal 0 HcmV?d00001 diff --git a/resources/js/bots/console/bot.js b/resources/js/bots/console/bot.js index ff43b4a364..7ad67afa1f 100644 --- a/resources/js/bots/console/bot.js +++ b/resources/js/bots/console/bot.js @@ -570,66 +570,6 @@ status.command({ } }); -status.response({ - name: "password", - color: "#7099e6", - scope: ["personal-chats", "anonymous", "dapps"], - description: I18n.t('password_description'), - icon: "lock_white", - sequentialParams: true, - params: [ - { - name: "password", - type: status.types.PASSWORD, - placeholder: I18n.t('password_placeholder'), - hidden: true - }, - { - name: "password-confirmation", - type: status.types.PASSWORD, - placeholder: I18n.t('password_placeholder2'), - hidden: true - } - ], - validator: function (params, context) { - if (!params.hasOwnProperty("password-confirmation") || params["password-confirmation"].length === 0) { - if (params.password === null || params.password.length < 6) { - var error = status.components.validationMessage( - I18n.t('password_validation_title'), - I18n.t('password_error') - ); - return {markup: error}; - } - } else { - if (params.password !== params["password-confirmation"]) { - var error = status.components.validationMessage( - I18n.t('password_validation_title'), - I18n.t('password_error1') - ); - return {markup: error}; - } - } - - }, - preview: function (params, context) { - var style = { - marginTop: 5, - marginHorizontal: 0, - fontSize: 14, - color: "black" - }; - - if (context.platform == "ios") { - style.fontSize = 8; - style.marginTop = 10; - style.marginBottom = 2; - style.letterSpacing = 1; - } - - return {markup: status.components.text({style: style}, "●●●●●●●●●●")}; - } -}); - status.response({ name: "grant-permissions", scope: ["personal-chats", "anonymous", "registered", "dapps"], diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index d9d556819e..5db5886509 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -22,11 +22,9 @@ ;; this listener and handle application's closing ;; in handlers (let [stack (subscribe [:get :navigation-stack]) - creating? (subscribe [:get :accounts/creating-account?]) result-box (subscribe [:get-current-chat-ui-prop :result-box]) webview (subscribe [:get :webview-bridge])] (cond - @creating? true (and @webview (:can-go-back? @result-box)) (do (.goBack @webview) true) diff --git a/src/status_im/chat/console.cljs b/src/status_im/chat/console.cljs index d5e18512e8..10659f0435 100644 --- a/src/status_im/chat/console.cljs +++ b/src/status_im/chat/console.cljs @@ -2,7 +2,6 @@ (:require [status-im.ui.components.styles :refer [default-chat-color]] [status-im.utils.random :as random] [status-im.constants :as const] - [status-im.chat.constants :as chat-const] [status-im.i18n :as i18n] [clojure.string :as string])) @@ -16,51 +15,6 @@ :content content :content-type content-type}) -(def shake-your-phone-message - (console-message {:content (i18n/label :t/shake-your-phone) - :content-type const/text-content-type})) - -(def account-generation-message - (console-message {:message-id chat-const/crazy-math-message-id - :content (i18n/label :t/account-generation-message) - :content-type const/text-content-type})) - -(def move-to-internal-failure-message - (console-message {:message-id chat-const/move-to-internal-failure-message-id - :content {:command "grant-permissions" - :content (i18n/label :t/move-to-internal-failure-message)} - :content-type const/content-type-command-request})) - -(defn passphrase-messages [mnemonic signing-phrase crazy-math-message?] - [(console-message {:message-id chat-const/passphrase-message-id - :content (if crazy-math-message? - (i18n/label :t/phew-here-is-your-passphrase) - (i18n/label :t/here-is-your-passphrase)) - :content-type const/text-content-type}) - - (console-message {:message-id (random/id) - :content mnemonic - :content-type const/text-content-type}) - - (console-message {:message-id chat-const/signing-phrase-message-id - :content (i18n/label :t/here-is-your-signing-phrase) - :content-type const/text-content-type}) - - (console-message {:message-id (random/id) - :content signing-phrase - :content-type const/text-content-type})]) - -(def intro-status-message - (console-message {:message-id chat-const/intro-status-message-id - :content (i18n/label :t/intro-status) - :content-type const/content-type-status})) - -(def intro-message1 - (console-message {:message-id chat-const/intro-message1-id - :content {:command "password" - :content (i18n/label :t/intro-message1)} - :content-type const/content-type-command-request})) - (def chat {:chat-id const/console-chat-id :name (string/capitalize const/console-chat-id) diff --git a/src/status_im/chat/constants.cljs b/src/status_im/chat/constants.cljs index b5abbc8485..dd73f09a98 100644 --- a/src/status_im/chat/constants.cljs +++ b/src/status_im/chat/constants.cljs @@ -5,18 +5,10 @@ (def arg-wrapping-char "\"") (def input-height 56) -(def max-input-height 66) (def input-spacing-top 16) (def console-chat-id "console") -(def crazy-math-message-id "crazy-math-message") -(def move-to-internal-failure-message-id "move-to-internal-failure-message") -(def passphrase-message-id "passphraze-message") -(def signing-phrase-message-id "signing-phrase-message") -(def intro-status-message-id "intro-status") -(def intro-message1-id "intro-message1") ;; TODO(janherich): figure out something better then this (def send-command-ref ["transactor" :command 83 "send"]) (def request-command-ref ["transactor" :command 83 "request"]) -(def phone-command-ref ["console" :command 50 "phone"]) diff --git a/src/status_im/chat/events.cljs b/src/status_im/chat/events.cljs index 2b43beb2d6..b3a5c3627a 100644 --- a/src/status_im/chat/events.cljs +++ b/src/status_im/chat/events.cljs @@ -7,7 +7,6 @@ [status-im.protocol.core :as protocol] [status-im.chat.models :as models] [status-im.chat.console :as console] - [status-im.chat.constants :as chat.constants] [status-im.data-store.chats :as chats] [status-im.data-store.messages :as messages] [status-im.data-store.pending-messages :as pending-messages] @@ -29,7 +28,7 @@ :stored-unviewed-messages (fn [cofx _] (assoc cofx :stored-unviewed-messages - (messages/get-unviewed (-> cofx :db :current-public-key))))) + (messages/get-unviewed (-> cofx :db :current-public-key))))) (re-frame/reg-cofx :get-stored-message @@ -129,7 +128,7 @@ [re-frame/trim-v] (fn [db [details]] (models/set-chat-ui-props db {:show-bottom-info? true - :bottom-info details}))) + :bottom-info details}))) (def index-messages (partial into {} (map (juxt :message-id identity)))) @@ -153,18 +152,15 @@ (update-in db [:chats chat-id :messages message-id] assoc :appearing? false))) (defn init-console-chat - [{:keys [chats] :accounts/keys [current-account-id] :as db}] + [{:keys [chats] :as db}] (if (chats constants/console-chat-id) {:db db} - (cond-> {:db (-> db - (assoc :current-chat-id constants/console-chat-id) - (update :chats assoc constants/console-chat-id console/chat)) - :dispatch-n [[:add-contacts [console/contact]]] - :save-chat console/chat - :save-all-contacts [console/contact]} - - (not current-account-id) - (update :dispatch-n concat [[:chat-received-message/add-when-commands-loaded console/intro-message1]])))) + {:db (-> db + (assoc :current-chat-id constants/console-chat-id) + (update :chats assoc constants/console-chat-id console/chat)) + :dispatch [:add-contacts [console/contact]] + :save-chat console/chat + :save-all-contacts [console/contact]})) (handlers/register-handler-fx :init-console-chat @@ -186,31 +182,26 @@ get-stored-messages stored-unviewed-messages stored-message-ids]} _] - (let [{:accounts/keys [account-creation?]} db - load-default-contacts-event [:load-default-contacts!]] - (if account-creation? - {:db db - :dispatch load-default-contacts-event} - (let [chat->message-id->request (reduce (fn [acc {:keys [chat-id message-id] :as request}] - (assoc-in acc [chat-id message-id] request)) - {} - stored-unanswered-requests) - chats (reduce (fn [acc {:keys [chat-id] :as chat}] - (let [chat-messages (index-messages (get-stored-messages chat-id))] - (assoc acc chat-id + (let [chat->message-id->request (reduce (fn [acc {:keys [chat-id message-id] :as request}] + (assoc-in acc [chat-id message-id] request)) + {} + stored-unanswered-requests) + chats (reduce (fn [acc {:keys [chat-id] :as chat}] + (let [chat-messages (index-messages (get-stored-messages chat-id))] + (assoc acc chat-id (assoc chat - :unviewed-messages (get stored-unviewed-messages chat-id) - :requests (get chat->message-id->request chat-id) - :messages chat-messages - :not-loaded-message-ids (set/difference (get stored-message-ids chat-id) - (-> chat-messages keys set)))))) - {} - all-stored-chats)] - (-> db - (assoc :chats chats - :deleted-chats inactive-chat-ids) - init-console-chat - (update :dispatch-n conj load-default-contacts-event))))))) + :unviewed-messages (get stored-unviewed-messages chat-id) + :requests (get chat->message-id->request chat-id) + :messages chat-messages + :not-loaded-message-ids (set/difference (get stored-message-ids chat-id) + (-> chat-messages keys set)))))) + {} + all-stored-chats)] + (-> db + (assoc :chats chats + :deleted-chats inactive-chat-ids) + init-console-chat + (update :dispatch-n conj [:load-default-contacts!]))))) (handlers/register-handler-fx :send-seen! @@ -219,40 +210,18 @@ (let [{:keys [web3 chats] :contacts/keys [contacts]} db {:keys [group-chat public? messages]} (get chats chat-id) statuses (assoc (get-in messages [message-id :user-statuses]) me :seen)] - (cond-> {:db (-> db - (update-in [:chats chat-id :unviewed-messages] disj message-id) - (assoc-in [:chats chat-id :messages message-id :user-statuses] statuses)) + (cond-> {:db (-> db + (update-in [:chats chat-id :unviewed-messages] disj message-id) + (assoc-in [:chats chat-id :messages message-id :user-statuses] statuses)) :update-message {:message-id message-id :user-statuses statuses}} - ;; for public chats and 1-1 bot/dapp chats, it makes no sense to signalise `:seen` msg - (not (or public? (get-in contacts [chat-id :dapp?]))) - (assoc :protocol-send-seen {:web3 web3 - :message (cond-> {:from me - :to from - :message-id message-id} - group-chat (assoc :group-id chat-id))}))))) - -(handlers/register-handler-fx - :show-mnemonic - [re-frame/trim-v] - (fn [{:keys [db]} [mnemonic signing-phrase]] - (let [crazy-math-message? (contains? (get-in db [:chats chat.constants/console-chat-id]) chat.constants/crazy-math-message-id) - messages-events (->> (console/passphrase-messages mnemonic signing-phrase crazy-math-message?) - (mapv #(vector :chat-received-message/add %)))] - {:dispatch-n messages-events}))) - -;; TODO(alwx): can be simplified -(handlers/register-handler-fx - :account-generation-message - (fn [{:keys [db]} _] - (when-not (contains? (get-in db [:chats chat.constants/console-chat-id]) chat.constants/passphrase-message-id) - {:dispatch [:chat-received-message/add console/account-generation-message]}))) - -(handlers/register-handler-fx - :move-to-internal-failure-message - (fn [{:keys [db]} _] - (when-not (contains? (get-in db [:chats chat.constants/console-chat-id]) chat.constants/move-to-internal-failure-message-id) - {:dispatch [:chat-received-message/add console/move-to-internal-failure-message]}))) + ;; for public chats and 1-1 bot/dapp chats, it makes no sense to signalise `:seen` msg + (not (or public? (get-in contacts [chat-id :dapp?]))) + (assoc :protocol-send-seen {:web3 web3 + :message (cond-> {:from me + :to from + :message-id message-id} + group-chat (assoc :group-id chat-id))}))))) (handlers/register-handler-fx :browse-link-from-message @@ -269,8 +238,8 @@ (models/set-chat-ui-props {:validation-messages nil}) (update-in [:chats chat-id] dissoc :chat-loaded-event))} - chat-loaded-event - (assoc :dispatch chat-loaded-event)))) + chat-loaded-event + (assoc :dispatch chat-loaded-event)))) (handlers/register-handler-fx :add-chat-loaded-event @@ -278,7 +247,7 @@ (fn [{:keys [db] :as cofx} [chat-id event]] (if (get (:chats db) chat-id) {:db (assoc-in db [:chats chat-id :chat-loaded-event] event)} - (-> (models/add-chat cofx chat-id) ; chat not created yet, we have to create it + (-> (models/add-chat cofx chat-id) ; chat not created yet, we have to create it (assoc-in [:db :chats chat-id :chat-loaded-event] event))))) ;; TODO(janherich): remove this unnecessary event in the future (only model function `add-chat` will stay) @@ -309,7 +278,7 @@ :start-chat [(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v] (fn [{:keys [db] :as cofx} [contact-id {:keys [navigation-replace?]}]] - (when (not= (:current-public-key db) contact-id) ; don't allow to open chat with yourself + (when (not= (:current-public-key db) contact-id) ; don't allow to open chat with yourself (if (get (:chats db) contact-id) (navigate-to-chat cofx contact-id navigation-replace?) ; existing chat, just preload and displey (let [add-chat-fx (models/add-chat cofx contact-id)] ; new chat, create before preload & display @@ -334,12 +303,12 @@ (update :chats dissoc chat-id) (update :deleted-chats (fnil conj #{}) chat-id)) :delete-pending-messages chat-id} - (or group-chat debug?) - (assoc :delete-messages chat-id) - debug? - (assoc :delete-chat chat-id) - (not debug?) - (assoc :deactivate-chat chat-id))))) + (or group-chat debug?) + (assoc :delete-messages chat-id) + debug? + (assoc :delete-chat chat-id) + (not debug?) + (assoc :deactivate-chat chat-id))))) (handlers/register-handler-fx :delete-chat diff --git a/src/status_im/chat/events/console.cljs b/src/status_im/chat/events/console.cljs index 8daac3cc64..1a61f5f604 100644 --- a/src/status_im/chat/events/console.cljs +++ b/src/status_im/chat/events/console.cljs @@ -1,7 +1,5 @@ (ns status-im.chat.events.console - (:require [re-frame.core :as re-frame] - [status-im.utils.handlers :as handlers] - [status-im.constants :as const] + (:require [status-im.constants :as constants] [status-im.i18n :as i18n] [status-im.chat.console :as console-chat] [status-im.ui.screens.accounts.events :as accounts-events] @@ -24,13 +22,13 @@ (console-chat/console-message {:message-id id :content (str type ": " message) - :content-type const/text-content-type})) + :content-type constants/text-content-type})) messages random-id-seq)] (conj message-events (console-chat/console-message {:message-id (first random-id-seq) :content (str content) - :content-type const/text-content-type}))) + :content-type constants/text-content-type}))) (log/debug "ignoring command: " name)))))) (defn faucet-base-url->url [url] @@ -40,15 +38,11 @@ [:chat-received-message/add (console-chat/console-message {:message-id message-id :content content - :content-type const/text-content-type})]) + :content-type constants/text-content-type})]) (def console-commands->fx - {"password" - (fn [{:keys [db]} {:keys [params]}] - (accounts-events/create-account db (:password params))) - - "faucet" - (fn [{:keys [db random-id]} {:keys [params id]}] + {"faucet" + (fn [{:keys [db random-id]} {:keys [params]}] (let [{:accounts/keys [accounts current-account-id]} db current-address (get-in accounts [current-account-id :address]) faucet-url (faucet-base-url->url (:url params))] @@ -64,7 +58,7 @@ (i18n/label :t/faucet-error)))}})) "debug" - (fn [{:keys [db random-id now] :as cofx} {:keys [params id]}] + (fn [{:keys [db random-id now]} {:keys [params]}] (let [debug? (= "On" (:mode params))] (-> {:db db} (accounts-events/account-update {:debug? debug? @@ -75,10 +69,10 @@ (console-chat/console-message {:message-id random-id :content (i18n/label :t/debug-enabled) - :content-type const/text-content-type})]] + :content-type constants/text-content-type})]] [[:stop-debugging]])))))}) (def commands-names (set (keys console-commands->fx))) (def commands-with-delivery-status - (disj commands-names "password" "faucet" "debug")) + (disj commands-names "faucet" "debug")) diff --git a/src/status_im/chat/events/receive_message.cljs b/src/status_im/chat/events/receive_message.cljs index a80848c501..093c2c4316 100644 --- a/src/status_im/chat/events/receive_message.cljs +++ b/src/status_im/chat/events/receive_message.cljs @@ -41,16 +41,6 @@ ;; regular non command message, we can add it right away (message-model/receive cofx message))))) -;; TODO janherich: get rid of this special case once they hacky app start-up sequence is refactored -(handlers/register-handler-fx - :chat-received-message/add-when-commands-loaded - message-model/receive-interceptors - (fn [{:keys [db] :as cofx} [{:keys [chat-id] :as message}]] - (if (and (:status-node-started? db) - (get-in db [:contacts/contacts chat-id :jail-loaded?])) - (message-model/receive cofx message) - {:dispatch-later [{:ms 400 :dispatch [:chat-received-message/add-when-commands-loaded message]}]}))) - ;; TODO(alwx): refactor this when status-im.commands.handlers.jail is refactored (handlers/register-handler-fx :chat-received-message/bot-response diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index 70a4a4ea5b..dea804334b 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -35,16 +35,11 @@ (defview chat-toolbar [public?] (letsubs [accounts [:get-accounts] - creating? [:get :accounts/creating-account?] {:keys [group-chat name chat-id]} [:get-current-chat]] [react/view [status-bar/status-bar] [toolbar/toolbar {} - (when-not creating? - (if (empty? accounts) - [toolbar/nav-clear-text {:handler #(re-frame/dispatch [:navigate-to-modal :recover-modal])} - (i18n/label :t/recover)] - toolbar/default-nav-back)) + toolbar/default-nav-back [toolbar-content/toolbar-content-view] [toolbar/actions [{:icon :icons/options :icon-opts {:color :black} diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index a9b465757a..2ef01424b7 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -9,7 +9,8 @@ [status-im.commands.utils :as commands-utils] [status-im.utils.datetime :as time] [status-im.utils.platform :as platform] - [status-im.i18n :as i18n])) + [status-im.i18n :as i18n] + [status-im.constants :as const])) (reg-sub :get-chats :chats) @@ -51,11 +52,15 @@ platform/ios? kb-height :default 0))) +(defn active-chats [[_ chat]] + ;;TODO (andrey) console should be shown in dev mode only, will be done soon + (and (:is-active chat))) ;(not= const/console-chat-id (:chat-id chat)))) + (reg-sub :get-active-chats :<- [:get-chats] (fn [chats] - (into {} (filter (comp :is-active second)) chats))) + (into {} (filter active-chats chats)))) (reg-sub :get-chat diff --git a/src/status_im/chat/views/toolbar_content.cljs b/src/status_im/chat/views/toolbar_content.cljs index b87e25d1fc..a501becaf8 100644 --- a/src/status_im/chat/views/toolbar_content.cljs +++ b/src/status_im/chat/views/toolbar_content.cljs @@ -66,11 +66,9 @@ show-actions? [:get-current-chat-ui-prop :show-actions?] accounts [:get-accounts] contact [:get-in [:contacts/contacts @chat-id]] - sync-state [:sync-state] - creating? [:get :accounts/creating-account?]] + sync-state [:sync-state]] [react/view (st/chat-name-view (or (empty? accounts) - show-actions? - creating?)) + show-actions?)) (let [chat-name (if (string/blank? name) (generate-gfy public-key) (or (i18n/get-contact-translated chat-id :name name) diff --git a/src/status_im/data_store/realm/schemas/base/core.cljs b/src/status_im/data_store/realm/schemas/base/core.cljs index 3070c9550b..f140d9021a 100644 --- a/src/status_im/data_store/realm/schemas/base/core.cljs +++ b/src/status_im/data_store/realm/schemas/base/core.cljs @@ -4,7 +4,8 @@ [status-im.data-store.realm.schemas.base.v3.core :as v3] [status-im.data-store.realm.schemas.base.v4.core :as v4] [status-im.data-store.realm.schemas.base.v5.core :as v5] - [status-im.data-store.realm.schemas.base.v6.core :as v6])) + [status-im.data-store.realm.schemas.base.v6.core :as v6] + [status-im.data-store.realm.schemas.base.v7.core :as v7])) ;; put schemas ordered by version (def schemas [{:schema v1/schema @@ -24,4 +25,7 @@ :migration v5/migration} {:schema v6/schema :schemaVersion 6 - :migration v6/migration}]) + :migration v6/migration} + {:schema v7/schema + :schemaVersion 7 + :migration v7/migration}]) diff --git a/src/status_im/data_store/realm/schemas/base/v7/account.cljs b/src/status_im/data_store/realm/schemas/base/v7/account.cljs new file mode 100644 index 0000000000..7dd531ef1e --- /dev/null +++ b/src/status_im/data_store/realm/schemas/base/v7/account.cljs @@ -0,0 +1,26 @@ +(ns status-im.data-store.realm.schemas.base.v7.account) + +(def schema {:name :account + :primaryKey :address + :properties {:address :string + :public-key :string + :updates-public-key {:type :string + :optional true} + :updates-private-key {:type :string + :optional true} + :name {:type :string :optional true} + :email {:type :string :optional true} + :status {:type :string :optional true} + :debug? {:type :bool :default false} + :photo-path :string + :signing-phrase {:type :string} + :last-updated {:type :int :default 0} + :last-sign-in {:type :int :default 0} + :signed-up? {:type :bool + :default false} + :network :string + :networks {:type :list + :objectType :network} + :wnode :string + :settings {:type :string} + :sharing-usage-data? {:type :bool :default false}}}) \ No newline at end of file diff --git a/src/status_im/data_store/realm/schemas/base/v7/core.cljs b/src/status_im/data_store/realm/schemas/base/v7/core.cljs new file mode 100644 index 0000000000..db2c059636 --- /dev/null +++ b/src/status_im/data_store/realm/schemas/base/v7/core.cljs @@ -0,0 +1,10 @@ +(ns status-im.data-store.realm.schemas.base.v7.core + (:require [status-im.data-store.realm.schemas.base.v4.network :as network] + [status-im.data-store.realm.schemas.base.v7.account :as account] + [taoensso.timbre :as log])) + +(def schema [network/schema + account/schema]) + +(defn migration [old-realm new-realm] + (log/debug "migrating v7 base database: " old-realm new-realm)) diff --git a/src/status_im/react_native/resources.cljs b/src/status_im/react_native/resources.cljs index 624e7b7d68..99c146ef20 100644 --- a/src/status_im/react_native/resources.cljs +++ b/src/status_im/react_native/resources.cljs @@ -18,8 +18,10 @@ :ethcro (js/require "./resources/images/contacts/ethcro.png")}) (def assets - {:ethereum (js/require "./resources/images/assets/ethereum.png")}) + {:ethereum (js/require "./resources/images/assets/ethereum.png")}) (def ui - {:empty-hashtags (js/require "./resources/images/ui/empty-hashtags.png") - :empty-recent (js/require "./resources/images/ui/empty-recent.png")}) + {:empty-hashtags (js/require "./resources/images/ui/empty-hashtags.png") + :empty-recent (js/require "./resources/images/ui/empty-recent.png") + :analytics-image (js/require "./resources/images/ui/analytics-image.png") + :welcome-image (js/require "./resources/images/ui/welcome-image.png")}) \ No newline at end of file diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 81b69d5dab..90932e4447 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -28,6 +28,26 @@ :camera-access-error "To grant the required camera permission, please go to your system settings and make sure that Status > Camera is selected." :photos-access-error "To grant the required photos permission, please go to your system settings and make sure that Status > Photos is selected." + ;;sign in + :intro-text "Status is an open source decentralized chat and Ethereum browser" + :intro-text-description "Status is built with the help of the community to help you use all the benefits of decentralized web in your mobile phone" + :create-account "Create account" + :already-have-account "I already have an account" + :creating-your-account "Creating your account on the blockchain. We can't touch it, no one can, except for you!" + :password-placeholder "Type your password" + :password-placeholder2 "Confirm your password" + :name-placeholder "Enter your full name…" + :password_error1 "Password confirmation doesn't match password." + :password-description "You'll need this password to open the app, confirm transactions and whenever you need to regain access on a new device or install." + :name-description "This will be the name everybody who uses Status will see. You can change it later." + :other-accounts "Other accounts" + :sign-you-in "Signing you in…" + + :help-improve "Help improve Status \n by sharing usage data" + :help-improve-description "We strive to collect only what we need to understand how and where we can improve Status" + :share-usage-data "Share usage data" + :dont-want-to-share "No, i don't want to share" + ;;drawer :switch-users "Switch users" :logout-title "Log out?" @@ -37,6 +57,9 @@ ;;home :home "Home" + :no-recent-chats "There are no recent Chats or DApps here yet.\nUse the “Plus” button to see the list of Dapps or discover people to chat with" + :welcome-to-status "Welcome to Status" + :welcome-to-status-description "Here you can chat with people in a secure private chat, browse and interact with DApps. Use the “Plus” icon above to explore Status" ;;chat :is-typing "is typing" @@ -271,6 +294,7 @@ :password "Password" :sign-in-to-status "Sign in to Status" :sign-in "Sign in" + :sign-in-to-another "Sign in to another account" :wrong-password "Wrong password" :enter-password "Enter password" @@ -278,10 +302,13 @@ :passphrase "Passphrase" :recover "Recover" :twelve-words-in-correct-order "12 words in correct order" + :enter-12-words "Enter the 12 words of your seed phrase" + ;;accounts :recover-access "Recover access" :create-new-account "Create new account" + :add-existing-account "Add existing account" ;;wallet-qr-code :done "Done" diff --git a/src/status_im/ui/components/action_button/styles.cljs b/src/status_im/ui/components/action_button/styles.cljs index 0f0b19e004..74fa0f7879 100644 --- a/src/status_im/ui/components/action_button/styles.cljs +++ b/src/status_im/ui/components/action_button/styles.cljs @@ -31,7 +31,6 @@ :android {:padding-top 8 :padding-bottom 8}}) - (def action-button-label-disabled (merge action-button-label {:color styles/color-gray4})) diff --git a/src/status_im/ui/components/colors.cljs b/src/status_im/ui/components/colors.cljs index 5191c671b6..00a8a01202 100644 --- a/src/status_im/ui/components/colors.cljs +++ b/src/status_im/ui/components/colors.cljs @@ -1,4 +1,5 @@ -(ns status-im.ui.components.colors) +(ns status-im.ui.components.colors + (:require [clojure.string :as string])) (def white "#ffffff") (def white-light-transparent "rgba(255, 255, 255, 0.1)") ;; Used as icon background color for a dark foreground @@ -7,11 +8,19 @@ (def black "#000000") ;; Used as the default text color (def black-transparent "#00000020") ;; Used as background color for rounded button on dark background (def gray "#939ba1") ;; Used as a background for a light foreground and as section header and secondary text color +(def gray-icon "#6e777e") ;; Used for forward icon in accounts (def gray-light "#e8ebec") ;; Used as divider color (def gray-lighter "#eef2f5") ;; Used as a background or shadow -(def blue "#4360df") ;; Used as main wallet color -(def blue-transparent "rgba(67, 96, 223, 0.10)") ;;used as shadow for blue elements +(def blue "#4360df") ;; Used as main wallet color, and ios home add button (def red "#ff2d55") ;; Used to highlight errors or "dangerous" actions +(def red-light "#ffe5ea") ;; error tooltip (def text-light-gray "#212121") ;; Used for labels (home items) +(defn alpha [hex opacity] + (let [hex (string/replace hex #"#" "") + r (js/parseInt (subs hex 0 2) 16) + g (js/parseInt (subs hex 2 4) 16) + b (js/parseInt (subs hex 4 6) 16)] + (str "rgba(" r "," g "," b "," opacity")"))) + (def text black) diff --git a/src/status_im/ui/components/common/common.cljs b/src/status_im/ui/components/common/common.cljs index 86b641ff12..672549431d 100644 --- a/src/status_im/ui/components/common/common.cljs +++ b/src/status_im/ui/components/common/common.cljs @@ -7,7 +7,9 @@ [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.react :as react] [status-im.utils.ethereum.core :as ethereum] - [status-im.utils.platform :as platform])) + [status-im.utils.platform :as platform] + [status-im.ui.components.icons.vector-icons :as icons] + [status-im.ui.components.colors :as colors])) (defn top-shadow [] (when platform/android? @@ -38,7 +40,7 @@ [react/view styles/list-header-footer-spacing]) (defn list-header [] - [react/view styles/list-header-footer-spacing]) + [react/view styles/list-header-footer-spacing]) (defn form-title [label & [{:keys [count-value]}]] [react/view @@ -63,3 +65,25 @@ (if (ethereum/testnet? network-id) (i18n/label :t/testnet-text {:testnet (get-in ethereum/chains [(ethereum/chain-id->chain-keyword network-id) :name] "Unknown")}) (i18n/label :t/mainnet-text))]]])) + +(defn logo + ([] (logo nil)) + ([{:keys [size icon-size shadow?] :or {shadow? true}}] + [react/view {:style (styles/logo-container size shadow?)} + [icons/icon :icons/logo (styles/logo icon-size)]])) + +(defn bottom-button [{:keys [label disabled? on-press forward?]}] + [react/touchable-highlight {:on-press on-press :disabled disabled?} + [react/view (styles/bottom-button disabled?) + [react/text {:style styles/bottom-button-label + :uppercase? platform/android?} + (or label (i18n/label :t/next))] + (when forward? + [icons/icon :icons/forward {:color colors/blue}])]]) + +(defn button [{:keys [on-press label background? style] :or {background? true}}] + [react/touchable-highlight {:on-press on-press} + [react/view {:style (styles/button style background?)} + [react/text {:uppercase? platform/android? + :style styles/button-label} + label]]]) \ No newline at end of file diff --git a/src/status_im/ui/components/common/styles.cljs b/src/status_im/ui/components/common/styles.cljs index c5ab4a59c1..a175a69bd5 100644 --- a/src/status_im/ui/components/common/styles.cljs +++ b/src/status_im/ui/components/common/styles.cljs @@ -1,5 +1,5 @@ (ns status-im.ui.components.common.styles - (:require-macros [status-im.utils.styles :refer [defstyle]]) + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) (:require [status-im.ui.components.styles :as styles] [status-im.ui.components.colors :as colors])) @@ -50,15 +50,6 @@ :padding-bottom 17 :margin-top 8}}) -(defstyle form-title-extend-container - {:ios {:margin-top 16 - :background-color colors/white} - :android {:margin-top 8 - :background-color colors/gray-lighter}}) - -(def form-title-extend-button - {:padding 16}) - (defstyle form-title {:flex-shrink 1 :ios {:color styles/text1-color @@ -109,3 +100,51 @@ :color colors/blue :ios {:font-size 15} :android {:font-size 14}}) + +(defstyle logo-shaddow + {:ios {:shadowColor colors/black + :shadowOffset {:height 5} + :shadowRadius 10 + :shadowOpacity 0.14} + :android {:elevation 2}}) + +(defn logo-container [size shadow?] + (merge + {:width size + :height size + :border-radius size + :background-color colors/blue + :align-items :center + :justify-content :center} + (when shadow? + logo-shaddow))) + +(defn logo [icon-size] + {:color :white + :width icon-size + :height icon-size}) + +(defn bottom-button [disabled?] + {:flex-direction :row + :align-items :center + :opacity (if disabled? 0.4 1)}) + +(def bottom-button-label + {:font-size 15 + :letter-spacing -0.2 + :color colors/blue}) + +(defn button [style background?] + (merge + {:padding-vertical 12 + :padding-horizontal 42 + :border-radius 8} + style + (when background? + {:background-color (colors/alpha colors/blue 0.1)}))) + +(def button-label + {:font-size 15 + :letter-spacing -0.2 + :text-align :center + :color colors/blue}) diff --git a/src/status_im/ui/components/icons/vector_icons.cljs b/src/status_im/ui/components/icons/vector_icons.cljs index d18c75a164..3dd07831dd 100644 --- a/src/status_im/ui/components/icons/vector_icons.cljs +++ b/src/status_im/ui/components/icons/vector_icons.cljs @@ -77,7 +77,8 @@ :icons/network (slurp/slurp-svg "./resources/icons/network.svg") :icons/wnode (slurp/slurp-svg "./resources/icons/wnode.svg") :icons/refresh (slurp/slurp-svg "./resources/icons/refresh.svg") - :icons/newchat (slurp/slurp-svg "./resources/icons/newchat.svg")}) + :icons/newchat (slurp/slurp-svg "./resources/icons/newchat.svg") + :icons/logo (slurp/slurp-svg "./resources/icons/logo.svg")}) (defn normalize-property-name [n] (if (= n :icons/options) @@ -86,25 +87,28 @@ (defn icon ([name] (icon name nil)) - ([name {:keys [color container-style style accessibility-label] - :or {accessibility-label :icon}}] + ([name {:keys [color container-style style accessibility-label width height] + :or {accessibility-label :icon}}] ^{:key name} [react/view {:style container-style :accessibility-label accessibility-label} (if-let [icon-fn (get icons (normalize-property-name name))] - (icon-fn - (cond - (keyword? color) - (case color - :dark styles/icon-dark-color - :gray styles/icon-gray-color - :blue styles/color-light-blue - :active styles/color-blue4 - :white styles/color-white - :red styles/icon-red-color - styles/icon-dark-color) - (string? color) - color - :else - styles/icon-dark-color)) + (let [icon-vec (icon-fn + (cond + (keyword? color) + (case color + :dark styles/icon-dark-color + :gray styles/icon-gray-color + :blue styles/color-light-blue + :active styles/color-blue4 + :white styles/color-white + :red styles/icon-red-color + styles/icon-dark-color) + (string? color) + color + :else + styles/icon-dark-color))] + (if width + (update icon-vec 1 assoc :width width :height height) + icon-vec)) (throw (js/Error. (str "Unknown icon: " name))))])) diff --git a/src/status_im/ui/components/react.cljs b/src/status_im/ui/components/react.cljs index cffae9dd63..071ff55d6a 100644 --- a/src/status_im/ui/components/react.cljs +++ b/src/status_im/ui/components/react.cljs @@ -242,11 +242,10 @@ :wallet-send-transaction-request :wallet-transaction-fee :contact-code) styles/color-blue4 - (:accounts - :login) styles/color-blue2 (:qr-viewer :recipient-qr-code) "#2f3031" - (:wallet-transactions-filter + (:accounts :login + :wallet-transactions-filter :contact-list-modal) styles/color-white :transparent)}) children (cond-> children diff --git a/src/status_im/ui/components/status_bar/view.cljs b/src/status_im/ui/components/status_bar/view.cljs index 8471f9bed1..33d86b26f2 100644 --- a/src/status_im/ui/components/status_bar/view.cljs +++ b/src/status_im/ui/components/status_bar/view.cljs @@ -2,7 +2,7 @@ (:require [status-im.ui.components.react :as react] [status-im.ui.components.status-bar.styles :as styles])) -(defn status-bar [{type :type}] +(defn status-bar [{:keys [type flat?]}] (let [[status-bar-style view-style] (case type :main [styles/status-bar-main styles/view-main] @@ -15,5 +15,5 @@ :wallet-tab [styles/status-bar-wallet-tab styles/view-wallet-tab] [styles/status-bar-default styles/view-default])] [react/view - [react/status-bar status-bar-style] - [react/view {:style view-style}]])) + [react/status-bar (cond-> status-bar-style flat? (assoc :elevation 0))] + [react/view {:style (cond-> view-style flat? (assoc :elevation 0))}]])) diff --git a/src/status_im/ui/components/styles.cljs b/src/status_im/ui/components/styles.cljs index 0c12482e83..6c97d39bc5 100644 --- a/src/status_im/ui/components/styles.cljs +++ b/src/status_im/ui/components/styles.cljs @@ -99,10 +99,10 @@ :height 24}) (def icon-add - {:width 14 - :height 14 + {:width 24 + :height 24 :color colors/blue - :container-style {:background-color colors/blue-transparent + :container-style {:background-color (colors/alpha colors/blue 0.12) :border-radius 32 :width 32 :height 32 diff --git a/src/status_im/ui/components/text_input/styles.cljs b/src/status_im/ui/components/text_input/styles.cljs new file mode 100644 index 0000000000..8a9f4d3467 --- /dev/null +++ b/src/status_im/ui/components/text_input/styles.cljs @@ -0,0 +1,27 @@ +(ns status-im.ui.components.text-input.styles + (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) + (:require [status-im.ui.components.colors :as colors])) + +(def label + {:font-size 14 + :letter-spacing -0.2 + :color colors/black}) + +(defn input-container [height] + {:padding 16 + :justify-content :center + :margin-vertical 8 + :height (or height 52) + :border-radius 8 + :background-color colors/gray-lighter}) + +(def input + {:font-size 15 + :letter-spacing -0.2 + :color colors/black + :padding 0}) + +(def error + {:bottom-value -20 + :color colors/red-light + :font-size 12}) \ No newline at end of file diff --git a/src/status_im/ui/components/text_input/view.cljs b/src/status_im/ui/components/text_input/view.cljs new file mode 100644 index 0000000000..2be1dccbc6 --- /dev/null +++ b/src/status_im/ui/components/text_input/view.cljs @@ -0,0 +1,20 @@ +(ns status-im.ui.components.text-input.view + (:require [status-im.ui.components.react :as react] + [status-im.ui.components.text-input.styles :as styles] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.tooltip.views :as tooltip])) + +(defn text-input-with-label [{:keys [label error style height] :as props}] + [react/view + [react/text {:style styles/label} + label] + [react/view {:style (styles/input-container height)} + [react/text-input + (merge + {:style (merge styles/input style) + :placeholder-text-color colors/gray + :auto-focus true + :auto-capitalize :none} + (dissoc props :style :height))]] + (when error + [tooltip/tooltip error styles/error])]) diff --git a/src/status_im/ui/components/text_input_with_label/animation.cljs b/src/status_im/ui/components/text_input_with_label/animation.cljs deleted file mode 100644 index f7fc5b1fca..0000000000 --- a/src/status_im/ui/components/text_input_with_label/animation.cljs +++ /dev/null @@ -1,32 +0,0 @@ -(ns status-im.ui.components.text-input-with-label.animation - (:require [status-im.ui.components.animation :as animation] - [clojure.string :as string])) - -(def anim-duration 200) - -(defn animate-underline [underline-width to-line-width underline-height to-line-height] - (let [anim (animation/parallel [(animation/timing underline-width {:toValue to-line-width - :duration anim-duration}) - (animation/timing underline-height {:toValue to-line-height - :duration anim-duration})])] - (animation/start anim))) - -(defn text-input-on-focus [{:keys [underline-width underline-max-width* underline-height underline-max-height]}] - (animate-underline underline-width @underline-max-width* underline-height underline-max-height)) - -(defn text-input-on-blur [{:keys [underline-width underline-height]}] - (animate-underline underline-width 0 underline-height 1)) - -(defn animate-label [text {:keys [value* label-top label-font-size - label-top-top label-top-bottom label-font-size-top label-font-size-bottom]}] - (when (or (string/blank? text) (string/blank? @value*)) - (let [was-blank? (string/blank? @value*) - anim (animation/parallel [(animation/timing label-top {:toValue (if was-blank? - label-top-top - label-top-bottom) - :duration anim-duration}) - (animation/timing label-font-size {:toValue (if was-blank? - label-font-size-top - label-font-size-bottom) - :duration anim-duration})])] - (animation/start anim)))) \ No newline at end of file diff --git a/src/status_im/ui/components/text_input_with_label/styles.cljs b/src/status_im/ui/components/text_input_with_label/styles.cljs deleted file mode 100644 index 2e0ab1e801..0000000000 --- a/src/status_im/ui/components/text_input_with_label/styles.cljs +++ /dev/null @@ -1,68 +0,0 @@ -(ns status-im.ui.components.text-input-with-label.styles - (:require-macros [status-im.utils.styles :refer [defstyle defnstyle]]) - (:require [status-im.utils.platform :as platform] - [status-im.ui.components.styles :as common])) - -(defstyle text-input - {:placeholder "" - :android {:padding-top 0 - :padding-bottom 0 - :padding-left 0 - :margin-top 26 - :margin-bottom 4 - :font-size 16} - :ios {:margin-top 24 - :margin-bottom 6 - :font-size 17 - :letter-spacing -0.2}}) - -(defstyle content-height - {:android {:height 24} - :ios {:height 26}}) - -(defstyle component-container - {:margin-left 16 - :android {:min-height 76} - :ios {:min-height 78}}) - -(defnstyle label-animated-text [{:keys [label-top label-font-size]}] - {:position :absolute - :top label-top - :font-size label-font-size - :color common/color-gray4 - :ios {:letter-spacing -0.2}}) - -(defstyle description-text - {:color common/color-gray4 - :android {:margin-top 6 - :font-size 12} - :ios {:margin-top 4 - :font-size 14 - :letter-spacing -0.2}}) - -(defstyle error-text - {:color common/color-red-2 - :android {:margin-top 6 - :font-size 12} - :ios {:margin-top 4 - :font-size 14 - :letter-spacing -0.2}}) - -(defn underline-blured [error] - {:background-color (if error common/color-red-2 common/color-light-gray2) - :align-items :center}) - -(defn underline-focused [underline-width underline-height error] - {:height underline-height - :width underline-width - :background-color (if error common/color-red-2 common/color-light-blue)}) - -(def label-top-top (if platform/ios? 6 6)) - -(def label-top-bottom (if platform/ios? 26 26)) - -(def label-font-size-top (if platform/ios? 14 12)) - -(def label-font-size-bottom (if platform/ios? 17 16)) - -(def underline-max-height (if platform/ios? 1 2)) diff --git a/src/status_im/ui/components/text_input_with_label/view.cljs b/src/status_im/ui/components/text_input_with_label/view.cljs deleted file mode 100644 index 141d715e47..0000000000 --- a/src/status_im/ui/components/text_input_with_label/view.cljs +++ /dev/null @@ -1,72 +0,0 @@ -(ns status-im.ui.components.text-input-with-label.view - (:require [reagent.core :as reagent] - [status-im.ui.components.animation :as animation] - [status-im.ui.components.text-input-with-label.animation :as label-animation] - [status-im.ui.components.react :as react] - [status-im.ui.components.text-input-with-label.styles :as styles] - [clojure.string :as string])) - -(defn get-init-props [{:keys [default-value]}] - (let [blank? (string/blank? default-value)] - {:underline-width (animation/create-value 0) - :underline-height (animation/create-value 1) - :label-top (animation/create-value (if blank? - styles/label-top-bottom - styles/label-top-top)) - :label-font-size (animation/create-value (if blank? - styles/label-font-size-bottom - styles/label-font-size-top)) - :label-top-top styles/label-top-top - :label-top-bottom styles/label-top-bottom - :label-font-size-top styles/label-font-size-top - :label-font-size-bottom styles/label-font-size-bottom - :underline-max-height styles/underline-max-height - :input-ref* (reagent/atom nil) - :value* (reagent/atom default-value) - :underline-max-width* (reagent/atom 0)})) - -(defn get-width [event] - (.-width (.-layout (.-nativeEvent event)))) - -(defn text-input-on-change-text [text props] - (label-animation/animate-label text props) - (reset! (:value* props) text)) - -(defn text-input-handlers [{:keys [on-focus on-blur on-change-text on-change - on-submit-editing max-height ref]} props] - {:ref #(do - (reset! (:input-ref* props) %) - (when ref (ref %))) - :on-submit-editing #(do - (.blur @(:input-ref* props)) - (when on-submit-editing (on-submit-editing))) - :on-focus #(do - (label-animation/text-input-on-focus props) - (when on-focus (on-focus))) - :on-blur #(do - (label-animation/text-input-on-blur props) - (when on-blur (on-blur))) - :on-change-text #(do - (text-input-on-change-text % props) - (when on-change-text (on-change-text %)))}) - -(defn text-input-with-label [options] - (let [props (get-init-props options)] - (fn [{:keys [label description error hide-underline? auto-expanding multiline] :as options}] - [react/view styles/component-container - [react/animated-text {:style (styles/label-animated-text props)} label] - [react/text-input (merge styles/text-input - (when-not (and auto-expanding multiline) - styles/content-height) - (dissoc options :label :description :error :auto-expanding :hide-underline?) - (text-input-handlers options props))] - (when-not hide-underline? - [react/view {:style (styles/underline-blured error) - :on-layout #(reset! (:underline-max-width* props) (get-width %))} - [react/animated-view {:style (styles/underline-focused (:underline-width props) - (:underline-height props) - error)}]]) - (cond error - [react/text {:style styles/error-text} error] - description - [react/text {:style styles/description-text} description])]))) diff --git a/src/status_im/ui/components/toolbar/styles.cljs b/src/status_im/ui/components/toolbar/styles.cljs index a6bac120f8..8512bf05dc 100644 --- a/src/status_im/ui/components/toolbar/styles.cljs +++ b/src/status_im/ui/components/toolbar/styles.cljs @@ -19,15 +19,13 @@ :android {:height 55} :ios {:height 56}}) -(defnstyle toolbar-nav-actions-container - [actions] +(def toolbar-nav-actions-container {:flex-direction :row :margin-left 4}) (defstyle toolbar-container - {:flex 1 - :android {:padding-left 18} - :ios {:align-items :center}}) + {:flex 1 + :align-items :center}) (def toolbar-title-container {:flex 1 @@ -38,15 +36,7 @@ {:color styles/text1-color :letter-spacing -0.2 :font-size 17 - :ios {:text-align "center"}}) - -(defstyle toolbar-border-container - {:ios {:background-color styles/color-white}}) - -(defstyle toolbar-border - {:ios {:height 1 - :background-color styles/color-gray5 - :opacity 0.5}}) + :text-align :center}) (def toolbar-actions {:flex 0 @@ -72,10 +62,6 @@ {:padding-vertical 16 :padding-horizontal 12}) -(def nav-item-text - {:padding-vertical 18 - :padding-horizontal 16}) - (defstyle item {:ios {:margin-horizontal 12 :margin-vertical 16} diff --git a/src/status_im/ui/components/toolbar/view.cljs b/src/status_im/ui/components/toolbar/view.cljs index 0cb6b89ff0..70b9925dcc 100644 --- a/src/status_im/ui/components/toolbar/view.cljs +++ b/src/status_im/ui/components/toolbar/view.cljs @@ -1,8 +1,6 @@ (ns status-im.ui.components.toolbar.view - (:require [reagent.core :as reagent] - [re-frame.core :as re-frame] + (:require [re-frame.core :as re-frame] [status-im.i18n :as i18n] - [status-im.ui.components.colors :as colors] [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.react :as react] @@ -110,21 +108,17 @@ (defn toolbar ([props nav-item content-item] (toolbar props nav-item content-item [actions [{:image :blank}]])) - ([{:keys [background-color style flat? title-centered?]} + ([{:keys [background-color style flat?]} nav-item content-item action-items] [react/view {:style (merge (styles/toolbar background-color flat?) style)} - ;; On iOS title must be centered. Current solution is a workaround and eventually this will be sorted out using flex - (when (or title-centered? platform/ios?) - [react/view styles/ios-content-item - content-item]) + [react/view styles/ios-content-item + content-item] (when nav-item - [react/view {:style (styles/toolbar-nav-actions-container 0)} + [react/view {:style styles/toolbar-nav-actions-container} nav-item]) - (if (or title-centered? platform/ios?) - [react/view components.styles/flex] - content-item) + [react/view components.styles/flex] action-items])) (defn simple-toolbar diff --git a/src/status_im/ui/components/tooltip/animations.cljs b/src/status_im/ui/components/tooltip/animations.cljs new file mode 100644 index 0000000000..a81a717189 --- /dev/null +++ b/src/status_im/ui/components/tooltip/animations.cljs @@ -0,0 +1,12 @@ +(ns status-im.ui.components.tooltip.animations + (:require [status-im.ui.components.animation :as animation])) + +(defn animate-tooltip [bottom-value bottom-anim-value opacity-value] + (fn [] + (animation/start + (animation/parallel + [(animation/timing opacity-value {:toValue 1 + :duration 500}) + (animation/timing bottom-anim-value {:toValue (- bottom-value 10) + :easing (.bezier (animation/easing) 0.685, 0.000, 0.025, 1.185) + :duration 500})])))) \ No newline at end of file diff --git a/src/status_im/ui/components/tooltip/styles.cljs b/src/status_im/ui/components/tooltip/styles.cljs new file mode 100644 index 0000000000..0c2dde09a1 --- /dev/null +++ b/src/status_im/ui/components/tooltip/styles.cljs @@ -0,0 +1,31 @@ +(ns status-im.ui.components.tooltip.styles + (:require [status-im.ui.components.styles :as styles])) + +(def tooltip-container + {:position :absolute + :align-items :center + :left 0 + :right 0 + :top 0}) + +(defn tooltip-animated [bottom-value opacity-value] + {:position :absolute + :align-items :center + :left 0 + :right 0 + :bottom bottom-value + :opacity opacity-value}) + +(defn tooltip-text-container [color] + {:padding-horizontal 16 + :padding-vertical 9 + :background-color color + :border-radius 8}) + +(defn tooltip-text [font-size] + {:color styles/color-red-2 + :font-size font-size}) + +(def tooltip-triangle + {:width 16 + :height 8}) \ No newline at end of file diff --git a/src/status_im/ui/components/tooltip/views.cljs b/src/status_im/ui/components/tooltip/views.cljs new file mode 100644 index 0000000000..778bdb57c3 --- /dev/null +++ b/src/status_im/ui/components/tooltip/views.cljs @@ -0,0 +1,17 @@ +(ns status-im.ui.components.tooltip.views + (:require-macros [status-im.utils.views :as views]) + (:require [status-im.ui.components.animation :as animation] + [status-im.ui.components.tooltip.animations :as animations] + [status-im.ui.components.react :as react] + [status-im.ui.components.icons.vector-icons :as vector-icons] + [status-im.ui.components.tooltip.styles :as styles])) + +(views/defview tooltip [label & [{:keys [bottom-value color font-size] :or {bottom-value -30 color :white font-size 15}}]] + (views/letsubs [bottom-anim-value (animation/create-value bottom-value) + opacity-value (animation/create-value 0)] + {:component-did-mount (animations/animate-tooltip bottom-value bottom-anim-value opacity-value)} + [react/view styles/tooltip-container + [react/animated-view {:style (styles/tooltip-animated bottom-value opacity-value)} + [react/view (styles/tooltip-text-container color) + [react/text {:style (styles/tooltip-text font-size)} label]] + [vector-icons/icon :icons/tooltip-triangle {:color color :style styles/tooltip-triangle}]]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/create/navigation.cljs b/src/status_im/ui/screens/accounts/create/navigation.cljs new file mode 100644 index 0000000000..57ec659a56 --- /dev/null +++ b/src/status_im/ui/screens/accounts/create/navigation.cljs @@ -0,0 +1,9 @@ +(ns status-im.ui.screens.accounts.create.navigation + (:require [status-im.ui.screens.navigation :as nav])) + +(defmethod nav/preload-data! :create-account + [db] + (update db :accounts/create + #(-> % + (assoc :step :enter-password) + (dissoc :password :password-confirm :name :error)))) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/create/styles.cljs b/src/status_im/ui/screens/accounts/create/styles.cljs new file mode 100644 index 0000000000..bb157844fa --- /dev/null +++ b/src/status_im/ui/screens/accounts/create/styles.cljs @@ -0,0 +1,58 @@ +(ns status-im.ui.screens.accounts.create.styles + (:require [status-im.ui.components.colors :as colors])) + +(def create-account-view + {:flex 1 + :background-color colors/white}) + +(def account-creating-view + {:flex 1 + :padding-horizontal 14}) + +(def account-creating-logo-container + {:margin-top 37 + :align-items :center}) + +(def account-creating-logo + {:size 82 + :icon-size 34}) + +(def account-creating-indicatior + {:flex 1 + :align-items :center + :justify-content :center + :margin-bottom 100}) + +(def account-creating-text + {:font-size 14 + :line-height 21 + :letter-spacing -0.2 + :text-align :center + :color colors/black + :margin-top 16}) + +(def logo-container + {:position :absolute + :top 37 + :left 0 + :right 0 + :align-items :center}) + +(def logo + {:size 82 + :icon-size 34}) + +(def input-container + {:margin-horizontal 16 + :margin-top 105}) + +(def input-description + {:font-size 14 + :letter-spacing -0.2 + :color colors/gray + :line-height 21}) + +(def bottom-container + {:flex-direction :row + :margin-horizontal 12 + :margin-vertical 15}) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/create/views.cljs b/src/status_im/ui/screens/accounts/create/views.cljs new file mode 100644 index 0000000000..50d0603162 --- /dev/null +++ b/src/status_im/ui/screens/accounts/create/views.cljs @@ -0,0 +1,85 @@ +(ns status-im.ui.screens.accounts.create.views + (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require [status-im.ui.components.react :as react] + [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.i18n :as i18n] + [re-frame.core :as re-frame] + [status-im.ui.components.styles :as components.styles] + [status-im.ui.components.toolbar.actions :as actions] + [status-im.ui.components.react :as components] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.components.text-input.view :as text-input] + [status-im.ui.screens.accounts.create.styles :as styles])) + +(def steps + {:enter-password {:input-key :password + :input-label (i18n/label :t/password) + :input-placeholder (i18n/label :t/password-placeholder) + :input-description (i18n/label :t/password-description)} + :confirm-password {:input-key :password-confirm + :input-label (i18n/label :t/confirm) + :input-placeholder (i18n/label :t/password-placeholder2) + :input-description (i18n/label :t/password-description)} + :account-creating nil + :enter-name {:input-key :name + :input-label (i18n/label :t/name) + :input-placeholder (i18n/label :t/name-placeholder) + :input-description (i18n/label :t/name-description)}}) + +(defn next-step [step password password-confirm] + (case step + :enter-password (re-frame/dispatch [:set-in [:accounts/create :step] :confirm-password]) + :confirm-password (if (= password password-confirm) + (re-frame/dispatch [:create-account]) + (re-frame/dispatch [:set-in [:accounts/create :error] (i18n/label :t/password_error1)])) + :enter-name (re-frame/dispatch [:account-set-name]))) + +(defn step-back [step] + (case step + :enter-password (re-frame/dispatch [:navigate-back]) + :confirm-password (re-frame/dispatch [:reset-account-creation]))) + +(defview input [step error] + [text-input/text-input-with-label + {:label (get-in steps [step :input-label]) + :placeholder (get-in steps [step :input-placeholder]) + :on-change-text #(re-frame/dispatch [:set-in [:accounts/create (get-in steps [step :input-key])] %]) + :secure-text-entry (boolean (#{:enter-password :confirm-password} step)) + :error error}]) + +(defview create-account [] + (letsubs [step [:get-in [:accounts/create :step]] + next-enabled? [:get-account-creation-next-enabled?] + error [:get-in [:accounts/create :error]] + password [:get-in [:accounts/create :password]] + password-confirm [:get-in [:accounts/create :password-confirm]]] + [react/keyboard-avoiding-view {:style styles/create-account-view} + [status-bar/status-bar {:flat? true}] + (when (= :account-creating step) + [react/view styles/account-creating-view + [react/view styles/account-creating-logo-container + [components.common/logo styles/account-creating-logo]] + [react/view {:style styles/account-creating-indicatior} + [components/activity-indicator {:animating true}] + [react/text {:style styles/account-creating-text} + (i18n/label :t/creating-your-account)]]]) + (when (#{:enter-password :confirm-password :enter-name} step) + [react/view components.styles/flex + [toolbar/toolbar {:flat? true} (when (#{:enter-password :confirm-password} step) + (toolbar/nav-button (actions/back #(step-back step)))) nil] + [react/view {:style styles/logo-container} + [components.common/logo styles/logo]] + ^{:key (str "step" step)} + [react/view components.styles/flex + [react/view {:style styles/input-container} + [input step error] + [react/text {:style styles/input-description} + (get-in steps [step :input-description])]] + [react/view {:style components.styles/flex}] + [react/view {:style styles/bottom-container} + [react/view {:style components.styles/flex}] + [components.common/bottom-button + {:forward? true + :disabled? (not next-enabled?) + :on-press #(next-step step password password-confirm)}]]]])])) diff --git a/src/status_im/ui/screens/accounts/db.cljs b/src/status_im/ui/screens/accounts/db.cljs index a427f2b79c..fe5da47c53 100644 --- a/src/status_im/ui/screens/accounts/db.cljs +++ b/src/status_im/ui/screens/accounts/db.cljs @@ -2,7 +2,13 @@ (:require-macros [status-im.utils.db :refer [allowed-keys]]) (:require [cljs.spec.alpha :as spec] status-im.utils.db - status-im.ui.screens.network-settings.db)) + status-im.ui.screens.network-settings.db + [status-im.constants :as const])) + +(defn valid-length? [password] + (>= (count password) const/min-password-length)) + +(spec/def ::password (spec/and :global/not-empty-string valid-length?)) (spec/def :account/address :global/address) (spec/def :account/name :global/not-empty-string) @@ -11,6 +17,7 @@ (spec/def :account/email nil?) (spec/def :account/signed-up? (spec/nilable boolean?)) (spec/def :account/last-updated (spec/nilable int?)) +(spec/def :account/last-sign-in (spec/nilable int?)) (spec/def :account/updates-private-key :global/not-empty-string) (spec/def :account/updates-public-key :global/not-empty-string) (spec/def :account/photo-path (spec/nilable string?)) @@ -21,6 +28,7 @@ (spec/def :account/wnode (spec/nilable string?)) (spec/def :account/settings (spec/nilable (spec/map-of keyword? any?))) (spec/def :account/signing-phrase :global/not-empty-string) +(spec/def :account/sharing-usage-data? (spec/nilable boolean?)) (spec/def :accounts/account (allowed-keys :req-un [:account/name :account/address :account/public-key @@ -28,16 +36,16 @@ :opt-un [:account/debug? :account/status :account/last-updated :account/updates-private-key :account/updates-public-key :account/email :account/signed-up? :account/network - :account/networks :account/settings :account/wnode])) + :account/networks :account/settings :account/wnode + :account/last-sign-in :account/sharing-usage-data?])) (spec/def :accounts/accounts (spec/nilable (spec/map-of :account/address :accounts/account))) -;;true during creating new account -(spec/def :accounts/account-creation? (spec/nilable boolean?)) -;;true during login just created account -(spec/def :accounts/creating-account? (spec/nilable boolean?)) ;;id of logged in account (spec/def :accounts/current-account-id (spec/nilable string?)) + +;;used during creating account +(spec/def :accounts/create (spec/nilable map?)) ;;used during recovering account (spec/def :accounts/recover (spec/nilable map?)) ;;used during logging diff --git a/src/status_im/ui/screens/accounts/events.cljs b/src/status_im/ui/screens/accounts/events.cljs index 2a144cdf85..9b0facf3bc 100644 --- a/src/status_im/ui/screens/accounts/events.cljs +++ b/src/status_im/ui/screens/accounts/events.cljs @@ -13,17 +13,8 @@ [status-im.ui.screens.accounts.statuses :as statuses] [status-im.utils.signing-phrase.core :as signing-phrase] [status-im.utils.gfycat.core :refer [generate-gfy]] - [status-im.utils.hex :as utils.hex])) - -;;;; Helper fns - -(defn create-account - "Takes db and password, creates map of effects describing account creation" - [db password] - {:db (assoc db :accounts/creating-account? true) - ::create-account password - ;; TODO(janherich): get rid of this shitty delayed dispatch once sending commands/msgs is refactored - :dispatch-later [{:ms 400 :dispatch [:account-generation-message]}]}) + [status-im.utils.hex :as utils.hex] + status-im.ui.screens.accounts.create.navigation)) ;;;; COFX @@ -90,6 +81,12 @@ :private updates-private-key}}}})))) ;;;; Handlers +(handlers/register-handler-fx + :create-account + (fn [{{:accounts/keys [create] :as db} :db}] + {:db (update db :accounts/create assoc :step :account-creating :error nil) + ::create-account (:password create)})) + (defn add-account "Takes db and new account, creates map of effects describing adding account to database and realm" [{:keys [network inbox/wnode] :networks/keys [networks] :as db} {:keys [address] :as account}] @@ -126,15 +123,7 @@ (log/debug "account-created") (when-not (str/blank? pubkey) (-> (add-account db account) - (assoc :dispatch-n [[:show-mnemonic mnemonic signing-phrase] - [:login-account normalized-address password true]])))))) - -(handlers/register-handler-fx - :create-new-account-handler - (fn [_ _] - {:dispatch-n [[:initialize-db] - [:load-accounts] - [:check-console-chat true]]})) + (assoc :dispatch [:login-account normalized-address password true])))))) (handlers/register-handler-fx :load-accounts @@ -204,3 +193,20 @@ ;; TODO(janherich): this is very strange and misleading, need to figure out why it'd necessary to update ;; account with network update when last update was more then week ago (account-update {:db db} nil))))) + +(handlers/register-handler-fx + :account-set-name + (fn [{{:accounts/keys [create] :as db} :db} _] + (-> {:db (assoc-in db [:accounts/create :show-welcome?] true) + :dispatch [:navigate-to-clean :usage-data]} + (account-update {:name (:name create)})))) + +(handlers/register-handler-fx + :update-sign-in-time + (fn [{db :db now :now} _] + (account-update {:db db} {:last-sign-in now}))) + +(handlers/register-handler-fx + :reset-account-creation + (fn [{db :db} _] + {:db (update db :accounts/create assoc :step :enter-password :password nil :password-confirm nil :error nil)})) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/login/events.cljs b/src/status_im/ui/screens/accounts/login/events.cljs index 78b31241ce..80c5eb2ff9 100644 --- a/src/status_im/ui/screens/accounts/login/events.cljs +++ b/src/status_im/ui/screens/accounts/login/events.cljs @@ -3,11 +3,9 @@ [re-frame.core :refer [dispatch reg-fx]] [status-im.utils.handlers :refer [register-handler-db register-handler-fx]] [taoensso.timbre :as log] - [status-im.chat.console :as console-chat] [status-im.utils.types :refer [json->clj]] [status-im.data-store.core :as data-store] [status-im.native-module.core :as status] - [status-im.constants :refer [console-chat-id]] [status-im.utils.config :as config] [status-im.utils.utils :as utils] [status-im.constants :as constants])) @@ -16,7 +14,6 @@ (reg-fx ::stop-node (fn [] (status/stop-node))) - (reg-fx ::login (fn [[address password]] @@ -94,11 +91,10 @@ (register-handler-fx :login-account (fn [{{:keys [network status-node-started?] :as db} :db} - [_ address password account-creation?]] + [_ address password]] (let [{account-network :network} (get-network-by-address db address) wnode (get-wnode-by-address db address) db' (-> db - (assoc :accounts/account-creation? account-creation?) (assoc :inbox/wnode wnode) (assoc-in [:accounts/login :processing] true)) wrap-fn (cond (not status-node-started?) @@ -113,32 +109,27 @@ (register-handler-fx :login-handler - (fn [{{:accounts/keys [account-creation?] :as db} :db} [_ login-result address]] + (fn [{db :db} [_ login-result address]] (let [data (json->clj login-result) error (:error data) success (zero? (count error)) db' (assoc-in db [:accounts/login :processing] false)] - (log/debug "Logging result: " login-result) - (merge - {:db (if success db' (assoc-in db' [:accounts/login :error] error))} - (when success - (log/debug "Logged in" (when account-creation? " new account") ":" address) - {::clear-web-data nil - ::change-account [address account-creation?]}))))) + (if success + {:db db' + ::clear-web-data nil + ::change-account [address]} + {:db (assoc-in db' [:accounts/login :error] error)})))) (register-handler-fx :change-account-handler - (fn [{db :db} [_ error address new-account?]] - (let [recover-in-progress? (:accounts/recover db)] - (if (nil? error) - {:db (dissoc db :accounts/login) - :dispatch-n [[:stop-debugging] - [:initialize-account - address - (when (or new-account? recover-in-progress?) - [[:chat-received-message/add console-chat/shake-your-phone-message]])] - [:navigate-to-clean :home] - (if new-account? - [:navigate-to-chat console-chat-id] - [:navigate-to :home])]} - (log/debug "Error changing acount: " error))))) + (fn [{{:keys [view-id] :as db} :db} [_ error address]] + (if (nil? error) + {:db (cond-> (dissoc db :accounts/login) + (= view-id :create-account) + (assoc-in [:accounts/create :step] :enter-name)) + :dispatch-n (concat + [[:stop-debugging] + [:initialize-account address]] + (when (not= view-id :create-account) + [[:navigate-to-clean :home]]))} + (log/debug "Error changing acount: " error)))) diff --git a/src/status_im/ui/screens/accounts/login/styles.cljs b/src/status_im/ui/screens/accounts/login/styles.cljs index 900f7d61ce..113b08a95f 100644 --- a/src/status_im/ui/screens/accounts/login/styles.cljs +++ b/src/status_im/ui/screens/accounts/login/styles.cljs @@ -1,46 +1,44 @@ (ns status-im.ui.screens.accounts.login.styles (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) - (:require [status-im.ui.components.styles :as st])) + (:require [status-im.ui.components.styles :as st] + [status-im.ui.components.colors :as colors])) (defstyle login-view {:flex 1 - :ios {:margin-top 10 - :margin-bottom 10} - :android {:margin-top 16 - :margin-bottom 16} :margin-horizontal 16}) (defstyle login-badge-container - {:background-color :white - :ios {:padding-top 16 - :height 150} - :android {:border-radius 4 - :padding-top 12 - :height 144}}) - -(defstyle sign-it-text - {:color :white - :ios {:font-size 17 - :letter-spacing -0.2} - :android {:font-size 16}}) - -(def sign-it-disabled-text - (merge sign-it-text - {:color st/color-gray2})) - -(def sign-in-button - {:background-color st/color-blue3 - :align-items :center - :justify-content :center - :height 52 - :border-radius 8}) + {:margin-top 24}) (def processing-view - {:position :absolute - :top 0 - :bottom 0 - :right 0 - :left 0 - :align-items :center - :justify-content :center - :background-color (str st/color-black "1A")}) + {:flex 1 + :align-items :center + :justify-content :center}) + +(def sign-you-in + {:margin-top 16 + :font-size 13 + :letter-spacing -0.2 + :color colors/text-light-gray}) + +(def bottom-button-container + {:flex-direction :row + :margin-horizontal 12 + :margin-vertical 15 + :align-items :center}) + +(def login-badge + {:align-items :center}) + +(def login-badge-image + {:width 56 + :height 56 + :border-radius 28}) + +(def login-badge-name + {:font-size 15 + :color colors/text-light-gray + :margin-top 8}) + +(def password-container + {:margin-top 24}) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/login/views.cljs b/src/status_im/ui/screens/accounts/login/views.cljs index 3ec67193e4..3d8b4ca5b0 100644 --- a/src/status_im/ui/screens/accounts/login/views.cljs +++ b/src/status_im/ui/screens/accounts/login/views.cljs @@ -1,28 +1,30 @@ (ns status-im.ui.screens.accounts.login.views (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [clojure.string :as string] - [re-frame.core :refer [dispatch dispatch-sync]] [status-im.ui.screens.accounts.styles :as ast] - [status-im.ui.screens.accounts.views :refer [account-badge]] - [status-im.ui.components.text-input-with-label.view :refer [text-input-with-label]] - [status-im.ui.components.status-bar.view :refer [status-bar]] + [status-im.ui.components.text-input.view :as text-input] + [status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.toolbar.actions :as act] - [status-im.ui.screens.accounts.login.styles :as st] + [status-im.ui.screens.accounts.login.styles :as styles] [status-im.ui.components.react :as react] [status-im.i18n :as i18n] - [status-im.ui.components.react :as components])) + [status-im.ui.components.react :as components] + [status-im.ui.components.common.common :as components.common] + [re-frame.core :as re-frame] + [cljs.spec.alpha :as spec] + [status-im.ui.screens.accounts.db :as db])) -(defn login-toolbar [] - [toolbar/toolbar {:background-color :transparent} - [toolbar/nav-button (act/back-white #(dispatch [:navigate-back]))] - [toolbar/content-title {:color :white} (i18n/label :t/sign-in-to-status)]]) - -(def password-text-input (atom nil)) +(defn login-toolbar [can-navigate-back?] + [toolbar/toolbar + nil + (when can-navigate-back? + [toolbar/nav-button act/default-back]) + [toolbar/content-title (i18n/label :t/sign-in-to-status)]]) (defn login-account [password-text-input address password] - (.blur @password-text-input) - (dispatch [:login-account address password])) + (.blur password-text-input) + (re-frame/dispatch [:login-account address password])) (defn- error-key [error] ;; TODO Improve selection logic when status-go provide an error code @@ -37,31 +39,53 @@ :else :t/unknown-status-go-error)) +(defn account-login-badge [photo-path name] + [react/view styles/login-badge + [react/image {:source {:uri (if (string/blank? photo-path) :avatar photo-path)} + :style styles/login-badge-image}] + [react/view + [react/text {:style styles/login-badge-name + :numberOfLines 1} + name]]]) + (defview login [] - (letsubs [{:keys [address photo-path name password error processing]} [:get :accounts/login]] - [react/view ast/accounts-container - [status-bar {:type :transparent}] - [login-toolbar] - [react/view st/login-view - [react/view st/login-badge-container - [account-badge address photo-path name] - [react/view {:height 8}] - [text-input-with-label {:ref #(reset! password-text-input %) - :label (i18n/label :t/password) - :auto-capitalize :none - :hide-underline? true - :on-change-text #(do - (dispatch [:set-in [:accounts/login :password] %]) - (dispatch [:set-in [:accounts/login :error] ""])) - :on-submit-editing #(login-account password-text-input address password) - :auto-focus true - :secure-text-entry true - :error (when (pos? (count error)) (i18n/label (error-key error)))}]] - (let [enabled? (pos? (count password))] - [react/view {:margin-top 16} - [react/touchable-highlight (if enabled? {:on-press #(login-account password-text-input address password)}) - [react/view st/sign-in-button - [react/text {:style (if enabled? st/sign-it-text st/sign-it-disabled-text)} (i18n/label :t/sign-in)]]]])] - (when processing - [react/view st/processing-view - [components/activity-indicator {:animating true}]])])) + (letsubs [{:keys [address photo-path name password error processing]} [:get :accounts/login] + can-navigate-back? [:can-navigate-back?] + password-text-input (atom nil)] + [react/keyboard-avoiding-view {:style ast/accounts-view} + [status-bar/status-bar] + [login-toolbar can-navigate-back?] + [components.common/separator] + [react/view styles/login-view + [react/view styles/login-badge-container + [account-login-badge photo-path name] + [react/view styles/password-container + [text-input/text-input-with-label + {:label (i18n/label :t/password) + :placeholder (i18n/label :t/password) + :ref #(reset! password-text-input %) + :auto-focus can-navigate-back? ;;this needed because keyboard overlays testfairy alert + :on-submit-editing #(login-account @password-text-input address password) + :on-change-text #(do + (re-frame/dispatch [:set-in [:accounts/login :password] %]) + (re-frame/dispatch [:set-in [:accounts/login :error] ""])) + :secure-text-entry true + :error (when (pos? (count error)) (i18n/label (error-key error)))}]]]] + [react/view styles/processing-view + (when processing + [components/activity-indicator {:animating true}]) + (when processing + [react/text {:style styles/sign-you-in} + (i18n/label :t/sign-you-in)])] + (when-not processing + [react/view {:style styles/bottom-button-container} + (when-not can-navigate-back? + [components.common/bottom-button + {:label (i18n/label :t/other-accounts) + :on-press #(re-frame/dispatch [:navigate-to-clean :accounts])}]) + [react/view {:style {:flex 1}}] + [components.common/bottom-button + {:forward? true + :label (i18n/label :t/sign-in) + :disabled? (not (spec/valid? ::db/password password)) + :on-press #(login-account @password-text-input address password)}]])])) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/recover/db.cljs b/src/status_im/ui/screens/accounts/recover/db.cljs index f21400fd5d..fee18ff9f7 100644 --- a/src/status_im/ui/screens/accounts/recover/db.cljs +++ b/src/status_im/ui/screens/accounts/recover/db.cljs @@ -1,10 +1,4 @@ (ns status-im.ui.screens.accounts.recover.db - (:require [cljs.spec.alpha :as spec] - [status-im.constants :as const] - status-im.utils.db)) - -(defn valid-length? [password] - (>= (count password) const/min-password-length)) + (:require [cljs.spec.alpha :as spec])) (spec/def ::passphrase :global/not-empty-string) -(spec/def ::password (spec/and :global/not-empty-string valid-length?)) diff --git a/src/status_im/ui/screens/accounts/recover/events.cljs b/src/status_im/ui/screens/accounts/recover/events.cljs index 20c06879a4..36d70f742e 100644 --- a/src/status_im/ui/screens/accounts/recover/events.cljs +++ b/src/status_im/ui/screens/accounts/recover/events.cljs @@ -1,55 +1,52 @@ (ns status-im.ui.screens.accounts.recover.events (:require status-im.ui.screens.accounts.recover.navigation - - [re-frame.core :refer [reg-fx inject-cofx dispatch]] + [re-frame.core :as re-frame] [status-im.native-module.core :as status] [status-im.ui.screens.accounts.events :as accounts-events] - [status-im.utils.types :refer [json->clj]] - [status-im.utils.identicon :refer [identicon]] - [taoensso.timbre :as log] - [clojure.string :as str] - [status-im.utils.handlers :refer [register-handler-fx]] - [status-im.utils.gfycat.core :refer [generate-gfy]] + [status-im.utils.types :as types] + [status-im.utils.identicon :as identicon] + [clojure.string :as string] + [status-im.utils.handlers :as handlers] + [status-im.utils.gfycat.core :as gfycat] [status-im.utils.signing-phrase.core :as signing-phrase] [status-im.utils.hex :as utils.hex])) ;;;; FX -(reg-fx +(re-frame/reg-fx ::recover-account-fx (fn [[passphrase password]] (status/recover-account - (str/trim passphrase) + (string/trim passphrase) password - #(dispatch [:account-recovered %])))) + #(re-frame/dispatch [:account-recovered % password])))) ;;;; Handlers -(register-handler-fx +(handlers/register-handler-fx :account-recovered - [(inject-cofx :get-new-keypair!)] - (fn [{:keys [db keypair]} [_ result]] - (let [data (json->clj result) + [(re-frame/inject-cofx :get-new-keypair!)] + (fn [{:keys [db keypair]} [_ result password]] + (let [data (types/json->clj result) public-key (:pubkey data) address (-> data :address utils.hex/normalize-hex) phrase (signing-phrase/generate) {:keys [public private]} keypair account {:public-key public-key :address address - :name (generate-gfy public-key) - :photo-path (identicon public-key) + :name (gfycat/generate-gfy public-key) + :photo-path (identicon/identicon public-key) :updates-public-key public :updates-private-key private :signed-up? true :signing-phrase phrase}] - (log/debug "account-recovered") - (when-not (str/blank? public-key) + (when-not (string/blank? public-key) (-> db (accounts-events/add-account account) - (assoc :dispatch [:navigate-to-clean :accounts])))))) + (assoc :dispatch [:login-account address password])))))) -(register-handler-fx +(handlers/register-handler-fx :recover-account (fn [_ [_ passphrase password]] {::recover-account-fx [passphrase password]})) diff --git a/src/status_im/ui/screens/accounts/recover/styles.cljs b/src/status_im/ui/screens/accounts/recover/styles.cljs index 8c1d87e31d..e4d1c62560 100644 --- a/src/status_im/ui/screens/accounts/recover/styles.cljs +++ b/src/status_im/ui/screens/accounts/recover/styles.cljs @@ -1,10 +1,11 @@ (ns status-im.ui.screens.accounts.recover.styles - (:require [status-im.ui.components.styles :as common] - [status-im.utils.platform :refer [ios?]])) + (:require [status-im.ui.components.colors :as colors])) (def screen-container {:flex 1 - :background-color common/color-white}) + :background-color colors/white}) -(def passphrase-input-max-height - (if ios? 78 72)) +(def bottom-button-container + {:flex-direction :row + :margin-horizontal 12 + :margin-vertical 15}) diff --git a/src/status_im/ui/screens/accounts/recover/views.cljs b/src/status_im/ui/screens/accounts/recover/views.cljs index 14d9436a36..7609b8845e 100644 --- a/src/status_im/ui/screens/accounts/recover/views.cljs +++ b/src/status_im/ui/screens/accounts/recover/views.cljs @@ -1,63 +1,59 @@ (ns status-im.ui.screens.accounts.recover.views (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [re-frame.core :refer [dispatch]] - [status-im.ui.components.text-input-with-label.view :refer [text-input-with-label]] - [status-im.ui.components.react :refer [view - text - image - keyboard-avoiding-view - touchable-highlight]] - [status-im.ui.components.sticky-button :refer [sticky-button]] - [status-im.ui.components.status-bar.view :refer [status-bar]] + (:require [re-frame.core :as re-frame] + [status-im.ui.components.text-input.view :as text-input] + [status-im.ui.components.react :as react] + [status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.toolbar.view :as toolbar] - [status-im.ui.components.toolbar.actions :as act] [status-im.i18n :as i18n] - [status-im.ui.screens.accounts.recover.styles :as st] - [status-im.ui.screens.accounts.recover.db :as v] + [status-im.ui.screens.accounts.recover.styles :as styles] + [status-im.ui.screens.accounts.recover.db :as recover.db] + [status-im.ui.screens.accounts.db :as db] [cljs.spec.alpha :as spec] - [clojure.string :as str])) + [status-im.ui.components.common.common :as components.common])) (defview passphrase-input [passphrase] (letsubs [error [:get-in [:accounts/recover :passphrase-error]]] - [view {:margin-top 10} - [text-input-with-label {:label (i18n/label :t/passphrase) - :description (i18n/label :t/twelve-words-in-correct-order) - :multiline true - :auto-expanding true - :max-height st/passphrase-input-max-height - :default-value passphrase - :auto-capitalize :none - :on-change-text #(dispatch [:set-in [:accounts/recover :passphrase] %]) - :error error}]])) + [text-input/text-input-with-label + {:style {:flex 1} + :height 92 + :label (i18n/label :t/passphrase) + :placeholder (i18n/label :t/enter-12-words) + :multiline true + :default-value passphrase + :on-change-text #(re-frame/dispatch [:set-in [:accounts/recover :passphrase] %]) + :error error}])) (defview password-input [password] (letsubs [error [:get-in [:accounts/recover :password-error]]] - [view {:margin-top 10} - [text-input-with-label {:label (i18n/label :t/password) - :default-value password - :auto-capitalize :none - :on-change-text #(dispatch [:set-in [:accounts/recover :password] %]) - :secure-text-entry true - :error error}]])) + [react/view {:margin-top 10} + [text-input/text-input-with-label + {:label (i18n/label :t/password) + :placeholder (i18n/label :t/enter-password) + :default-value password + :auto-focus false + :on-change-text #(re-frame/dispatch [:set-in [:accounts/recover :password] %]) + :secure-text-entry true + :error error}]])) -(defview recover [& [modal?]] +(defview recover [] (letsubs [{:keys [passphrase password]} [:get :accounts/recover]] (let [valid-form? (and - (spec/valid? ::v/passphrase passphrase) - (spec/valid? ::v/password password))] - [keyboard-avoiding-view {:style st/screen-container} - [status-bar] - [toolbar/toolbar {:modal? modal?} toolbar/default-nav-back - [toolbar/content-title (i18n/label :t/recover-access)]] - [passphrase-input (or passphrase "")] - [password-input (or password "")] - [view {:flex 1}] - (when valid-form? - [sticky-button - (i18n/label :t/recover-access) - #(do - (when modal? (dispatch [:navigate-back])) - (dispatch [:recover-account passphrase password]))])]))) - -(defview recover-modal [] - [recover true]) + (spec/valid? ::recover.db/passphrase passphrase) + (spec/valid? ::db/password password))] + [react/keyboard-avoiding-view {:style styles/screen-container} + [status-bar/status-bar] + [toolbar/toolbar nil toolbar/default-nav-back + [toolbar/content-title (i18n/label :t/sign-in-to-another)]] + [components.common/separator] + [react/view {:margin 16} + [passphrase-input (or passphrase "")] + [password-input (or password "")]] + [react/view {:flex 1}] + [react/view {:style styles/bottom-button-container} + [react/view {:style {:flex 1}}] + [components.common/bottom-button + {:forward? true + :label (i18n/label :t/sign-in) + :disabled? (not valid-form?) + :on-press #(re-frame/dispatch [:recover-account passphrase password])}]]]))) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/styles.cljs b/src/status_im/ui/screens/accounts/styles.cljs index a0683372ff..024fd2da6b 100644 --- a/src/status_im/ui/screens/accounts/styles.cljs +++ b/src/status_im/ui/screens/accounts/styles.cljs @@ -1,10 +1,16 @@ (ns status-im.ui.screens.accounts.styles (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) - (:require [status-im.ui.components.styles :as common])) + (:require [status-im.ui.components.styles :as common] + [status-im.ui.components.colors :as colors])) + +(def accounts-view + {:flex 1 + :background-color colors/white}) (def accounts-container - {:flex 1 - :background-color common/color-blue2}) + {:flex 1 + :padding-horizontal 16 + :background-color colors/gray-lighter}) (def bottom-actions-container {:margin-bottom 16}) @@ -14,54 +20,40 @@ :width 40 :border-radius 20}) -(defstyle account-title-conatiner - {:justify-content :center - :align-items :center - :ios {:height 56} - :android {:height 55}}) - (defstyle account-title-text - {:color :white + {:color :black :font-size 17 :ios {:letter-spacing -0.2}}) (defstyle accounts-list-container - {:flex 1 - :margin-horizontal 16 - :ios {:margin-top 10 - :margin-bottom 10} - :android {:margin-top 16 - :margin-bottom 16}}) - -(def accounts-action-button - {:label-style {:color :white} - :cyrcle-color "#ffffff33"}) - -(def accounts-separator - {:background-color "#7482eb" - :opacity 1 - :margin-left 72}) - -(def accounts-separator-wrapper - {:background-color common/color-blue2}) + {:flex 1 + :margin-top 16 + :margin-bottom 16}) (defstyle account-view - {:background-color :white - :justify-content :center - :height 64 - :border-radius 8}) - -(def account-badge - {:flex-direction :row + {:background-color :white + :flex-direction :row :align-items :center - :padding-horizontal 16}) + :padding-horizontal 16 + :height 64 + :border-radius 8}) (def account-badge-text-view - {:margin-left 16 - :flex-shrink 1}) + {:margin-left 16 + :margin-right 21 + :flex-shrink 1}) -(defstyle account-badge-text - {:ios {:font-size 17 - :letter-spacing -0.2} - :android {:font-size 16 - :color common/color-black}}) +(def account-badge-text + {:font-size 17 + :letter-spacing -0.2 + :color common/color-black}) + +(def account-badge-pub-key-text + {:font-size 14 + :letter-spacing -0.2 + :color colors/gray + :margin-top 4}) + +(def bottom-button-container + {:margin-top 14 + :margin-bottom 6}) diff --git a/src/status_im/ui/screens/accounts/subs.cljs b/src/status_im/ui/screens/accounts/subs.cljs index cb416712b0..ef6083f66a 100644 --- a/src/status_im/ui/screens/accounts/subs.cljs +++ b/src/status_im/ui/screens/accounts/subs.cljs @@ -1,5 +1,8 @@ (ns status-im.ui.screens.accounts.subs - (:require [re-frame.core :refer [reg-sub subscribe]])) + (:require [re-frame.core :refer [reg-sub subscribe]] + [clojure.string :as string] + [status-im.ui.screens.accounts.db :as db] + [cljs.spec.alpha :as spec])) (reg-sub :get-current-public-key (fn [db] @@ -18,3 +21,11 @@ :<- [:get-accounts] (fn [[account-id accounts]] (some-> accounts (get account-id)))) + +(reg-sub + :get-account-creation-next-enabled? + (fn [{:accounts/keys [create]}] + (let [{:keys [step password password-confirm name]} create] + (or (and password (= :enter-password step) (spec/valid? ::db/password password)) + (and password-confirm (= :confirm-password step) (spec/valid? ::db/password password-confirm)) + (and name (= :enter-name step) (not (string/blank? name))))))) \ No newline at end of file diff --git a/src/status_im/ui/screens/accounts/views.cljs b/src/status_im/ui/screens/accounts/views.cljs index 9d779da7fb..b113159229 100644 --- a/src/status_im/ui/screens/accounts/views.cljs +++ b/src/status_im/ui/screens/accounts/views.cljs @@ -1,56 +1,48 @@ (ns status-im.ui.screens.accounts.views - (:require-macros [status-im.utils.views :refer [defview]]) + (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [clojure.string :as string] [re-frame.core :as re-frame] [status-im.ui.screens.accounts.styles :as styles] [status-im.ui.components.list.views :as list] [status-im.ui.components.status-bar.view :as status-bar] - [status-im.ui.components.toolbar.actions :as act] - [status-im.ui.components.common.common :as common] - [status-im.ui.components.action-button.action-button :refer [action-button]] - [status-im.constants :refer [console-chat-id]] [status-im.ui.components.react :as react] - [status-im.i18n :as i18n])) + [status-im.i18n :as i18n] + [status-im.ui.components.icons.vector-icons :as icons] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.components.toolbar.view :as toolbar])) - -(defn account-badge [address photo-path name] - [react/view styles/account-badge - [react/image {:source {:uri (if (string/blank? photo-path) :avatar photo-path)} - :style styles/photo-image}] - [react/view styles/account-badge-text-view - [react/text {:style styles/account-badge-text - :numberOfLines 1} - (or name address)]]]) - -(defn account-view [{:keys [address photo-path name] :as account}] - [react/view - [react/touchable-highlight {:on-press #(re-frame/dispatch [:open-login address photo-path name])} - [react/view styles/account-view - [account-badge address photo-path name]]]]) +(defn account-view [{:keys [address photo-path name public-key]}] + [react/touchable-highlight {:on-press #(re-frame/dispatch [:open-login address photo-path name])} + [react/view styles/account-view + [react/image {:source {:uri (if (string/blank? photo-path) :avatar photo-path)} + :style styles/photo-image}] + [react/view styles/account-badge-text-view + [react/text {:style styles/account-badge-text + :numberOfLines 1} + name] + [react/text {:style styles/account-badge-pub-key-text + :ellipsize-mode :middle + :numberOfLines 1} + public-key]] + [react/view {:flex 1}] + [icons/icon :icons/forward {:color (colors/alpha colors/gray-icon 0.4)}]]]) (defview accounts [] - [accounts [:get-accounts]] - [react/view styles/accounts-container - [status-bar/status-bar {:type :transparent}] - [react/view styles/account-title-conatiner - [react/text {:style styles/account-title-text - :font :toolbar-title} - (i18n/label :t/sign-in-to-status)]] - [react/view styles/accounts-list-container - [list/flat-list {:data (vals accounts) - :render-fn (fn [account] [account-view account]) - :separator [react/view {:height 10}]}]] - [react/view styles/bottom-actions-container - [action-button (merge - {:label (i18n/label :t/create-new-account) - :icon :icons/add - :icon-opts {:color :white} - :on-press #(re-frame/dispatch [:create-new-account-handler])} - styles/accounts-action-button)] - [common/separator styles/accounts-separator styles/accounts-separator-wrapper] - [action-button (merge - {:label (i18n/label :t/recover-access) - :icon :icons/dots-horizontal - :icon-opts {:color :white} - :on-press #(re-frame/dispatch [:navigate-to :recover])} - styles/accounts-action-button)]]]) + (letsubs [accounts [:get-accounts]] + [react/view styles/accounts-view + [status-bar/status-bar] + [toolbar/toolbar nil nil + [toolbar/content-title (i18n/label :t/sign-in-to-status)]] + [react/view styles/accounts-container + [react/view styles/accounts-list-container + [list/flat-list {:data (vals accounts) + :render-fn (fn [account] [account-view account]) + :separator [react/view {:height 12}]}]] + [react/view + [components.common/button {:on-press #(re-frame/dispatch [:navigate-to :create-account]) + :label (i18n/label :t/create-new-account)}] + [react/view styles/bottom-button-container + [components.common/button {:on-press #(re-frame/dispatch [:navigate-to :recover]) + :label (i18n/label :t/add-existing-account) + :background? false}]]]]])) \ No newline at end of file diff --git a/src/status_im/ui/screens/add_new/views.cljs b/src/status_im/ui/screens/add_new/views.cljs index 2d1f560438..52bbf16f66 100644 --- a/src/status_im/ui/screens/add_new/views.cljs +++ b/src/status_im/ui/screens/add_new/views.cljs @@ -43,10 +43,8 @@ :on-press #()}]]) (defview add-new [] - (letsubs [contacts [:all-added-group-contacts] - params [:get :contacts/click-params]] - [react/view {:flex 1} - [status-bar/status-bar] - [toolbar.view/simple-toolbar (i18n/label :t/new)] - [components/separator] - [options-list]])) \ No newline at end of file + [react/view {:flex 1 :background-color :white} + [status-bar/status-bar] + [toolbar.view/simple-toolbar (i18n/label :t/new)] + [components/separator] + [options-list]]) \ No newline at end of file diff --git a/src/status_im/ui/screens/browser/events.cljs b/src/status_im/ui/screens/browser/events.cljs index 9239870fd9..6d00da8310 100644 --- a/src/status_im/ui/screens/browser/events.cljs +++ b/src/status_im/ui/screens/browser/events.cljs @@ -15,10 +15,8 @@ :initialize-browsers [(re-frame/inject-cofx :all-stored-browsers)] (fn [{:keys [db all-stored-browsers]} _] - (let [{:accounts/keys [account-creation?]} db] - (when-not account-creation? - (let [browsers (into {} (map #(vector (:browser-id %) %) all-stored-browsers))] - {:db (assoc db :browser/browsers browsers)}))))) + (let [browsers (into {} (map #(vector (:browser-id %) %) all-stored-browsers))] + {:db (assoc db :browser/browsers browsers)}))) (re-frame/reg-fx :save-browser diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 0f06b9675d..f2cbe097c9 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -28,7 +28,7 @@ :group/contact-groups {} :group/selected-contacts #{} :chats {} - :current-chat-id constants/console-chat-id + :current-chat-id nil :selected-participants #{} :discoveries {} :discover-search-tags #{} @@ -139,8 +139,7 @@ :group/selected-contacts :group/groups-order :accounts/accounts - :accounts/account-creation? - :accounts/creating-account? + :accounts/create :accounts/current-account-id :accounts/recover :accounts/login diff --git a/src/status_im/ui/screens/discover/all_dapps/views.cljs b/src/status_im/ui/screens/discover/all_dapps/views.cljs index 72a23271a2..f7af631a23 100644 --- a/src/status_im/ui/screens/discover/all_dapps/views.cljs +++ b/src/status_im/ui/screens/discover/all_dapps/views.cljs @@ -57,8 +57,7 @@ (repeat (- columns extras) {:name ""}))))) (defview main [] - (letsubs [all-dapps [:discover/all-dapps] - tabs-hidden? [:tabs-hidden?]] + (letsubs [all-dapps [:discover/all-dapps]] (let [columns 3] (when (seq all-dapps) [react/view styles/all-dapps-container diff --git a/src/status_im/ui/screens/discover/recent_statuses/views.cljs b/src/status_im/ui/screens/discover/recent_statuses/views.cljs index c344089a70..3eedbf8bf5 100644 --- a/src/status_im/ui/screens/discover/recent_statuses/views.cljs +++ b/src/status_im/ui/screens/discover/recent_statuses/views.cljs @@ -8,7 +8,6 @@ (defview discover-all-recent [] (letsubs [discoveries [:discover/recent-discoveries] - tabs-hidden? [:tabs-hidden?] current-account [:get-current-account] contacts [:get-contacts]] [react/view styles/all-recent-container @@ -16,7 +15,7 @@ toolbar/default-nav-back [toolbar/content-title (i18n/label :t/recent)]] (when (seq discoveries) - [react/scroll-view (styles/list-container tabs-hidden?) + [react/scroll-view (styles/list-container false) [react/view styles/status-list-outer [react/view styles/status-list-inner (let [discoveries (map-indexed vector discoveries)] diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 540b880f4d..53c6793232 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -24,9 +24,9 @@ status-im.ui.screens.wallet.choose-recipient.events status-im.ui.screens.browser.events status-im.ui.screens.offline-messaging-settings.events + status-im.ui.screens.usage-data.events [re-frame.core :as re-frame] [status-im.native-module.core :as status] - [status-im.ui.components.react :as react] [status-im.ui.components.permissions :as permissions] [status-im.constants :refer [console-chat-id]] [status-im.data-store.core :as data-store] @@ -159,13 +159,14 @@ (re-frame/reg-fx :initialize-geth-fx (fn [config] + ;;TODO get rid of this, because we don't need this anymore (status/should-move-to-internal-storage? (fn [should-move?] (if should-move? (re-frame/dispatch [:request-permissions [:read-external-storage] #(move-to-internal-storage config) - #(re-frame/dispatch [:move-to-internal-failure-message])]) + #()]) (status/start-node config)))))) (re-frame/reg-fx @@ -225,7 +226,7 @@ {::testfairy-alert nil :dispatch-n [[:initialize-db] [:load-accounts] - [:check-console-chat] + [:initialize-views] [:listen-to-network-status] [:initialize-crypt] [:initialize-geth]]})) @@ -234,7 +235,6 @@ :initialize-db (fn [{{:keys [status-module-initialized? status-node-started? network-status network] - :networks/keys [networks] :or {network (get app-db :network)}} :db} _] {::init-store nil :db (assoc app-db @@ -247,8 +247,8 @@ (handlers/register-handler-db :initialize-account-db - (fn [{:keys [accounts/accounts contacts/contacts networks/networks - network network-status view-id navigation-stack chats + (fn [{:keys [accounts/accounts accounts/create contacts/contacts networks/networks + network network-status view-id navigation-stack access-scope->commands-responses status-module-initialized? status-node-started? inbox/wnode] @@ -268,7 +268,7 @@ :status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?) :status-node-started? status-node-started? :accounts/accounts accounts - :accounts/creating-account? false + :accounts/create create :networks/networks networks :network-status network-status :network network @@ -291,24 +291,24 @@ [:send-account-update-if-needed] [:update-wallet] [:update-transactions] - [:get-fcm-token]] + [:get-fcm-token] + [:update-sign-in-time]] (seq events-after) (into events-after))})) (handlers/register-handler-fx - :check-console-chat - (fn [{{:accounts/keys [accounts] :as db} :db} [_ open-console?]] - (let [view (if (empty? accounts) - :chat - :accounts)] - (merge - {:db (assoc db - :view-id view - :navigation-stack (list view))} - (when (or (empty? accounts) open-console?) - {:dispatch-n (concat [[:init-console-chat]] - (when open-console? - [[:navigate-to-chat console-chat-id]]))}))))) + :initialize-views + (fn [{{:accounts/keys [accounts] :as db} :db}] + {:db (if (empty? accounts) + (assoc db :view-id :intro :navigation-stack (list :intro)) + (let [{:keys [address photo-path name]} (first (sort-by :last-sign-in > (vals accounts)))] + (-> db + (assoc :view-id :login + :navigation-stack (list :login)) + (update :accounts/login assoc + :address address + :photo-path photo-path + :name name))))})) (handlers/register-handler-fx :initialize-crypt diff --git a/src/status_im/ui/screens/home/styles.cljs b/src/status_im/ui/screens/home/styles.cljs index d9ae427ef3..b871d958ca 100644 --- a/src/status_im/ui/screens/home/styles.cljs +++ b/src/status_im/ui/screens/home/styles.cljs @@ -155,3 +155,51 @@ :width 14 :height 9 :tint-color :white}) + +(def no-chats + {:flex 1 + :align-items :center + :justify-content :center + :margin-horizontal 34}) + +(def no-chats-text + {:font-size 14 + :line-height 21 + :letter-spacing -0.2 + :text-align :center + :color colors/gray}) + +(def welcome-view + {:flex 1 + :padding-horizontal 30}) + +(def welcome-image-container + {:flex 1 + :align-items :center + :justify-content :center}) + +(def welcome-image + {:width 320 + :height 278}) + +(def welcome-text + {:line-height 28 + :font-size 22 + :font-weight :bold + :letter-spacing -0.3 + :text-align :center + :color colors/black}) + +(def welcome-text-description + {:line-height 21 + :margin-top 8 + :margin-bottom 32 + :font-size 14 + :letter-spacing -0.2 + :text-align :center + :color colors/gray}) + +(def toolbar-logo + {:size 42 + :icon-size 17 + :shadow? false}) \ No newline at end of file diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index 3f706e0257..e5c197f1ff 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -1,9 +1,7 @@ (ns status-im.ui.screens.home.views (:require-macros [status-im.utils.views :as views]) (:require [re-frame.core :as re-frame] - [status-im.i18n :as i18n] [status-im.ui.components.colors :as colors] - [status-im.ui.components.common.common :as components.common] [status-im.ui.components.list.views :as list] [status-im.ui.components.react :as react] [status-im.ui.components.native-action-button :refer [native-action-button]] @@ -12,12 +10,16 @@ [status-im.ui.components.sync-state.offline :refer [offline-view]] [status-im.ui.screens.home.views.inner-item :as inner-item] [status-im.ui.screens.home.styles :as styles] - [status-im.utils.platform :as platform])) + [status-im.utils.platform :as platform] + [status-im.react-native.resources :as resources] + [status-im.ui.components.common.common :as components.common] + [status-im.i18n :as i18n])) -(defn- toolbar [] - [toolbar/toolbar {:title-centered? true} - nil - [toolbar/content-title (i18n/label :t/status)] +(defn- toolbar [show-welcome?] + [toolbar/toolbar nil nil + (when-not show-welcome? + [toolbar/content-wrapper + [components.common/logo styles/toolbar-logo]]) [toolbar/actions (when platform/ios? [(toolbar.actions/add #(re-frame/dispatch [:navigate-to :new]))])]]) @@ -38,13 +40,37 @@ [react/view [inner-item/home-list-browser-item-inner-view home-item]]])) +;;do not remove view-id and will-update or will-unmount handlers, this is how it works +(views/defview welcome [view-id] + (views/letsubs [handler #(re-frame/dispatch [:set-in [:accounts/create :show-welcome?] false])] + {:component-will-update handler + :component-will-unmount handler} + [react/view {:style styles/welcome-view} + [react/view {:style styles/welcome-image-container} + [react/image {:source (:welcome-image resources/ui) + :style styles/welcome-image}]] + [react/text {:style styles/welcome-text} + (i18n/label :t/welcome-to-status)] + [react/view + [react/text {:style styles/welcome-text-description} + (i18n/label :t/welcome-to-status-description)]]])) + (views/defview home [] - (views/letsubs [home-items [:home-items]] + (views/letsubs [home-items [:home-items] + show-welcome? [:get-in [:accounts/create :show-welcome?]] + view-id [:get :view-id]] [react/view styles/container - [toolbar] - [list/flat-list {:data home-items - :render-fn (fn [[home-item-id :as home-item]] - ^{:key home-item-id} [home-list-item home-item])}] + [toolbar show-welcome?] + (cond show-welcome? + [welcome view-id] + (empty? home-items) + [react/view styles/no-chats + [react/text {:style styles/no-chats-text} + (i18n/label :t/no-recent-chats)]] + :else + [list/flat-list {:data home-items + :render-fn (fn [[home-item-id :as home-item]] + ^{:key home-item-id} [home-list-item home-item])}]) (when platform/android? [home-action-button]) [offline-view]])) diff --git a/src/status_im/ui/screens/intro/styles.cljs b/src/status_im/ui/screens/intro/styles.cljs new file mode 100644 index 0000000000..46d4dc6315 --- /dev/null +++ b/src/status_im/ui/screens/intro/styles.cljs @@ -0,0 +1,43 @@ +(ns status-im.ui.screens.intro.styles + (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) + (:require [status-im.ui.components.colors :as colors])) + +(def intro-view + {:flex 1 + :padding-horizontal 30 + :background-color colors/white}) + +(def intro-logo-container + {:flex 1 + :align-items :center + :justify-content :center}) + +(def intro-logo + {:size 111 + :icon-size 46}) + +(defstyle intro-text + {:text-align :center + :color colors/black + :ios {:line-height 28 + :font-size 22 + :font-weight :bold + :letter-spacing -0.3} + :android {:font-size 24 + :line-height 30}}) + +(def intro-text-description + {:line-height 21 + :margin-top 8 + :margin-bottom 16 + :font-size 14 + :letter-spacing -0.2 + :text-align :center + :color colors/gray}) + +(def buttons-container + {:align-items :center}) + +(def bottom-button-container + {:margin-bottom 6 + :margin-top 38}) \ No newline at end of file diff --git a/src/status_im/ui/screens/intro/views.cljs b/src/status_im/ui/screens/intro/views.cljs new file mode 100644 index 0000000000..d4f12baa5c --- /dev/null +++ b/src/status_im/ui/screens/intro/views.cljs @@ -0,0 +1,27 @@ +(ns status-im.ui.screens.intro.views + (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require [status-im.ui.components.react :as react] + [re-frame.core :as re-frame] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.screens.intro.styles :as styles] + [status-im.i18n :as i18n] + [status-im.ui.components.status-bar.view :as status-bar])) + +(defview intro [] + [react/view {:style styles/intro-view} + [status-bar/status-bar {:flat? true}] + [react/view {:style styles/intro-logo-container} + [components.common/logo styles/intro-logo]] + [react/text {:style styles/intro-text} + (i18n/label :t/intro-text)] + [react/view + [react/text {:style styles/intro-text-description} + (i18n/label :t/intro-text-description)]] + [react/view styles/buttons-container + [components.common/button {:style {:flex-direction :row} + :on-press #(re-frame/dispatch [:navigate-to :create-account]) + :label (i18n/label :t/create-account)}] + [react/view styles/bottom-button-container + [components.common/button {:on-press #(re-frame/dispatch [:navigate-to :recover]) + :label (i18n/label :t/already-have-account) + :background? false}]]]]) \ No newline at end of file diff --git a/src/status_im/ui/screens/navigation.cljs b/src/status_im/ui/screens/navigation.cljs index c05bb1f1b1..3cbc31c30c 100644 --- a/src/status_im/ui/screens/navigation.cljs +++ b/src/status_im/ui/screens/navigation.cljs @@ -21,9 +21,6 @@ (update :navigation-stack replace-top-element view-id) (assoc :view-id view-id))) -(defn- can-navigate-back? [db] - (not (get db :accounts/creating-account?))) - ;; public fns (defn navigate-to-clean [db view-id] @@ -89,15 +86,13 @@ (>= 1 (count navigation-stack)) db :else - (if (can-navigate-back? db) - (let [[previous-view-id :as navigation-stack'] (pop navigation-stack) - first-in-stack (first navigation-stack)] - (if (= view-id first-in-stack) - (-> db - (assoc :view-id previous-view-id) - (assoc :navigation-stack navigation-stack')) - (assoc db :view-id first-in-stack))) - db)))) + (let [[previous-view-id :as navigation-stack'] (pop navigation-stack) + first-in-stack (first navigation-stack)] + (if (= view-id first-in-stack) + (-> db + (assoc :view-id previous-view-id) + (assoc :navigation-stack navigation-stack')) + (assoc db :view-id first-in-stack)))))) (register-handler-db :navigate-to-clean diff --git a/src/status_im/ui/screens/network_settings/add_rpc/views.cljs b/src/status_im/ui/screens/network_settings/add_rpc/views.cljs index 84a98892ad..df09158b20 100644 --- a/src/status_im/ui/screens/network_settings/add_rpc/views.cljs +++ b/src/status_im/ui/screens/network_settings/add_rpc/views.cljs @@ -3,7 +3,7 @@ [re-frame.core :refer [dispatch]] [status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.toolbar.view :as toolbar] - [status-im.ui.components.text-input-with-label.view :refer [text-input-with-label]] + [status-im.ui.components.text-input.view :as text-input] [status-im.ui.screens.network-settings.views :as network-settings] [status-im.ui.components.react :as react] [status-im.ui.components.sticky-button :as sticky-button] @@ -18,7 +18,7 @@ (i18n/label :t/add-network)] [network-settings/network-badge] [react/view {:margin-top 8} - [text-input-with-label {:label (i18n/label :t/rpc-url)}]] + [text-input/text-input-with-label {:label (i18n/label :t/rpc-url)}]] [react/view {:flex 1}] (when (not (str/blank? rpc-url)) [sticky-button/sticky-button (i18n/label :t/add-network) #()])])) diff --git a/src/status_im/ui/screens/profile/group_chat/styles.cljs b/src/status_im/ui/screens/profile/group_chat/styles.cljs index 9b77ba8f1f..c459c3d302 100644 --- a/src/status_im/ui/screens/profile/group_chat/styles.cljs +++ b/src/status_im/ui/screens/profile/group_chat/styles.cljs @@ -6,7 +6,7 @@ :padding-top 24}) (def action - {:background-color colors/blue-transparent + {:background-color (colors/alpha colors/blue 0.1) :border-radius 50}) (def action-label diff --git a/src/status_im/ui/screens/profile/user/styles.cljs b/src/status_im/ui/screens/profile/user/styles.cljs index abb892a506..0c0d971a56 100644 --- a/src/status_im/ui/screens/profile/user/styles.cljs +++ b/src/status_im/ui/screens/profile/user/styles.cljs @@ -11,7 +11,7 @@ :align-items :center :height 42 :border-radius components.styles/border-radius - :background-color colors/blue-transparent}) + :background-color (colors/alpha colors/blue 0.1)}) (def share-contact-code-text-container {:padding-left 16 diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index 18840d5664..b345589b5c 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -31,13 +31,6 @@ (fn [current-account] (:signed-up? current-account))) -(reg-sub :tabs-hidden? - :<- [:get-in [:chat-list-ui-props :edit?]] - :<- [:get-in [:contacts/ui-props :edit?]] - :<- [:get :view-id] - (fn [[chats-edit-mode? contacts-edit-mode? view-id]] - (and (= view-id :contact-list) contacts-edit-mode?))) - (reg-sub :network (fn [db] (:network db))) @@ -54,3 +47,7 @@ (reg-sub :get-screen-params (fn [db [_ view-id]] (get-in db [:navigation/screen-params (or view-id (:view-id db))]))) + +(reg-sub :can-navigate-back? + (fn [db] + (> (count (:navigation-stack db)) 1))) \ No newline at end of file diff --git a/src/status_im/ui/screens/usage_data/events.cljs b/src/status_im/ui/screens/usage_data/events.cljs new file mode 100644 index 0000000000..7a2f999918 --- /dev/null +++ b/src/status_im/ui/screens/usage_data/events.cljs @@ -0,0 +1,10 @@ +(ns status-im.ui.screens.usage-data.events + (:require [status-im.utils.handlers :as handlers] + [status-im.ui.screens.accounts.events :as accounts])) + +(handlers/register-handler-fx + :help-improve-handler + (fn [{db :db} [_ yes?]] + (merge (when yes? + (accounts/account-update {:db db} {:sharing-usage-data? true})) + {:dispatch [:navigate-to-clean :home]}))) \ No newline at end of file diff --git a/src/status_im/ui/screens/usage_data/styles.cljs b/src/status_im/ui/screens/usage_data/styles.cljs new file mode 100644 index 0000000000..cfae954927 --- /dev/null +++ b/src/status_im/ui/screens/usage_data/styles.cljs @@ -0,0 +1,48 @@ +(ns status-im.ui.screens.usage-data.styles + (:require-macros [status-im.utils.styles :refer [defnstyle defstyle]]) + (:require [status-im.ui.components.colors :as colors])) + +(def usage-data-view + {:flex 1 + :padding-horizontal 30 + :background-color colors/white}) + +(def logo-container + {:flex 1 + :align-items :center + :justify-content :center}) + +(def logo + {:size 82 + :icon-size 34}) + +(def usage-data-image + {:width 138 + :height 208 + :margin-top 10}) + +(defstyle help-improve-text + {:text-align :center + :color colors/black + :ios {:line-height 28 + :font-size 22 + :font-weight :bold + :letter-spacing -0.3} + :android {:font-size 24 + :line-height 30}}) + +(def help-improve-text-description + {:line-height 21 + :margin-top 8 + :margin-bottom 16 + :font-size 14 + :letter-spacing -0.2 + :text-align :center + :color colors/gray}) + +(def buttons-container + {:align-items :center}) + +(def bottom-button-container + {:margin-bottom 6 + :margin-top 38}) \ No newline at end of file diff --git a/src/status_im/ui/screens/usage_data/views.cljs b/src/status_im/ui/screens/usage_data/views.cljs new file mode 100644 index 0000000000..d4b95d8ba7 --- /dev/null +++ b/src/status_im/ui/screens/usage_data/views.cljs @@ -0,0 +1,30 @@ +(ns status-im.ui.screens.usage-data.views + (:require-macros [status-im.utils.views :refer [defview letsubs]]) + (:require [status-im.ui.components.react :as react] + [re-frame.core :as re-frame] + [status-im.react-native.resources :as resources] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.screens.usage-data.styles :as styles] + [status-im.i18n :as i18n] + [status-im.ui.components.status-bar.view :as status-bar])) + +(defview usage-data [] + [react/view {:style styles/usage-data-view} + [status-bar/status-bar {:flat? true}] + [react/view {:style styles/logo-container} + [components.common/logo styles/logo] + [react/image {:source (:analytics-image resources/ui) + :style styles/usage-data-image}]] + [react/text {:style styles/help-improve-text} + (i18n/label :t/help-improve)] + [react/view + [react/text {:style styles/help-improve-text-description} + (i18n/label :t/help-improve-description)]] + [react/view styles/buttons-container + [components.common/button {:style {:flex-direction :row} + :on-press #(re-frame/dispatch [:help-improve-handler true]) + :label (i18n/label :t/share-usage-data)}] + [react/view styles/bottom-button-container + [components.common/button {:on-press #(re-frame/dispatch [:help-improve-handler false]) + :label (i18n/label :t/dont-want-to-share) + :background? false}]]]]) \ No newline at end of file diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index c065ade0f3..385dd8a291 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -7,7 +7,7 @@ [status-im.ui.screens.main-tabs.views :refer [main-tabs]] [status-im.ui.screens.accounts.login.views :refer [login]] - [status-im.ui.screens.accounts.recover.views :refer [recover recover-modal]] + [status-im.ui.screens.accounts.recover.views :refer [recover]] [status-im.ui.screens.accounts.views :refer [accounts]] [status-im.chat.screen :refer [chat]] @@ -38,7 +38,6 @@ [status-im.ui.screens.wallet.transactions.views :as wallet-transactions] [status-im.ui.screens.wallet.send.transaction-sent.views :refer [transaction-sent transaction-sent-modal]] [status-im.ui.screens.wallet.components.views :refer [contact-code recent-recipients recipient-qr-code]] - [status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.screens.discover.search-results.views :as discover-search] [status-im.ui.screens.discover.recent-statuses.views :as discover-recent] [status-im.ui.screens.discover.all-dapps.views :as discover-all-dapps] @@ -51,15 +50,11 @@ [status-im.ui.screens.network-settings.parse-json.views :refer [paste-json-text]] [status-im.ui.screens.browser.views :refer [browser]] [status-im.ui.screens.add-new.open-dapp.views :refer [open-dapp dapp-description]] + [status-im.ui.screens.intro.views :refer [intro]] + [status-im.ui.screens.accounts.create.views :refer [create-account]] + [status-im.ui.screens.usage-data.views :refer [usage-data]] [status-im.utils.config :as config])) -(defn validate-current-view - [current-view signed-up?] - (if (or (contains? #{:login :chat :recover :accounts} current-view) - signed-up?) - current-view - :chat)) - ;;; defines hierarchy of views, when parent screen is opened children screens ;;; are pre-rendered, currently it is: ;;; @@ -129,76 +124,77 @@ modal-view [:get :modal]] {:component-will-update (fn [] (react/dismiss-keyboard!))} (when view-id - (let [current-view (validate-current-view view-id signed-up?)] - (let [component (case current-view - (:home :wallet :my-profile) main-tabs - :browser browser - :open-dapp open-dapp - :dapp-description dapp-description - :wallet-send-transaction send-transaction - :wallet-transaction-sent transaction-sent - :wallet-request-transaction request-transaction - :wallet-send-transaction-request send-transaction-request - (:transactions-history :unsigned-transactions) wallet-transactions/transactions - :wallet-transaction-details wallet-transactions/transaction-details - :wallet-send-assets wallet.components/send-assets - :wallet-request-assets wallet.components/request-assets - :new add-new - :new-group new-group - :add-contacts-toggle-list add-contacts-toggle-list - :add-participants-toggle-list add-participants-toggle-list - :edit-group-contact-list edit-contact-group-contact-list - :new-public-chat new-public-chat - :contact-toggle-list contact-toggle-list - :new-chat new-chat - :qr-scanner qr-scanner - :chat chat - :profile profile.contact/profile - :group-chat-profile profile.group-chat/group-chat-profile - :discover-all-recent discover-recent/discover-all-recent - :discover-all-popular-hashtags discover-popular/discover-all-popular-hashtags - :discover-search-results discover-search/discover-search-results - :discover-dapp-details discover-dapp-details/dapp-details - :discover-all-dapps discover-all-dapps/main - :profile-photo-capture profile-photo-capture - :accounts accounts - :login login - :recover recover - :network-settings network-settings - :offline-messaging-settings offline-messaging-settings - :paste-json-text paste-json-text - :add-rpc-url add-rpc-url - :network-details network-details - :recent-recipients recent-recipients - :recipient-qr-code recipient-qr-code - :contact-code contact-code - :profile-qr-viewer profile.user/qr-viewer - (throw (str "Unknown view: " current-view))) - main-screen-view (create-main-screen-view current-view)] - [main-screen-view common-styles/flex - (if (and config/compile-views-enabled? - signed-up? - (#{:home :wallet :my-profile :chat :wallet-send-transaction - :choose-recipient :wallet-transaction-sent :transactions-history - :unsigned-transactions :wallet-request-transaction :edit-my-profile - :profile-photo-capture :wallet-request-assets} - current-view)) - [root-view] - [component]) - (when modal-view - [view common-styles/modal - [modal {:animation-type :slide - :transparent true - :on-request-close #(dispatch [:navigate-back])} - (let [component (case modal-view - :qr-scanner qr-scanner - :recover-modal recover-modal - :contact-list-modal contact-list-modal - :wallet-transactions-filter wallet-transactions/filter-history - :wallet-settings-assets wallet-settings/manage-assets - :wallet-send-transaction-modal send-transaction-modal - :wallet-transaction-sent-modal transaction-sent-modal - :wallet-transaction-fee wallet.send/transaction-fee - (throw (str "Unknown modal view: " modal-view)))] - [react/main-screen-modal-view modal-view - [component]])]])]))))) + (let [component (case view-id + :intro intro + :create-account create-account + :usage-data usage-data + (:home :wallet :my-profile) main-tabs + :browser browser + :open-dapp open-dapp + :dapp-description dapp-description + :wallet-send-transaction send-transaction + :wallet-transaction-sent transaction-sent + :wallet-request-transaction request-transaction + :wallet-send-transaction-request send-transaction-request + (:transactions-history :unsigned-transactions) wallet-transactions/transactions + :wallet-transaction-details wallet-transactions/transaction-details + :wallet-send-assets wallet.components/send-assets + :wallet-request-assets wallet.components/request-assets + :new add-new + :new-group new-group + :add-contacts-toggle-list add-contacts-toggle-list + :add-participants-toggle-list add-participants-toggle-list + :edit-group-contact-list edit-contact-group-contact-list + :new-public-chat new-public-chat + :contact-toggle-list contact-toggle-list + :new-chat new-chat + :qr-scanner qr-scanner + :chat chat + :profile profile.contact/profile + :group-chat-profile profile.group-chat/group-chat-profile + :discover-all-recent discover-recent/discover-all-recent + :discover-all-popular-hashtags discover-popular/discover-all-popular-hashtags + :discover-search-results discover-search/discover-search-results + :discover-dapp-details discover-dapp-details/dapp-details + :discover-all-dapps discover-all-dapps/main + :profile-photo-capture profile-photo-capture + :accounts accounts + :login login + :recover recover + :network-settings network-settings + :offline-messaging-settings offline-messaging-settings + :paste-json-text paste-json-text + :add-rpc-url add-rpc-url + :network-details network-details + :recent-recipients recent-recipients + :recipient-qr-code recipient-qr-code + :contact-code contact-code + :profile-qr-viewer profile.user/qr-viewer + [react/view [react/text (str "Unknown view: " view-id)]]) + main-screen-view (create-main-screen-view view-id)] + [main-screen-view common-styles/flex + (if (and config/compile-views-enabled? + signed-up? + (#{:home :wallet :my-profile :chat :wallet-send-transaction + :choose-recipient :wallet-transaction-sent :transactions-history + :unsigned-transactions :wallet-request-transaction :edit-my-profile + :profile-photo-capture :wallet-request-assets} + view-id)) + [root-view] + [component]) + (when modal-view + [view common-styles/modal + [modal {:animation-type :slide + :transparent true + :on-request-close #(dispatch [:navigate-back])} + (let [component (case modal-view + :qr-scanner qr-scanner + :contact-list-modal contact-list-modal + :wallet-transactions-filter wallet-transactions/filter-history + :wallet-settings-assets wallet-settings/manage-assets + :wallet-send-transaction-modal send-transaction-modal + :wallet-transaction-sent-modal transaction-sent-modal + :wallet-transaction-fee wallet.send/transaction-fee + [react/view [react/text (str "Unknown modal view: " modal-view)]])] + [react/main-screen-modal-view modal-view + [component]])]])])))) diff --git a/src/status_im/ui/screens/wallet/components/animations.cljs b/src/status_im/ui/screens/wallet/components/animations.cljs deleted file mode 100644 index 6848a5fbac..0000000000 --- a/src/status_im/ui/screens/wallet/components/animations.cljs +++ /dev/null @@ -1,12 +0,0 @@ -(ns status-im.ui.screens.wallet.components.animations - (:require [status-im.ui.components.animation :as animation])) - -(defn animate-tooltip [bottom-value opacity-value] - (fn [] - (animation/start - (animation/parallel - [(animation/timing opacity-value {:toValue 1 - :duration 500}) - (animation/timing bottom-value {:toValue -40 - :easing (.bezier (animation/easing) 0.685, 0.000, 0.025, 1.185) - :duration 500})])))) diff --git a/src/status_im/ui/screens/wallet/components/styles.cljs b/src/status_im/ui/screens/wallet/components/styles.cljs index 79ad8d3728..669dcbc632 100644 --- a/src/status_im/ui/screens/wallet/components/styles.cljs +++ b/src/status_im/ui/screens/wallet/components/styles.cljs @@ -184,31 +184,4 @@ :font-size 15 :letter-spacing -0.2}) -(def tooltip-container - {:position :absolute - :align-items :center - :left 0 - :right 0 - :top 0}) -(defn tooltip-animated [bottom-value opacity-value] - {:position :absolute - :align-items :center - :left 0 - :right 0 - :bottom bottom-value - :opacity opacity-value}) - -(def tooltip-text-container - {:padding-horizontal 16 - :padding-vertical 9 - :background-color :white - :border-radius 8}) - -(def tooltip-text - {:color styles/color-red-2 - :font-size 15}) - -(def tooltip-triangle - {:width 16 - :height 8}) diff --git a/src/status_im/ui/screens/wallet/components/views.cljs b/src/status_im/ui/screens/wallet/components/views.cljs index 9305335656..84b8387876 100644 --- a/src/status_im/ui/screens/wallet/components/views.cljs +++ b/src/status_im/ui/screens/wallet/components/views.cljs @@ -4,18 +4,15 @@ [reagent.core :as reagent] [re-frame.core :as re-frame] [status-im.i18n :as i18n] - [status-im.ui.components.animation :as animation] [status-im.ui.components.bottom-buttons.view :as bottom-buttons] [status-im.ui.components.button.view :as button] [status-im.ui.components.chat-icon.screen :as chat-icon] - [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.list.views :as list] [status-im.ui.components.list.styles :as list.styles] [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.react :as react] [status-im.ui.components.styles :as components.styles] [status-im.ui.screens.wallet.components :as components] - [status-im.ui.screens.wallet.components.animations :as animations] [status-im.ui.screens.wallet.components.styles :as styles] [status-im.ui.screens.wallet.choose-recipient.views :as choose-recipient] [status-im.ui.screens.wallet.views :as wallet] @@ -23,17 +20,8 @@ [status-im.ui.screens.wallet.utils :as wallet.utils] [status-im.utils.ethereum.core :as ethereum] [status-im.utils.ethereum.tokens :as tokens] - [status-im.utils.platform :as platform])) - -(views/defview tooltip [label] - (views/letsubs [bottom-value (animation/create-value -30) - opacity-value (animation/create-value 0)] - {:component-did-mount (animations/animate-tooltip bottom-value opacity-value)} - [react/view styles/tooltip-container - [react/animated-view {:style (styles/tooltip-animated bottom-value opacity-value)} - [react/view styles/tooltip-text-container - [react/text {:style styles/tooltip-text} label]] - [vector-icons/icon :icons/tooltip-triangle {:color :white :style styles/tooltip-triangle}]]])) + [status-im.utils.platform :as platform] + [status-im.ui.components.tooltip.views :as tooltip])) (defn view-asset [symbol] [react/view @@ -198,7 +186,7 @@ (i18n/label :t/amount) [amount-input m]] (when error - [tooltip error])]) + [tooltip/tooltip error])]) (defn separator [] [react/view styles/separator]) diff --git a/src/status_im/ui/screens/wallet/send/views.cljs b/src/status_im/ui/screens/wallet/send/views.cljs index 7d115d69ac..1a5bc1bdf5 100644 --- a/src/status_im/ui/screens/wallet/send/views.cljs +++ b/src/status_im/ui/screens/wallet/send/views.cljs @@ -12,6 +12,7 @@ [status-im.ui.components.styles :as components.styles] [status-im.ui.components.toolbar.actions :as act] [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.components.tooltip.views :as tooltip] [status-im.ui.screens.wallet.components.styles :as wallet.components.styles] [status-im.ui.screens.wallet.components.views :as components] [status-im.ui.screens.wallet.components :as wallet.components] @@ -51,7 +52,7 @@ :on-change-text #(re-frame/dispatch [:wallet.send/set-password %]) :style styles/password}]]] (when wrong-password? - [components/tooltip (i18n/label :t/wrong-password)])])) + [tooltip/tooltip (i18n/label :t/wrong-password)])])) ;; "Cancel" and "Sign Transaction >" buttons, signing with password (defview signing-buttons [cancel-handler sign-handler in-progress?] diff --git a/src/status_im/ui/screens/wallet/transactions/styles.cljs b/src/status_im/ui/screens/wallet/transactions/styles.cljs index cc9e455d50..ab62aacb2d 100644 --- a/src/status_im/ui/screens/wallet/transactions/styles.cljs +++ b/src/status_im/ui/screens/wallet/transactions/styles.cljs @@ -53,7 +53,7 @@ :font-size 17}) (def tx-time - {:flex-grow 1 + {:flex-grow 1 :font-size 14 :text-align :right :color styles/color-gray4}) @@ -216,4 +216,7 @@ (def filter-container {:flex 1}) - ;:background-color colors/white}) + +(def transacions-view + {:flex 1 + :background-color :white}) diff --git a/src/status_im/ui/screens/wallet/transactions/views.cljs b/src/status_im/ui/screens/wallet/transactions/views.cljs index 95f78c96ac..20cbad5737 100644 --- a/src/status_im/ui/screens/wallet/transactions/views.cljs +++ b/src/status_im/ui/screens/wallet/transactions/views.cljs @@ -28,7 +28,7 @@ (every? :checked? (:tokens filter-data)))) (defn- toolbar-view [current-tab filter-data] - [toolbar/toolbar {:flat? true} + [toolbar/toolbar nil toolbar/default-nav-back [toolbar/content-title (i18n/label :t/transactions)] (case current-tab @@ -187,7 +187,7 @@ (defview transactions [] (letsubs [current-tab [:get :view-id] filter-data [:wallet.transactions/filters]] - [react/view {:style components.styles/flex} + [react/view styles/transacions-view [status-bar/status-bar] [toolbar-view current-tab filter-data] [tabs current-tab]