chore(wallet) import private key main screen (#19625)
Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
This commit is contained in:
parent
380603ddce
commit
e6f9932dc5
|
@ -30,8 +30,10 @@
|
|||
(let [theme (quo.theme/use-theme)
|
||||
color (get-text-color theme (or blur? false))
|
||||
description? (not (nil? description))
|
||||
root-view (if (seq container-style) rn/view :<>)]
|
||||
[root-view {:style container-style}
|
||||
root-view (if (seq container-style) rn/view :<>)
|
||||
root-style (when (seq container-style)
|
||||
{:style container-style})]
|
||||
[root-view root-style
|
||||
[text/text
|
||||
{:number-of-lines 1
|
||||
:size (if description? :paragraph-1 :paragraph-2)
|
||||
|
|
|
@ -214,6 +214,7 @@
|
|||
(def regx-string-public-key "0x04[0-9a-f]{128}")
|
||||
(def regx-compressed-key (re-pattern (str "^" regx-string-compressed-key "$")))
|
||||
(def regx-public-key (re-pattern (str "^" regx-string-public-key "$")))
|
||||
(def regx-private-key #"^0x[0-9a-fA-F]{64}$")
|
||||
(def regx-emoji
|
||||
#"^((?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F|[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF])+$")
|
||||
(def regx-bold #"\*[^*]+\*")
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
(ns status-im.contexts.wallet.add-account.create-account.import-private-key.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def input
|
||||
{:margin-top 12
|
||||
:padding-horizontal 20})
|
||||
|
||||
(def indicator
|
||||
{:padding-horizontal 20
|
||||
:padding-vertical 8})
|
||||
|
||||
(def info-box
|
||||
{:margin-bottom 20})
|
||||
|
||||
(def page-top
|
||||
{:margin-top 2})
|
||||
|
||||
(def key-section
|
||||
{:margin-top 22
|
||||
:padding-horizontal 20})
|
||||
|
||||
(def section-label
|
||||
{:margin-bottom 8})
|
||||
|
||||
(defn public-address
|
||||
[state theme]
|
||||
(let [border-color (case state
|
||||
:active-address (colors/resolve-color :success theme 40)
|
||||
:inactive-address (colors/resolve-color :warning theme 40)
|
||||
colors/neutral-20)]
|
||||
{:border-width 1
|
||||
:border-color border-color
|
||||
:border-style :dashed
|
||||
:border-radius 16
|
||||
:padding-vertical 8
|
||||
:padding-horizontal 12}))
|
|
@ -0,0 +1,133 @@
|
|||
(ns status-im.contexts.wallet.add-account.create-account.import-private-key.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as theme]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.contexts.wallet.add-account.create-account.import-private-key.style :as style]
|
||||
[status-im.contexts.wallet.common.validation :as v]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- address-input
|
||||
[{:keys [input-value set-input-value set-flow-state error?]}]
|
||||
(let [check-address (rn/use-callback
|
||||
(debounce/debounce (fn [v]
|
||||
(if (empty? v)
|
||||
(set-flow-state nil)
|
||||
;; TODO check for validation
|
||||
(if-not (v/private-key? v)
|
||||
(set-flow-state :invalid-private-key)
|
||||
;; TODO add real requests
|
||||
(do
|
||||
(set-flow-state :scanning)
|
||||
(js/setTimeout
|
||||
set-flow-state
|
||||
400
|
||||
(rand-nth [:active-address :inactive-address]))))))
|
||||
500))
|
||||
on-change (rn/use-callback
|
||||
(fn [v]
|
||||
(set-input-value v)
|
||||
(check-address v)))
|
||||
on-paste (rn/use-callback
|
||||
(fn []
|
||||
(clipboard/get-string
|
||||
(fn [clipboard]
|
||||
(when-not (empty? clipboard)
|
||||
(on-change clipboard))))))]
|
||||
[quo/input
|
||||
{:accessibility-label :add-address-to-watch
|
||||
:placeholder (i18n/label :t/enter-private-key-placeholder)
|
||||
:container-style style/input
|
||||
:label (i18n/label :t/private-key)
|
||||
:type :password
|
||||
:error? error?
|
||||
:return-key-type :done
|
||||
:on-change-text on-change
|
||||
:button (when (empty? input-value)
|
||||
{:on-press on-paste
|
||||
:text (i18n/label :t/paste)})
|
||||
:value input-value}]))
|
||||
|
||||
(defn- activity-indicator
|
||||
[state]
|
||||
(let [{:keys [message] :as props}
|
||||
(case state
|
||||
:scanning
|
||||
{:type :info
|
||||
:icon :i/scanning
|
||||
:message :t/scanning-for-activity}
|
||||
|
||||
:inactive-address
|
||||
{:type :warning
|
||||
:icon :i/info
|
||||
:message :t/this-account-has-no-activity}
|
||||
|
||||
:active-address
|
||||
{:type :success
|
||||
:icon :i/done
|
||||
:message :t/this-address-has-activity}
|
||||
|
||||
:invalid-private-key
|
||||
{:type :error
|
||||
:icon :i/info
|
||||
:message :t/invalid-private-key}
|
||||
|
||||
nil)]
|
||||
(when props
|
||||
[quo/info-message
|
||||
(assoc props
|
||||
:size :default
|
||||
:style style/indicator)
|
||||
(i18n/label message)])))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [theme (theme/use-theme)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
[input-value set-input-value] (rn/use-state "")
|
||||
[flow-state set-flow-state] (rn/use-state)
|
||||
error? (= :invalid-private-key flow-state)]
|
||||
[rn/view {:flex 1}
|
||||
[floating-button-page/view
|
||||
{:customization-color customization-color
|
||||
:header [quo/page-nav
|
||||
{:background :white
|
||||
:type :no-title
|
||||
:icon-name :i/close
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
:footer [:<>
|
||||
(when-not (#{:active-address :inactive-address} flow-state)
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:icon :i/info
|
||||
:style style/info-box}
|
||||
(i18n/label :t/import-private-key-info)])
|
||||
[quo/button
|
||||
{:customization-color customization-color
|
||||
:disabled? (or (empty? input-value) error?)
|
||||
:on-press #()}
|
||||
(i18n/label :t/continue)]]}
|
||||
[quo/page-top
|
||||
{:container-style style/page-top
|
||||
:title (i18n/label :t/import-private-key)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/enter-private-key)}]
|
||||
[address-input
|
||||
{:input-value input-value
|
||||
:set-input-value set-input-value
|
||||
:set-flow-state set-flow-state
|
||||
:error? error?}]
|
||||
(when (#{:scanning :active-address :inactive-address} flow-state)
|
||||
[rn/view {:style style/key-section}
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/private-key-public-address)
|
||||
:container-style style/section-label}]
|
||||
;; TODO Get real address
|
||||
[rn/view {:style (style/public-address flow-state theme)}
|
||||
[quo/text "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]]])
|
||||
(when (seq input-value)
|
||||
[activity-indicator flow-state])]]))
|
|
@ -5,6 +5,7 @@
|
|||
[react-native.core :as rn]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.add-account.create-account.select-keypair.style :as style]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.address :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
@ -22,7 +23,9 @@
|
|||
:add-divider? true}
|
||||
{:icon :i/key
|
||||
:accessibility-label :import-private-key
|
||||
:label (i18n/label :t/import-private-key)}]]])
|
||||
:label (i18n/label :t/import-private-key)
|
||||
:on-press (when (ff/enabled? ::wallet.import-private-key)
|
||||
#(rf/dispatch [:navigate-to :screen/wallet.import-private-key]))}]]])
|
||||
|
||||
(defn- parse-accounts
|
||||
[given-accounts]
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
|
||||
(defn ens-name? [s] (re-find constants/regx-ens s))
|
||||
(defn eth-address? [s] (re-find constants/regx-multichain-address s))
|
||||
(defn private-key? [s] (re-find constants/regx-private-key s))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
{::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)
|
||||
::wallet.edit-derivation-path (enabled-in-env? :FLAG_EDIT_DERIVATION_PATH)
|
||||
::wallet.remove-account (enabled-in-env? :FLAG_REMOVE_ACCOUNT_ENABLED)
|
||||
::wallet.import-private-key (enabled-in-env? :FLAG_IMPORT_PRIVATE_KEY_ENABLED)
|
||||
::wallet.long-press-watch-only-asset (enabled-in-env? :FLAG_LONG_PRESS_WATCH_ONLY_ASSET_ENABLED)
|
||||
::wallet.assets-modal-manage-tokens (enabled-in-env? :FLAG_ASSETS_MODAL_MANAGE_TOKENS)
|
||||
::wallet.assets-modal-hide (enabled-in-env? :FLAG_ASSETS_MODAL_HIDE)
|
||||
|
|
|
@ -70,6 +70,8 @@
|
|||
[status-im.contexts.wallet.add-account.add-address-to-watch.view :as wallet-add-address-to-watch]
|
||||
[status-im.contexts.wallet.add-account.create-account.edit-derivation-path.view :as
|
||||
wallet-edit-derivation-path]
|
||||
[status-im.contexts.wallet.add-account.create-account.import-private-key.view :as
|
||||
wallet-import-private-key]
|
||||
[status-im.contexts.wallet.add-account.create-account.new-keypair.backup-recovery-phrase.view :as
|
||||
wallet-backup-recovery-phrase]
|
||||
[status-im.contexts.wallet.add-account.create-account.new-keypair.check-your-backup.view :as
|
||||
|
@ -393,6 +395,10 @@
|
|||
{:name :screen/wallet.edit-derivation-path
|
||||
:component wallet-edit-derivation-path/view}
|
||||
|
||||
{:name :screen/wallet.import-private-key
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-import-private-key/view}
|
||||
|
||||
{:name :screen/wallet.collectible
|
||||
:component wallet-collectible/view}
|
||||
|
||||
|
|
|
@ -2579,5 +2579,13 @@
|
|||
"one-user-was-invited": "1 user was invited",
|
||||
"n-users-were-invited": "{{count}} users were invited",
|
||||
"invite-friend-to-status": "Invite friends to Status",
|
||||
"send-community-link": "Send community link"
|
||||
"send-community-link": "Send community link",
|
||||
"enter-private-key": "Enter the private key of an address",
|
||||
"enter-private-key-placeholder": "Enter your private key",
|
||||
"import-private-key-info": "New addresses cannot be derived from an account imported from a private key. Import using a seed phrase if you wish to derive addresses.",
|
||||
"invalid-private-key": "It’s not a valid private key",
|
||||
"private-key-public-address": "Public address of private key",
|
||||
"this-account-has-no-activity": "This account has no activity",
|
||||
"this-address-has-activity": "This address has activity",
|
||||
"scanning-for-activity": "Scanning for activity..."
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue