chore(wallet) import private key main screen (#19625)

Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
This commit is contained in:
Nikolay 2024-04-24 00:28:49 +03:00 committed by GitHub
parent 380603ddce
commit e6f9932dc5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 195 additions and 4 deletions

View File

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

View File

@ -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 #"\*[^*]+\*")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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": "Its 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..."
}