Introduced onboarding sign in

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
Andrey Shovkoplyas 2018-02-28 14:14:59 +03:00
parent 8b1288e20b
commit eb8557dde8
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
76 changed files with 1225 additions and 999 deletions

5
resources/icons/logo.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" viewBox="0 0 144 152">
<g stroke="none" stroke-width="1" fill-rule="evenodd">
<path fill="" d="M41.85,82.81 C61.54,81.7 73.88,86.18 93.57,85.07 C98.4541022,84.8006381 103.305626,84.1080412 108.07,83 C105.16,118.58 79.34,149.68 44.34,151.68 C22.83,152.86 1.33,139.92 0.16,118.86 C-0.98,98.16 15.18,84.31 41.85,82.81 Z M99.53,73.91 C79,75.1 66.1,70.31 45.54,71.5 C40.4407254,71.7827279 35.3770963,72.5223591 30.41,73.71 C33.44,35.69 60.35,2.43 96.94,0.32 C119.39,-0.98 141.83,12.89 143.05,35.39 C144.24,57.51 127.38,72.31 99.53,73.91 Z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -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"],

View File

@ -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)

View File

@ -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)

View File

@ -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"])

View File

@ -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]
@ -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
{: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]]]
:dispatch [: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]]))))
:save-all-contacts [console/contact]}))
(handlers/register-handler-fx
:init-console-chat
@ -186,11 +182,6 @@
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))
{}
@ -210,7 +201,7 @@
(assoc :chats chats
:deleted-chats inactive-chat-ids)
init-console-chat
(update :dispatch-n conj load-default-contacts-event)))))))
(update :dispatch-n conj [:load-default-contacts!])))))
(handlers/register-handler-fx
:send-seen!
@ -232,28 +223,6 @@
: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]})))
(handlers/register-handler-fx
:browse-link-from-message
(fn [_ [_ link]]

View File

@ -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"))

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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)

View File

@ -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}])

View File

@ -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}}})

View File

@ -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))

View File

@ -22,4 +22,6 @@
(def ui
{:empty-hashtags (js/require "./resources/images/ui/empty-hashtags.png")
:empty-recent (js/require "./resources/images/ui/empty-recent.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")})

View File

@ -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"

View File

@ -31,7 +31,6 @@
:android {:padding-top 8
:padding-bottom 8}})
(def action-button-label-disabled
(merge action-button-label
{:color styles/color-gray4}))

View File

@ -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)

View File

@ -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?
@ -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]]])

View File

@ -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})

View File

@ -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,13 +87,13 @@
(defn icon
([name] (icon name nil))
([name {:keys [color container-style style accessibility-label]
([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
(let [icon-vec (icon-fn
(cond
(keyword? color)
(case color
@ -106,5 +107,8 @@
(string? color)
color
:else
styles/icon-dark-color))
styles/icon-dark-color))]
(if width
(update icon-vec 1 assoc :width width :height height)
icon-vec))
(throw (js/Error. (str "Unknown icon: " name))))]))

View File

@ -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

View File

@ -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))}]]))

View File

@ -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

View File

@ -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})

View File

@ -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])])

View File

@ -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))))

View File

@ -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))

View File

@ -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])])))

View File

@ -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}})
: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}

View File

@ -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])
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)
action-items]))
(defn simple-toolbar

View File

@ -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})]))))

View File

@ -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})

View File

@ -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}]]]))

View File

@ -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))))

View File

@ -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})

View File

@ -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)}]]]])]))

View File

@ -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

View File

@ -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)}))

View File

@ -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)]
(fn [{{:keys [view-id] :as db} :db} [_ error address]]
(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)))))
{: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))))

View File

@ -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
{:flex 1
:align-items :center
:justify-content :center
:background-color (str st/color-black "1A")})
: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})

View File

@ -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
(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
(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
(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)))}]]
(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)]]]])]
:error (when (pos? (count error)) (i18n/label (error-key error)))}]]]]
[react/view styles/processing-view
(when processing
[react/view st/processing-view
[components/activity-indicator {:animating true}]])]))
[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)}]])]))

View File

@ -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?))

View File

@ -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]}))

View File

@ -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})

View File

@ -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)
[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
: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}]]))
: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)
[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-capitalize :none
:on-change-text #(dispatch [:set-in [:accounts/recover :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)]]
(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 "")]
[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])
[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])}]]])))

View File

@ -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})
: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})
:margin-top 16
:margin-bottom 16})
(defstyle account-view
{:background-color :white
:justify-content :center
:flex-direction :row
:align-items :center
:padding-horizontal 16
:height 64
:border-radius 8})
(def account-badge
{:flex-direction :row
:align-items :center
:padding-horizontal 16})
(def account-badge-text-view
{: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})

View File

@ -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)))))))

View File

@ -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
(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}
(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]]]])
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]]
(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
[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)]]])
: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}]]]]]))

View File

@ -43,10 +43,8 @@
:on-press #()}]])
(defview add-new []
(letsubs [contacts [:all-added-group-contacts]
params [:get :contacts/click-params]]
[react/view {:flex 1}
[react/view {:flex 1 :background-color :white}
[status-bar/status-bar]
[toolbar.view/simple-toolbar (i18n/label :t/new)]
[components/separator]
[options-list]]))
[options-list]])

View File

@ -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)})))))
{:db (assoc db :browser/browsers browsers)})))
(re-frame/reg-fx
:save-browser

View File

@ -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

View File

@ -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

View File

@ -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)]

View File

@ -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

View File

@ -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})

View File

@ -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]
[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])}]
^{:key home-item-id} [home-list-item home-item])}])
(when platform/android?
[home-action-button])
[offline-view]]))

View File

@ -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})

View File

@ -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}]]]])

View File

@ -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))))
(assoc db :view-id first-in-stack))))))
(register-handler-db
:navigate-to-clean

View File

@ -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) #()])]))

View File

@ -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

View File

@ -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

View File

@ -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)))

View File

@ -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]})))

View File

@ -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})

View File

@ -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}]]]])

View File

@ -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,8 +124,10 @@
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
(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
@ -173,8 +170,8 @@
: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)]
[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?
@ -182,7 +179,7 @@
:choose-recipient :wallet-transaction-sent :transactions-history
:unsigned-transactions :wallet-request-transaction :edit-my-profile
:profile-photo-capture :wallet-request-assets}
current-view))
view-id))
[root-view]
[component])
(when modal-view
@ -192,13 +189,12 @@
: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/view [react/text (str "Unknown modal view: " modal-view)]])]
[react/main-screen-modal-view modal-view
[component]])]])])))))
[component]])]])]))))

View File

@ -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})]))))

View File

@ -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})

View File

@ -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])

View File

@ -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?]

View File

@ -216,4 +216,7 @@
(def filter-container
{:flex 1})
;:background-color colors/white})
(def transacions-view
{:flex 1
:background-color :white})

View File

@ -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]