Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a81151be3a | ||
|
|
1da39e064d | ||
|
|
3899368aa0 | ||
|
|
5ff1c8f1e4 | ||
|
|
7289940653 | ||
|
|
a253f8cedb | ||
|
|
daf52102ce | ||
|
|
fa20d4d9c3 | ||
|
|
dd26fcf42c | ||
|
|
8ac9cc08e1 | ||
|
|
c1230319e1 | ||
|
|
1e48442d67 | ||
|
|
94fbbbcb3c | ||
|
|
4dfd616583 | ||
|
|
85d00e47af | ||
|
|
438fd7a512 | ||
|
|
ee5f73f5ee | ||
|
|
b49c0ae58a | ||
|
|
f474edf67d | ||
|
|
dfd90617bf | ||
|
|
9782ba2ac3 | ||
|
|
f0e0c95fe0 | ||
|
|
ef7d977299 | ||
|
|
70a5ed255f | ||
|
|
be1347346c | ||
|
|
803e83ae02 | ||
|
|
64748c939b | ||
|
|
64fb344197 | ||
|
|
f27b402205 | ||
|
|
b22744f81e | ||
|
|
174e44c77d |
@@ -267,9 +267,11 @@ run-metro: export TARGET := clojure
|
||||
run-metro: ##@run Start Metro to build React Native changes
|
||||
@scripts/run-metro.sh
|
||||
|
||||
export RE_FRISK_PORT ?= 4567
|
||||
|
||||
run-re-frisk: export TARGET := clojure
|
||||
run-re-frisk: ##@run Start re-frisk server
|
||||
yarn shadow-cljs run re-frisk-remote.core/start
|
||||
yarn shadow-cljs run re-frisk-remote.core/start ${RE_FRISK_PORT}
|
||||
|
||||
# TODO: Migrate this to a Nix recipe, much the same way as nix/mobile/android/targets/release-android.nix
|
||||
run-android: export TARGET := android
|
||||
@@ -443,7 +445,7 @@ android-ports: export RCT_METRO_PORT ?= 8081
|
||||
android-ports: ##@other Add proxies to Android Device/Simulator
|
||||
adb reverse tcp:$(RCT_METRO_PORT) tcp:$(RCT_METRO_PORT) && \
|
||||
adb reverse tcp:3449 tcp:3449 && \
|
||||
adb reverse tcp:4567 tcp:4567 && \
|
||||
adb reverse tcp:$(RE_FRISK_PORT) tcp:$(RE_FRISK_PORT) && \
|
||||
adb reverse tcp:$(FLOWSTORM_PORT) tcp:$(FLOWSTORM_PORT) && \
|
||||
adb forward tcp:5561 tcp:5561
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
- [Patching](patching.md)
|
||||
- [Creating a pixel perfect UI](pixel-perfection.md)
|
||||
- [Contributing to status-go](status-go-changes.md)
|
||||
- [Status Backend Server](use-status-backend-server.md)
|
||||
- [Malli schemas (recorded demo)](https://www.youtube.com/watch?v=SlRio70aYVI) ([slides](files/forging-code-with-schemas-sep-2023-slides.pdf))
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ callPackage, lib, buildGoPackage
|
||||
{ callPackage, lib, buildGoPackage, pkgs
|
||||
, androidPkgs, openjdk, gomobile, xcodeWrapper, removeReferencesTo
|
||||
, go-bindata, mockgen, protobuf3_20, protoc-gen-go
|
||||
, meta
|
||||
@@ -15,6 +15,8 @@ let
|
||||
isIOS = platform == "ios";
|
||||
isAndroid = platform == "android";
|
||||
enforceXCodeAvailable = callPackage ./enforceXCodeAvailable.nix { };
|
||||
# Fixes fatal: not a git repository (or any of the parent directories): .git
|
||||
fakeGit = pkgs.writeScriptBin "git" "echo ${source.version}";
|
||||
|
||||
in buildGoPackage rec {
|
||||
pname = source.repo;
|
||||
@@ -29,7 +31,7 @@ in buildGoPackage rec {
|
||||
|
||||
extraSrcPaths = [ gomobile ];
|
||||
nativeBuildInputs = [
|
||||
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20
|
||||
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20 fakeGit
|
||||
] ++ optional isAndroid openjdk
|
||||
++ optional isIOS xcodeWrapper;
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 156 KiB |
@@ -37,6 +37,8 @@ SECRETS_ENV_VARS=(
|
||||
'ALCHEMY_ARBITRUM_SEPOLIA_TOKEN'
|
||||
'ALCHEMY_OPTIMISM_MAINNET_TOKEN'
|
||||
'ALCHEMY_OPTIMISM_SEPOLIA_TOKEN'
|
||||
'ALCHEMY_BASE_MAINNET_TOKEN'
|
||||
'ALCHEMY_BASE_SEPOLIA_TOKEN'
|
||||
'RARIBLE_MAINNET_API_KEY'
|
||||
'RARIBLE_TESTNET_API_KEY'
|
||||
'INFURA_TOKEN'
|
||||
|
||||
+9
-3
@@ -58,7 +58,7 @@
|
||||
:preloads [;; The official recommendation is to
|
||||
;; load the debugger preload first.
|
||||
flow-storm.api
|
||||
re-frisk-remote.preload
|
||||
dev.re-frisk-preload
|
||||
status-im.setup.schema-preload
|
||||
;; In order to use component test helpers in the REPL we need to
|
||||
;; preload namespaces that are not normally required by
|
||||
@@ -87,7 +87,9 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"}
|
||||
:compiler-options {:output-feature-set :es5
|
||||
;; We disable `:fn-deprecated` warnings because we
|
||||
;; are managing deprecation via clj-kondo and we
|
||||
@@ -123,7 +125,9 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"}
|
||||
:compiler-options {:output-feature-set :es6
|
||||
;;disable for android build as there
|
||||
;;is an intermittent warning with deftype
|
||||
@@ -165,6 +169,8 @@
|
||||
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_MAINNET_TOKEN #shadow/env "ALCHEMY_BASE_MAINNET_TOKEN"
|
||||
status-im.config/ALCHEMY_BASE_SEPOLIA_TOKEN #shadow/env "ALCHEMY_BASE_SEPOLIA_TOKEN"
|
||||
status-im.config/WALLET_CONNECT_PROJECT_ID #shadow/env "WALLET_CONNECT_PROJECT_ID"}
|
||||
:compiler-options
|
||||
{;; needed because we override require and it
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
(ns dev.re-frisk-preload
|
||||
(:require [re-frisk-remote.core :as re-frisk-remote]
|
||||
[status-im.config]))
|
||||
|
||||
(re-frisk-remote/enable {:host (str status-im.config/re-frisk-host ":" status-im.config/re-frisk-port)})
|
||||
@@ -0,0 +1,43 @@
|
||||
(ns ^{:doc "Mailserver events and API"} legacy.status-im.mailserver.core
|
||||
(:require
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn handle-mailserver-changed
|
||||
[{:keys [db]} ms]
|
||||
(when (seq ms)
|
||||
{:db (assoc db :mailserver/current-id (keyword ms))}))
|
||||
|
||||
(rf/defn handle-mailserver-available
|
||||
[{:keys [db]} ms]
|
||||
{:db (assoc db :mailserver/current-id (keyword ms))})
|
||||
|
||||
(rf/defn toggle-use-mailservers
|
||||
[_ value]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_toggleUseMailservers"
|
||||
:params [value]
|
||||
:on-success #(log/info "successfully toggled use-mailservers" value)
|
||||
:on-error #(log/error "failed to toggle use-mailserver" value %)}]})
|
||||
|
||||
(rf/defn update-use-mailservers
|
||||
{:events [:mailserver.ui/use-history-switch-pressed]}
|
||||
[cofx use-mailservers?]
|
||||
(rf/merge cofx
|
||||
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
|
||||
(toggle-use-mailservers use-mailservers?)))
|
||||
|
||||
(defn add-mailservers
|
||||
[db mailservers]
|
||||
(reduce (fn [db {:keys [fleet id name] :as mailserver}]
|
||||
(let [updated-mailserver
|
||||
(-> mailserver
|
||||
(update :id keyword)
|
||||
(assoc :name (if (seq name) name id))
|
||||
(dissoc :fleet))]
|
||||
(assoc-in db
|
||||
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
||||
updated-mailserver)))
|
||||
db
|
||||
mailservers))
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns legacy.status-im.subs.mailservers
|
||||
(:require
|
||||
[legacy.status-im.fleet.core :as fleet]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
@@ -17,10 +16,3 @@
|
||||
:<- [:mailserver/mailservers]
|
||||
(fn [[current-fleet mailservers]]
|
||||
(current-fleet mailservers)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver/preferred-id
|
||||
:<- [:profile/profile]
|
||||
(fn [multiaccount]
|
||||
(get-in multiaccount
|
||||
[:pinned-mailservers (fleet/current-fleet-sub multiaccount)])))
|
||||
|
||||
@@ -38,11 +38,6 @@
|
||||
;;mailserver
|
||||
(reg-root-key-sub :mailserver/current-id :mailserver/current-id)
|
||||
(reg-root-key-sub :mailserver/mailservers :mailserver/mailservers)
|
||||
(reg-root-key-sub :mailserver.edit/mailserver :mailserver.edit/mailserver)
|
||||
(reg-root-key-sub :mailserver/state :mailserver/state)
|
||||
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
|
||||
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
|
||||
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
|
||||
|
||||
;;contacts
|
||||
(reg-root-key-sub :contacts/contacts-raw :contacts/contacts)
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.offline-messaging-settings.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.utils.styles :as styles]))
|
||||
|
||||
(def wrapper
|
||||
{:flex 1})
|
||||
|
||||
(styles/defn mailserver-item
|
||||
[]
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 16
|
||||
:ios {:height 64}
|
||||
:android {:height 56}})
|
||||
|
||||
(def mailserver-item-name-text
|
||||
{:typography :title})
|
||||
|
||||
(def switch-container
|
||||
{:height 52})
|
||||
|
||||
(def automatic-selection-container
|
||||
{:border-top-width 1
|
||||
:border-top-color colors/gray-lighter
|
||||
:margin-top 16})
|
||||
|
||||
(def explanation-text
|
||||
{:color colors/gray})
|
||||
|
||||
(def use-history-explanation-text-container
|
||||
{:margin-right 16
|
||||
:margin-left 16
|
||||
:margin-top 8
|
||||
:margin-bottom 16})
|
||||
|
||||
(def history-nodes-label
|
||||
{:color colors/gray
|
||||
:padding-horizontal 16
|
||||
:margin-top 48})
|
||||
@@ -1,88 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.offline-messaging-settings.views
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.offline-messaging-settings.styles :as styles]
|
||||
[legacy.status-im.ui.screens.profile.components.views :as profile.components]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn pinned-state
|
||||
[pinned?]
|
||||
[react/view {:style styles/automatic-selection-container}
|
||||
[react/view {:style styles/switch-container}
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/mailserver-automatic
|
||||
:value (not pinned?)
|
||||
:action-fn #(if pinned?
|
||||
(re-frame/dispatch [:mailserver.ui/unpin-pressed])
|
||||
(re-frame/dispatch [:mailserver.ui/pin-pressed]))}]]
|
||||
[react/view {:style {:padding-horizontal 16}}
|
||||
[react/text {:style styles/explanation-text}
|
||||
(i18n/label :t/mailserver-automatic-switch-explanation)]]])
|
||||
|
||||
(defn render-row
|
||||
[{:keys [name id custom]} _ _ {:keys [current-mailserver-id preferred-mailserver-id]}]
|
||||
(let [pinned? preferred-mailserver-id
|
||||
connected? (= id current-mailserver-id)
|
||||
visible? (or pinned? ; show everything when auto selection is turned off
|
||||
(and (not pinned?) ; auto selection turned on
|
||||
(= current-mailserver-id id)))] ; show only the selected server
|
||||
|
||||
(when visible?
|
||||
[react/touchable-highlight
|
||||
{:on-press (when pinned?
|
||||
#(if custom
|
||||
(re-frame/dispatch [:mailserver.ui/custom-mailserver-selected id])
|
||||
(re-frame/dispatch [:mailserver.ui/default-mailserver-selected id])))
|
||||
:accessibility-label :mailserver-item}
|
||||
[react/view (styles/mailserver-item)
|
||||
[react/text {:style styles/mailserver-item-name-text}
|
||||
name]
|
||||
|
||||
(if pinned?
|
||||
[quo/radio {:value connected?}]
|
||||
[icons/icon :check {:color colors/blue}])]])))
|
||||
|
||||
(views/defview offline-messaging-settings
|
||||
[]
|
||||
(views/letsubs [current-mailserver-id [:mailserver/current-id]
|
||||
preferred-mailserver-id [:mailserver/preferred-id]
|
||||
mailservers [:mailserver/fleet-mailservers]
|
||||
{:keys [use-mailservers?]} [:profile/profile]]
|
||||
[react/view {:style styles/wrapper}
|
||||
[topbar/topbar
|
||||
{:title (i18n/label :t/history-nodes)
|
||||
:right-accessories
|
||||
[{:icon :main-icons/add-circle
|
||||
:on-press #(re-frame/dispatch [:mailserver.ui/add-pressed])}]}]
|
||||
|
||||
[react/scroll-view
|
||||
[react/view {:style styles/switch-container}
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/offline-messaging-use-history-nodes
|
||||
:value use-mailservers?
|
||||
:action-fn #(re-frame/dispatch [:mailserver.ui/use-history-switch-pressed
|
||||
(not use-mailservers?)])}]]
|
||||
[react/view {:style styles/use-history-explanation-text-container}
|
||||
[react/text {:style styles/explanation-text}
|
||||
(i18n/label :t/offline-messaging-use-history-explanation)]]
|
||||
|
||||
(when use-mailservers?
|
||||
[:<>
|
||||
[pinned-state preferred-mailserver-id]
|
||||
|
||||
[react/text {:style styles/history-nodes-label}
|
||||
(i18n/label :t/history-nodes)]
|
||||
[list/flat-list
|
||||
{:data (vals mailservers)
|
||||
:default-separator? false
|
||||
:key-fn :name
|
||||
:render-data {:current-mailserver-id current-mailserver-id
|
||||
:preferred-mailserver-id preferred-mailserver-id}
|
||||
:render-fn render-row}]])]]))
|
||||
@@ -12,7 +12,6 @@
|
||||
[legacy.status-im.ui.screens.help-center.views :as help-center]
|
||||
[legacy.status-im.ui.screens.log-level-settings.views :as log-level-settings]
|
||||
[legacy.status-im.ui.screens.notifications-settings.views :as notifications-settings]
|
||||
[legacy.status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings]
|
||||
[legacy.status-im.ui.screens.pairing.views :as pairing]
|
||||
[legacy.status-im.ui.screens.peers-stats :as peers-stats]
|
||||
[legacy.status-im.ui.screens.profile.seed.views :as profile.seed]
|
||||
@@ -113,9 +112,6 @@
|
||||
:options {:topBar (topbar-options (i18n/label :t/devices))
|
||||
:insets {:top? true}}
|
||||
:component pairing/installations}
|
||||
{:name :offline-messaging-settings
|
||||
:options {:insets {:top? true}}
|
||||
:component offline-messaging-settings/offline-messaging-settings}
|
||||
{:name :rpc-usage-info
|
||||
:options {:topBar (topbar-options :t/rpc-usage-info)
|
||||
:insets {:top? true}}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[quo.core :as quo]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.clipboard :as clipboard]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -67,10 +68,10 @@
|
||||
{:size :small
|
||||
:accessibility-label :offline-messages-settings-button
|
||||
:title (i18n/label :t/history-nodes)
|
||||
:on-press #(re-frame/dispatch [:navigate-to :offline-messaging-settings])
|
||||
:on-press (fn []
|
||||
(clipboard/set-string current-mailserver-name))
|
||||
:accessory :text
|
||||
:accessory-text (when use-mailservers? current-mailserver-name)
|
||||
:chevron true}]
|
||||
:accessory-text (when use-mailservers? current-mailserver-name)}]
|
||||
;; TODO(Ferossgp): Devider componemt
|
||||
[react/view
|
||||
{:height 1
|
||||
|
||||
@@ -253,15 +253,19 @@
|
||||
|
||||
(defn hash-typed-data
|
||||
"used for keycard"
|
||||
[data callback]
|
||||
(log/debug "[native-module] hash-typed-data")
|
||||
(.hashTypedData ^js (encryption) data callback))
|
||||
([data]
|
||||
(native-utils/promisify-native-module-call hash-typed-data data))
|
||||
([data callback]
|
||||
(log/debug "[native-module] hash-typed-data")
|
||||
(.hashTypedData ^js (encryption) data callback)))
|
||||
|
||||
(defn hash-typed-data-v4
|
||||
"used for keycard"
|
||||
[data callback]
|
||||
(log/debug "[native-module] hash-typed-data-v4")
|
||||
(.hashTypedDataV4 ^js (encryption) data callback))
|
||||
([data]
|
||||
(native-utils/promisify-native-module-call hash-typed-data-v4 data))
|
||||
([data callback]
|
||||
(log/debug "[native-module] hash-typed-data-v4")
|
||||
(.hashTypedDataV4 ^js (encryption) data callback)))
|
||||
|
||||
(defn send-transaction-with-signature
|
||||
"used for keycard"
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
selected? (assoc :border-top-color (colors/alpha color 0.4)
|
||||
:border-end-color (colors/alpha color 0.4)
|
||||
:border-bottom-color (colors/alpha color 0.2)
|
||||
:border-start-color (colors/alpha color 0.2))
|
||||
:border-start-color (colors/alpha color 0.2)
|
||||
:border-color nil)
|
||||
(zero? idx) (assoc :margin-left -4))))
|
||||
|
||||
(defn color-circle
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
[:scroll? {:optional true} [:maybe :boolean]]
|
||||
[:blur? {:optional true} [:maybe :boolean]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:buttons-container-style {:optional true} [:maybe :map]]]]]
|
||||
[:buttons-container-style {:optional true} [:maybe :map]]
|
||||
[:buttons-style {:optional true} [:maybe :map]]]]]
|
||||
:any])
|
||||
|
||||
(def ^:private role-icon
|
||||
@@ -43,10 +44,9 @@
|
||||
(defn- view-internal
|
||||
[{:keys [actions description description-text description-top-text error-message role button-one-label
|
||||
button-two-label blur? button-one-props button-two-props scroll? container-style
|
||||
buttons-container-style context-tag-props]}]
|
||||
buttons-container-style buttons-style context-tag-props]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view
|
||||
{:style (merge (style/container scroll? blur? theme) container-style)}
|
||||
[rn/view {:style (merge (style/container scroll? blur? theme) container-style)}
|
||||
(when (= description :top-error)
|
||||
[rn/view {:style style/error-message}
|
||||
[icon/icon
|
||||
@@ -82,7 +82,7 @@
|
||||
[button/button
|
||||
(merge
|
||||
{:size 40
|
||||
:container-style style/button-container
|
||||
:container-style (merge style/button-container buttons-style)
|
||||
:background (when (or blur? scroll?) :blur)
|
||||
:theme theme
|
||||
:accessibility-label :button-two}
|
||||
@@ -91,7 +91,7 @@
|
||||
[button/button
|
||||
(merge
|
||||
{:size 40
|
||||
:container-style style/button-container
|
||||
:container-style (merge style/button-container buttons-style)
|
||||
:background (when (or blur? scroll?) :blur)
|
||||
:theme theme
|
||||
:accessibility-label :button-one}
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
[variant-colors]
|
||||
{:color (:label variant-colors)})
|
||||
|
||||
(def counter-container
|
||||
(def right-label-container
|
||||
{:flex 1
|
||||
:align-items :flex-end})
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(defn- label-&-counter
|
||||
[{:keys [label current-chars char-limit variant-colors theme]}]
|
||||
(defn- label-line
|
||||
[{:keys [label label-right current-chars char-limit variant-colors theme]}]
|
||||
[rn/view
|
||||
{:accessibility-label :input-labels
|
||||
:style style/texts-container}
|
||||
@@ -18,17 +18,24 @@
|
||||
:weight :medium
|
||||
:size :paragraph-2}
|
||||
label]]
|
||||
(when-let [count-text (some->> char-limit
|
||||
(str current-chars "/"))]
|
||||
[rn/view {:style style/counter-container}
|
||||
(when label-right
|
||||
[rn/view {:style style/right-label-container}
|
||||
[text/text
|
||||
{:style (style/counter-color {:current-chars current-chars
|
||||
:char-limit char-limit
|
||||
:variant-colors variant-colors
|
||||
:theme theme})
|
||||
{:style (style/label-color variant-colors)
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
count-text]])])
|
||||
label-right]])
|
||||
(when char-limit
|
||||
(let [count-text (str current-chars "/" char-limit)]
|
||||
[rn/view {:style style/right-label-container}
|
||||
[text/text
|
||||
{:style (style/counter-color {:current-chars current-chars
|
||||
:char-limit char-limit
|
||||
:variant-colors variant-colors
|
||||
:theme theme})
|
||||
:weight :regular
|
||||
:size :paragraph-2}
|
||||
count-text]]))])
|
||||
|
||||
(defn- left-accessory
|
||||
[{:keys [variant-colors small? icon-name]}]
|
||||
@@ -65,7 +72,7 @@
|
||||
(defn- base-input
|
||||
[{:keys [blur? error? right-icon left-icon disabled? small? button
|
||||
label char-limit multiline? clearable? on-focus on-blur container-style input-container-style
|
||||
on-change-text on-char-limit-reach weight default-value on-clear placeholder]
|
||||
on-change-text on-char-limit-reach weight default-value on-clear placeholder label-right]
|
||||
:as props}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
ref (rn/use-ref-atom nil)
|
||||
@@ -115,10 +122,11 @@
|
||||
;; https://github.com/facebook/react-native/issues/27687
|
||||
modified-placeholder (if platform/android? (str "\u2009" placeholder) placeholder)]
|
||||
[rn/view {:style container-style}
|
||||
(when (or label char-limit)
|
||||
[label-&-counter
|
||||
(when (or label char-limit label-right)
|
||||
[label-line
|
||||
{:variant-colors variant-colors
|
||||
:label label
|
||||
:label-right label-right
|
||||
:current-chars char-count
|
||||
:char-limit char-limit
|
||||
:theme theme}])
|
||||
@@ -199,6 +207,7 @@
|
||||
- :on-clear - Function executed when the clear button is pressed.
|
||||
- :button - Map containing `:on-press` & `:text` keys, if provided renders a button
|
||||
- :label - A string to set as label for this input.
|
||||
- :label-right - Additional label aligned to the right
|
||||
- :char-limit - A number to set a maximum char limit for this input.
|
||||
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
|
||||
- :default-shown? - boolean to show password input initially
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
[{:keys [type on-press on-check disabled? checked? child]} customization-color theme]
|
||||
(if (= type :custom)
|
||||
child
|
||||
[rn/touchable-opacity
|
||||
{:on-press on-press}
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
(case type
|
||||
:options
|
||||
[icons/icon :i/options
|
||||
{:size 20
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}]
|
||||
|
||||
:checkbox
|
||||
[selectors/view
|
||||
{:type :checkbox
|
||||
@@ -36,6 +36,7 @@
|
||||
:accessibility-label :user-list-toggle-check
|
||||
:disabled? disabled?
|
||||
:on-change (when on-check on-check)}]
|
||||
|
||||
:close
|
||||
[text/text "not implemented"]
|
||||
[rn/view])]))
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
subtitle]]])
|
||||
|
||||
(defn- main-variant
|
||||
[{:keys [title subtitle button-label image max-height accessibility-label on-press]}]
|
||||
[{:keys [title subtitle button-label image max-height accessibility-label on-press button-type]}]
|
||||
[rn/view {:style style/main-variant}
|
||||
[rn/view {:style style/main-variant-text-container}
|
||||
[text/text
|
||||
@@ -58,7 +58,7 @@
|
||||
[button/button
|
||||
{:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:type :grey
|
||||
:type (or button-type :grey)
|
||||
:size 40
|
||||
:container-style style/main-button
|
||||
:theme :dark
|
||||
@@ -66,7 +66,8 @@
|
||||
button-label]])
|
||||
|
||||
(defn small-option-card
|
||||
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label]
|
||||
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label
|
||||
button-type container-style]
|
||||
:or {variant :main accessibility-label :small-option-card}}]
|
||||
(let [main-variant? (= variant :main)
|
||||
card-component (if main-variant? main-variant icon-variant)
|
||||
@@ -74,7 +75,7 @@
|
||||
(not main-variant?) style/icon-variant-height
|
||||
max-height (min max-height style/main-variant-height)
|
||||
:else style/main-variant-height)]
|
||||
[rn/view {:style (style/card card-height)}
|
||||
[rn/view {:style (merge (style/card card-height) container-style)}
|
||||
[card-component
|
||||
{:title title
|
||||
:subtitle subtitle
|
||||
@@ -82,4 +83,5 @@
|
||||
:on-press on-press
|
||||
:accessibility-label accessibility-label
|
||||
:image image
|
||||
:max-height max-height}]]))
|
||||
:max-height max-height
|
||||
:button-type button-type}]]))
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
:border-color (colors/theme-colors colors/neutral-20 dark-border theme)}))
|
||||
|
||||
(def text
|
||||
{:margin-left 8})
|
||||
{:flex 1
|
||||
:margin-left 8})
|
||||
|
||||
(def icon-container
|
||||
{:align-items :flex-end
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
:padding-bottom 2})
|
||||
|
||||
(defn title-style
|
||||
[{:keys [status theme]}]
|
||||
{:padding-left 4
|
||||
[{:keys [status theme networks-shown?]}]
|
||||
{:padding-left (if networks-shown? 4 0)
|
||||
:margin-top -1
|
||||
:color (when (= status :error)
|
||||
(colors/resolve-color :danger theme))})
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
:theme theme
|
||||
:blur? blur?})
|
||||
container-style)}
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:number (count networks)
|
||||
:size :size-16}
|
||||
networks]
|
||||
(when networks
|
||||
[preview-list/view
|
||||
{:type :network
|
||||
:number (count networks)
|
||||
:size :size-16}
|
||||
networks])
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/title-style {:status status
|
||||
:theme theme})}
|
||||
:style (style/title-style {:status status
|
||||
:theme theme
|
||||
:networks-shown? networks})}
|
||||
title]]))
|
||||
|
||||
@@ -30,13 +30,16 @@
|
||||
|
||||
(defn networks
|
||||
[values theme]
|
||||
(let [{:keys [ethereum optimism arbitrum]} values
|
||||
show-optimism? (and optimism
|
||||
(or (pos? (:amount optimism))
|
||||
(= (:amount optimism) "<0.01")))
|
||||
show-arbitrum? (and arbitrum
|
||||
(or (pos? (:amount arbitrum))
|
||||
(= (:amount arbitrum) "<0.01")))]
|
||||
(let [{:keys [ethereum optimism arbitrum base]} values
|
||||
show-optimism? (and optimism
|
||||
(or (pos? (:amount optimism))
|
||||
(= (:amount optimism) "<0.01")))
|
||||
show-arbitrum? (and arbitrum
|
||||
(or (pos? (:amount arbitrum))
|
||||
(= (:amount arbitrum) "<0.01")))
|
||||
show-base? (and base
|
||||
(or (pos? (:amount base))
|
||||
(= (:amount base) "<0.01")))]
|
||||
[rn/view
|
||||
{:style style/networks-container
|
||||
:accessibility-label :networks}
|
||||
@@ -56,6 +59,11 @@
|
||||
[network-amount
|
||||
{:network :arbitrum
|
||||
:amount (str (:amount arbitrum) " " (or (:token-symbol arbitrum) "ARB"))
|
||||
:theme theme}])
|
||||
(when show-base?
|
||||
[network-amount
|
||||
{:network :base
|
||||
:amount (str (:amount base) " " (or (:token-symbol base) "ETH"))
|
||||
:theme theme}])]))
|
||||
|
||||
(defn- view-internal
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
[:currency-symbol [:maybe [:or :string :keyword]]]
|
||||
[:hint-component {:optional true} [:maybe :schema.common/hiccup]]
|
||||
[:on-token-press {:optional true} [:maybe fn?]]
|
||||
[:on-swap [:maybe fn?]]
|
||||
[:on-swap {:optional true} [:maybe fn?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:error? [:maybe :boolean]]
|
||||
[:show-token-icon? {:optional true} [:maybe :boolean]]
|
||||
[:value [:maybe :string]]
|
||||
[:converted-value [:maybe :string]]]]]
|
||||
[:converted-value {:optional true} [:maybe :string]]
|
||||
[:swappable? {:optional true} [:maybe :boolean]]]]]
|
||||
:any])
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
|
||||
:padding-bottom 3})
|
||||
|
||||
(defn input-container
|
||||
[window-width]
|
||||
{:width (- window-width 120)
|
||||
(def input-container
|
||||
{:flex 1
|
||||
:margin-left 8
|
||||
:margin-right 8
|
||||
:flex-direction :row
|
||||
|
||||
@@ -20,17 +20,18 @@
|
||||
(string/upper-case (or (clj->js text) ""))])
|
||||
|
||||
(defn input-section
|
||||
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
window-width (:width (rn/get-window))]
|
||||
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol show-token-icon?
|
||||
swappable?]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/pressable
|
||||
{:style {:width "100%"
|
||||
:flex-direction :row}
|
||||
:on-press on-token-press}
|
||||
[token/view
|
||||
{:token token-symbol
|
||||
:size :size-32}]
|
||||
[rn/view {:style (style/input-container window-width)}
|
||||
(when show-token-icon?
|
||||
[token/view
|
||||
{:token token-symbol
|
||||
:size :size-32}])
|
||||
[rn/view {:style style/input-container}
|
||||
[rn/text-input
|
||||
{:style (style/text-input theme error?)
|
||||
:placeholder-text-color (style/placeholder-text theme)
|
||||
@@ -39,14 +40,15 @@
|
||||
:editable false
|
||||
:value value}]
|
||||
[token-name-text theme currency-symbol]]
|
||||
[button/button
|
||||
{:icon true
|
||||
:icon-only? true
|
||||
:size 32
|
||||
:on-press #(when on-swap (on-swap))
|
||||
:type :outline
|
||||
:accessibility-label :reorder}
|
||||
:i/reorder]]))
|
||||
(when swappable?
|
||||
[button/button
|
||||
{:icon true
|
||||
:icon-only? true
|
||||
:size 32
|
||||
:on-press #(when on-swap (on-swap))
|
||||
:type :outline
|
||||
:accessibility-label :reorder}
|
||||
:i/reorder])]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [token-symbol
|
||||
@@ -57,26 +59,33 @@
|
||||
on-swap
|
||||
converted-value
|
||||
hint-component
|
||||
currency-symbol]}]
|
||||
show-token-icon?
|
||||
currency-symbol
|
||||
swappable?]
|
||||
:or {show-token-icon? true
|
||||
swappable? true}}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
width (:width (rn/get-window))]
|
||||
[rn/view {:style (merge (style/main-container width) container-style)}
|
||||
[rn/view {:style style/amount-container}
|
||||
[input-section
|
||||
{:theme theme
|
||||
:token-symbol token-symbol
|
||||
:on-token-press on-token-press
|
||||
:value value
|
||||
:error? error?
|
||||
:on-swap on-swap
|
||||
:currency-symbol currency-symbol}]]
|
||||
{:theme theme
|
||||
:token-symbol token-symbol
|
||||
:on-token-press on-token-press
|
||||
:value value
|
||||
:error? error?
|
||||
:on-swap on-swap
|
||||
:currency-symbol currency-symbol
|
||||
:show-token-icon? show-token-icon?
|
||||
:swappable? swappable?}]]
|
||||
[divider-line/view {:container-style (style/divider theme)}]
|
||||
[rn/view {:style style/data-container}
|
||||
hint-component
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/converted-amount theme)}
|
||||
converted-value]]]))
|
||||
(when swappable?
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (style/converted-amount theme)}
|
||||
converted-value])]]))
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
:hermez (js/require "../resources/images/networks/Hermez.png")
|
||||
:optimism (js/require "../resources/images/networks/Optimism.png")
|
||||
:paraswap (js/require "../resources/images/networks/Paraswap.png")
|
||||
:base (js/require "../resources/images/networks/Base.png")
|
||||
:polygon (js/require "../resources/images/networks/Polygon.png")
|
||||
:scroll (js/require "../resources/images/networks/Scroll.png")
|
||||
:taiko (js/require "../resources/images/networks/Taiko.png")
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
(when (money/bignumber? (value-bn state))
|
||||
(money/greater-than (value-bn state) (upper-limit-bn state)))))
|
||||
|
||||
(defn- lower-limit-exceeded?
|
||||
(defn lower-limit-exceeded?
|
||||
[state]
|
||||
(and (lower-limit state)
|
||||
(when (money/bignumber? (value-bn state))
|
||||
@@ -78,16 +78,19 @@
|
||||
|
||||
(defn set-upper-limit
|
||||
[state limit]
|
||||
(when limit
|
||||
(if limit
|
||||
(-> state
|
||||
(assoc :upper-limit limit)
|
||||
recheck-errorness)))
|
||||
recheck-errorness)
|
||||
state))
|
||||
|
||||
(defn set-lower-limit
|
||||
[state limit]
|
||||
(-> state
|
||||
(assoc :lower-limit limit)
|
||||
recheck-errorness))
|
||||
(if limit
|
||||
(-> state
|
||||
(assoc :lower-limit limit)
|
||||
recheck-errorness)
|
||||
state))
|
||||
|
||||
(defn increase
|
||||
[state]
|
||||
|
||||
@@ -265,16 +265,11 @@
|
||||
:sub-label nil
|
||||
:chevron? false}))
|
||||
|
||||
;; TODO(OmarBasem): Requires design input.
|
||||
(defn show-qr-entry
|
||||
[public-key]
|
||||
(entry {:icon :i/qr-code
|
||||
:label (i18n/label :t/show-qr)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:universal-links/generate-profile-url
|
||||
{:public-key public-key
|
||||
:on-success #(rf/dispatch [:open-modal
|
||||
:share-contact])}]))
|
||||
:on-press #(rf/dispatch [:contacts/show-qr-code public-key])
|
||||
:danger? false
|
||||
:accessibility-label :show-qr-code
|
||||
:sub-label nil
|
||||
|
||||
@@ -73,10 +73,10 @@
|
||||
[{:keys [scroll-ref tabs selected-tab on-tab-change scroll-shared-value content customization-color]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[:<>
|
||||
[:f> banner-card-blur-layer scroll-shared-value
|
||||
[:f> banner-card-hiding-layer
|
||||
[banner-card-blur-layer scroll-shared-value
|
||||
[banner-card-hiding-layer
|
||||
(assoc content :scroll-shared-value scroll-shared-value :theme theme)]]
|
||||
[:f> banner-card-tabs-layer
|
||||
[banner-card-tabs-layer
|
||||
{:scroll-shared-value scroll-shared-value
|
||||
:selected-tab selected-tab
|
||||
:tabs tabs
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
:music (js/require "../resources/images/ui2/music.png")
|
||||
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
||||
:generate-keys (js/require "../resources/images/ui2/generate-keys.png")
|
||||
:generate-keys1 (js/require "../resources/images/ui2/generating-keys-1.png")
|
||||
:add-key-to-keycard (js/require "../resources/images/ui2/add-key-to-keycard.png")
|
||||
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
|
||||
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
||||
:use-recovery-phrase (js/require "../resources/images/ui2/recovery-phrase.png")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.common.signals.events
|
||||
(:require
|
||||
[legacy.status-im.chat.models.message :as models.message]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[legacy.status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||
[oops.core :as oops]
|
||||
[status-im.common.pairing.events :as pairing]
|
||||
@@ -63,6 +64,12 @@
|
||||
"messages.new"
|
||||
(messages.transport/sanitize-messages-and-process-response cofx event-js true)
|
||||
|
||||
"mailserver.changed"
|
||||
(mailserver/handle-mailserver-changed cofx (oops/oget event-js :id))
|
||||
|
||||
"mailserver.available"
|
||||
(mailserver/handle-mailserver-available cofx (oops/oget event-js :id))
|
||||
|
||||
"discovery.summary"
|
||||
(summary cofx (transforms/js->clj event-js))
|
||||
|
||||
|
||||
@@ -213,13 +213,15 @@
|
||||
|
||||
(defn save-profile-url
|
||||
[{:keys [db]} [public-key url]]
|
||||
(when url
|
||||
{:db
|
||||
(cond-> db
|
||||
(get-in db [:contacts/contacts public-key])
|
||||
(assoc-in [:contacts/contacts public-key :universal-profile-url] url)
|
||||
(= public-key (get-in db [:profile/profile :public-key]))
|
||||
(assoc-in [:profile/profile :universal-profile-url] url))}))
|
||||
(let [contact-from-key (get-in db [:contacts/contacts public-key])
|
||||
profile-public-key? (= public-key (get-in db [:profile/profile :public-key]))]
|
||||
(when url
|
||||
{:db (cond-> db
|
||||
contact-from-key
|
||||
(assoc-in [:contacts/contacts public-key :universal-profile-url] url)
|
||||
|
||||
profile-public-key?
|
||||
(assoc-in [:profile/profile :universal-profile-url] url))})))
|
||||
|
||||
(schema/=> save-profile-url
|
||||
[:=>
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
(goog-define ALCHEMY_ARBITRUM_SEPOLIA_TOKEN "")
|
||||
(goog-define ALCHEMY_OPTIMISM_MAINNET_TOKEN "")
|
||||
(goog-define ALCHEMY_OPTIMISM_SEPOLIA_TOKEN "")
|
||||
(goog-define ALCHEMY_BASE_MAINNET_TOKEN "")
|
||||
(goog-define ALCHEMY_BASE_SEPOLIA_TOKEN "")
|
||||
(goog-define WALLET_CONNECT_PROJECT_ID "87815d72a81d739d2a7ce15c2cfdefb3")
|
||||
(goog-define MIXPANEL_APP_ID "3350627")
|
||||
(goog-define MIXPANEL_TOKEN "5c73bda2d36a9f688a5ee45641fb6775")
|
||||
@@ -38,9 +40,11 @@
|
||||
(def mainnet-tx-details-base-link "https://etherscan.io/tx")
|
||||
(def optimism-mainnet-tx-details-base-link "https://optimistic.etherscan.io/tx")
|
||||
(def arbitrum-mainnet-tx-details-base-link "https://arbiscan.io/tx")
|
||||
(def base-mainnet-tx-details-base-link "https://basescan.org/tx")
|
||||
(def mainnet-sepolia-tx-details-base-link "https://sepolia.etherscan.io/tx")
|
||||
(def optimism-sepolia-tx-details-base-link "https://sepolia-optimistic.etherscan.io/tx")
|
||||
(def arbitrum-sepolia-tx-details-base-link "https://sepolia.arbiscan.io/tx")
|
||||
(def base-sepolia-tx-details-base-link "https://sepolia.basescan.org/tx")
|
||||
(def opensea-link "https://opensea.io")
|
||||
(def opensea-tesnet-link "https://testnets.opensea.io")
|
||||
|
||||
@@ -124,3 +128,6 @@
|
||||
(goog-define STATUS_BACKEND_SERVER_ROOT_DATA_DIR "")
|
||||
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
|
||||
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")
|
||||
|
||||
(def re-frisk-host (get-config :RE_FRISK_HOST "localhost"))
|
||||
(def re-frisk-port (get-config :RE_FRISK_PORT "4567"))
|
||||
|
||||
@@ -221,10 +221,7 @@
|
||||
(def ^:const wallet-connect-eth-sign-typed-v4-method "eth_signTypedData_v4")
|
||||
(def ^:const wallet-connect-supported-methods
|
||||
#{wallet-connect-personal-sign-method
|
||||
wallet-connect-eth-sign-method
|
||||
wallet-connect-eth-send-transaction-method
|
||||
;; NOTE: disabled, as we have no clear use cases for it and other wallets don't support it
|
||||
;; wallet-connect-eth-sign-transaction-method
|
||||
wallet-connect-eth-sign-typed-method
|
||||
wallet-connect-eth-sign-typed-v4-method})
|
||||
(def ^:const wallet-connect-supported-events #{"accountsChanged" "chainChanged"})
|
||||
@@ -237,11 +234,9 @@
|
||||
(def ^:const wallet-connect-message-signing-methods
|
||||
#{wallet-connect-personal-sign-method
|
||||
wallet-connect-eth-sign-typed-method
|
||||
wallet-connect-eth-sign-method
|
||||
wallet-connect-eth-sign-typed-v4-method})
|
||||
(def ^:const wallet-connect-transaction-methods
|
||||
#{wallet-connect-eth-send-transaction-method
|
||||
wallet-connect-eth-sign-transaction-method})
|
||||
#{wallet-connect-eth-send-transaction-method})
|
||||
|
||||
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
|
||||
|
||||
@@ -396,29 +391,34 @@
|
||||
(def ^:const arbitrum-sepolia-chain-id 421614)
|
||||
(def ^:const optimism-mainnet-chain-id 10)
|
||||
(def ^:const optimism-sepolia-chain-id 11155420)
|
||||
(def ^:const base-mainnet-chain-id 8453)
|
||||
(def ^:const base-sepolia-chain-id 84532)
|
||||
|
||||
(def opensea-url-names
|
||||
{:ethereum "ethereum"
|
||||
:sepolia "sepolia"})
|
||||
|
||||
(def ^:const mainnet-chain-ids
|
||||
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id})
|
||||
#{ethereum-mainnet-chain-id arbitrum-mainnet-chain-id optimism-mainnet-chain-id base-mainnet-chain-id})
|
||||
|
||||
(def ^:const sepolia-chain-ids
|
||||
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id})
|
||||
#{ethereum-sepolia-chain-id arbitrum-sepolia-chain-id optimism-sepolia-chain-id base-sepolia-chain-id})
|
||||
|
||||
(def ^:const mainnet-short-name "eth")
|
||||
(def ^:const ethereum-short-name "eth")
|
||||
(def ^:const optimism-short-name "oeth")
|
||||
(def ^:const arbitrum-short-name "arb1")
|
||||
(def ^:const base-short-name "base")
|
||||
|
||||
(def ^:const mainnet-abbreviated-name "Eth.")
|
||||
(def ^:const optimism-abbreviated-name "Oeth.")
|
||||
(def ^:const arbitrum-abbreviated-name "Arb1.")
|
||||
(def ^:const base-abbreviated-name "Base")
|
||||
|
||||
(def ^:const mainnet-full-name "Mainnet")
|
||||
(def ^:const optimism-full-name "Optimism")
|
||||
(def ^:const arbitrum-full-name "Arbitrum")
|
||||
(def ^:const base-full-name "Base")
|
||||
|
||||
(def ^:const sepolia-full-name "Sepolia")
|
||||
|
||||
@@ -426,11 +426,13 @@
|
||||
(def ^:const ethereum-network-name :ethereum)
|
||||
(def ^:const optimism-network-name :optimism)
|
||||
(def ^:const arbitrum-network-name :arbitrum)
|
||||
(def ^:const base-network-name :base)
|
||||
|
||||
(def ^:const layer-1-network 1)
|
||||
(def ^:const layer-2-network 2)
|
||||
|
||||
(def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
|
||||
(def ^:const default-network-names
|
||||
[mainnet-network-name optimism-network-name arbitrum-network-name base-network-name])
|
||||
|
||||
(def ^:const default-network-count (count default-network-names))
|
||||
|
||||
|
||||
@@ -151,3 +151,12 @@
|
||||
error]]]})
|
||||
|
||||
(rf/reg-event-fx :contacts/update-nickname-error update-nickname-error)
|
||||
|
||||
(rf/reg-event-fx
|
||||
:contacts/show-qr-code
|
||||
(fn [{db :db} [public-key]]
|
||||
{:db (assoc db :contacts/identity public-key)
|
||||
:fx [[:dispatch
|
||||
[:universal-links/generate-profile-url
|
||||
{:public-key public-key
|
||||
:on-success #(rf/dispatch [:open-modal :share-contact])}]]]}))
|
||||
|
||||
@@ -114,13 +114,17 @@
|
||||
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})}])))
|
||||
|
||||
(defn- on-new-message-press
|
||||
[]
|
||||
(let [main-event [:show-bottom-sheet {:content chat.actions.view/new-chat}]]
|
||||
(rf/dispatch [:profile/check-profile-update-prompt main-event])))
|
||||
|
||||
(defn- banner-data
|
||||
[profile-link]
|
||||
{:title-props
|
||||
{:beta? true
|
||||
:label (i18n/label :t/messages)
|
||||
:handler #(rf/dispatch
|
||||
[:show-bottom-sheet {:content chat.actions.view/new-chat}])
|
||||
:handler on-new-message-press
|
||||
:accessibility-label :new-chat-button}
|
||||
:card-props
|
||||
{:on-press #(rf/dispatch [:open-share {:options {:url profile-link}}])
|
||||
|
||||
@@ -159,7 +159,9 @@
|
||||
[content]
|
||||
(reduce (fn [acc e]
|
||||
(conj acc (resolve-group-system-message e)))
|
||||
[quo/text]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:flex-wrap :wrap}}]
|
||||
(:parsed-text content)))
|
||||
|
||||
(defn group-system-message
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
(ns status-im.contexts.keycard.backup.events
|
||||
(:require [utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.generate-and-load-key
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [masked-phrase pin]} (get-in db [:keycard :backup])]
|
||||
{:fx [[:effects.keycard/generate-and-load-key
|
||||
{:mnemonic (security/safe-unmask-data masked-phrase)
|
||||
:pin pin
|
||||
:on-success (fn []
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.success]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]})))
|
||||
|
||||
(defn- ready-to-add-not-empty
|
||||
[error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error error])
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
|
||||
{:on-press #(rf/dispatch [:keycard/backup.ready-to-add-connect])}]))))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.ready-to-add-connect
|
||||
(fn [_]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch [:keycard/backup.generate-and-load-key])
|
||||
(ready-to-add-not-empty error)))}]]]}))
|
||||
|
||||
(defn- scan-empty-card-not-empty
|
||||
[error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error error])
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
|
||||
{:on-press #(rf/dispatch [:keycard/backup.scan-empty-card])}]))))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.scan-empty-card
|
||||
(fn [_]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:keycard/backup.create-or-enter-pin]))
|
||||
(scan-empty-card-not-empty error)))}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.save-pin
|
||||
(fn [{:keys [db]} [pin]]
|
||||
{:db (assoc-in db [:keycard :backup :pin] pin)}))
|
||||
|
||||
(defn- save-pin-and-navigate-to-phrase
|
||||
[pin]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/backup.save-pin pin])
|
||||
(rf/dispatch
|
||||
[:open-modal :screen/use-recovery-phrase-dark
|
||||
{:on-success #(rf/dispatch [:keycard/backup.phrase-entered %])}]))
|
||||
|
||||
(defn- verify-entered-pin-and-continue
|
||||
[pin]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch
|
||||
[:keycard/verify-pin
|
||||
{:pin pin
|
||||
:on-success #(save-pin-and-navigate-to-phrase pin)
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}])
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]))
|
||||
|
||||
(declare init-card-not-empty)
|
||||
|
||||
(defn- init-card-with-pin-and-continue
|
||||
[pin]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch
|
||||
[:keycard/init-card
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch
|
||||
[:keycard/get-application-info
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(save-pin-and-navigate-to-phrase pin)
|
||||
(init-card-not-empty pin error)))}])}])
|
||||
(init-card-not-empty pin error)))}]))
|
||||
|
||||
(defn- init-card-not-empty
|
||||
[pin error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error error])
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
|
||||
{:on-press #(init-card-with-pin-and-continue pin)}]))))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.create-or-enter-pin
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [initialized?]} (get-in db [:keycard :application-info])]
|
||||
{:fx [[:dispatch [:navigate-back]]
|
||||
(if initialized?
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.pin.enter
|
||||
{:on-complete verify-entered-pin-and-continue}]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.pin.create
|
||||
{:on-complete init-card-with-pin-and-continue}]])]})))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.phrase-entered
|
||||
(fn [{:keys [db]} [{:keys [phrase]}]]
|
||||
{:db (assoc-in db [:keycard :backup :masked-phrase] phrase)
|
||||
:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch [:open-modal :screen/keycard.backup.ready-to-add]]]}))
|
||||
@@ -0,0 +1,96 @@
|
||||
(ns status-im.contexts.keycard.backup.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn ready-to-add
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/ready-add-keypair-keycard)}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration)}]]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/scan-keycard)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/backup.ready-to-add-connect])}}]])
|
||||
|
||||
(defn success-view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/backup-keycard-created)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/done)]]])
|
||||
|
||||
(defn not-empty-view
|
||||
[]
|
||||
(let [{:keys [on-press]} (rf/sub [:get-screen-params])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-not-empty)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/scan-empty-keycard)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[common.view/tips]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press on-press}
|
||||
(i18n/label :t/try-again)]]]))
|
||||
|
||||
(defn scan-empty
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/scan-empty-keycard)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/backup-empty-keycard-only)}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :check-your-keycard)}]]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/backup.scan-empty-card])}}]])
|
||||
|
||||
(defn sheet
|
||||
[{:keys [on-continue]}]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/create-backup-keycard)}]
|
||||
[quo/text
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-vertical 8}}
|
||||
(i18n/label :t/backup-keycard-instructions)]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(on-continue))}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:type :grey
|
||||
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
|
||||
@@ -0,0 +1,25 @@
|
||||
(ns status-im.contexts.keycard.check.events
|
||||
(:require [utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :keycard/check-empty-card
|
||||
(fn [{:keys [db]}]
|
||||
(let [keycard-profile? (not (nil? (get-in db [:profile/profile :keycard-pairing])))]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid (get-in db [:profile/profile :key-uid])
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if keycard-profile?
|
||||
(rf/dispatch [:open-modal :screen/keycard.manage.profile-keys])
|
||||
(rf/dispatch [:open-modal :screen/keycard.migrate.profile-keys])))
|
||||
:on-error
|
||||
(fn [error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (and (= error :keycard/error.keycard-blank)
|
||||
(not keycard-profile?))
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.empty]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]})))
|
||||
@@ -3,16 +3,40 @@
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- keycard-documentation
|
||||
[]
|
||||
[quo/documentation-drawers
|
||||
{:title (i18n/label :t/keycard)
|
||||
:shell? true}
|
||||
[rn/view
|
||||
[quo/text {:size :paragraph-2}
|
||||
(i18n/label :t/keycard-documentation)]
|
||||
[quo/button
|
||||
{:size 40
|
||||
:type :primary
|
||||
:container-style {:margin-top 24 :margin-bottom 12}
|
||||
:background :blur
|
||||
:icon-right :i/external
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])
|
||||
:accessibility-label :get-keycard}
|
||||
(i18n/label :t/buy-keycard)]]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [on-press]} (rf/sub [:get-screen-params])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content keycard-documentation
|
||||
:shell? true}])}]}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/check-keycard)
|
||||
:description :text
|
||||
@@ -21,9 +45,7 @@
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :check-your-keycard)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
(ns status-im.contexts.keycard.common.view
|
||||
(:require [quo.core :as quo]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn tips
|
||||
[]
|
||||
[:<>
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
|
||||
@@ -90,7 +90,7 @@
|
||||
(cond
|
||||
|
||||
(not initialized?)
|
||||
{:fx [[:keycard/init-card
|
||||
{:fx [[:effects.keycard/init-card
|
||||
{:pin pin
|
||||
:on-success get-application-info-and-continue}]]}
|
||||
|
||||
@@ -106,3 +106,10 @@
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch [:keycard.login/recover-profile-and-login %])
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.seed-phrase-entered
|
||||
(fn [{:keys [db]} [key-uid masked-seed-phrase]]
|
||||
(if (contains? (:profile/profiles-overview db) key-uid)
|
||||
{:fx [[:dispatch [:onboarding/multiaccount-already-exists key-uid]]]}
|
||||
{:db (assoc-in db [:keycard :create :masked-phrase] masked-seed-phrase)
|
||||
:fx [[:dispatch [:keycard/create.create-or-enter-pin]]]})))
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -35,28 +38,27 @@
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
|
||||
[common.view/tips]])
|
||||
|
||||
(defn ready-to-add
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [(when config/show-not-implemented-features?
|
||||
{:icon-name :i/info
|
||||
:on-press not-implemented/alert})]}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/ready-add-keypair-keycard)
|
||||
:description :text
|
||||
:description-text ""}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :generate-keys1)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:style {:flex 1 :align-self :center :margin-vertical 37}
|
||||
:source (resources/get-image :add-key-to-keycard)}]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-label (i18n/label :t/scan-keycard)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/create.start])}}]])
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
(ns status-im.contexts.keycard.different-card.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/different-keycard)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/scan-previous-keycard)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
||||
@@ -52,6 +52,14 @@
|
||||
(fn [args]
|
||||
(keycard/export-key (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/factory-reset
|
||||
(fn [args]
|
||||
(keycard/factory-reset (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/verify-pin
|
||||
(fn [args]
|
||||
(keycard/verify-pin (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign
|
||||
(fn [args]
|
||||
(-> (keycard/sign args)
|
||||
@@ -71,7 +79,7 @@
|
||||
(promesa/then on-success)
|
||||
(promesa/catch (keycard.utils/get-on-failure args)))))
|
||||
|
||||
(rf/reg-fx :keycard/init-card
|
||||
(rf/reg-fx :effects.keycard/init-card
|
||||
(fn [args]
|
||||
(keycard/init-card (keycard.utils/wrap-handlers args))))
|
||||
|
||||
|
||||
@@ -17,19 +17,27 @@
|
||||
{:title (i18n/label :t/keycard-empty)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/what-to-do)}]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/create-new-profile)
|
||||
:subtitle (i18n/label :t/new-key-pair-keycard)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :create-new-profile-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 32 :margin-horizontal 28}}
|
||||
(i18n/label :t/add-key-pair-desktop)]])
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/create-new-profile)
|
||||
:subtitle (i18n/label :t/new-key-pair-keycard)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :create-new-profile-keycard
|
||||
:container-style {:margin-horizontal 20 :margin-top 8}
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:button-type :primary
|
||||
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/import-recovery-phrase-to-keycard)
|
||||
:subtitle (i18n/label :t/store-key-pair-on-keycard)
|
||||
:accessibility-label :import-recovery-phrase-to-keycard
|
||||
:container-style {:margin 20}
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/use-recovery-phrase-dark
|
||||
{:on-success (fn [{:keys [key-uid phrase]}]
|
||||
(rf/dispatch [:keycard/create.seed-phrase-entered
|
||||
key-uid phrase]))}])}]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.contexts.keycard.backup.view :as backup.view]
|
||||
[status-im.contexts.keycard.factory-reset.view :as factory-reset]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -31,7 +33,31 @@
|
||||
:description-text description}]
|
||||
[rn/view {:style {:margin-horizontal 20}}
|
||||
[quo/keycard {:holder-name ""}]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 20}}
|
||||
(i18n/label :t/unlock-reset-instructions)]]]))
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/use-backup-keycard)
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[backup.view/sheet
|
||||
{:on-continue
|
||||
(rf/dispatch
|
||||
[:keycard/backup.create-or-enter-pin])}])}]))}]
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/factory-reset)
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/remove-keycard-content)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content factory-reset/sheet}]))}])]]))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
(ns status-im.contexts.keycard.events
|
||||
(:require [re-frame.core :as rf]
|
||||
status-im.contexts.keycard.backup.events
|
||||
status-im.contexts.keycard.check.events
|
||||
status-im.contexts.keycard.create.events
|
||||
status-im.contexts.keycard.login.events
|
||||
status-im.contexts.keycard.migrate.events
|
||||
@@ -56,6 +58,10 @@
|
||||
[:keycard/on-application-info-error
|
||||
:keycard/error.keycard-locked]])]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard/init-card
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/init-card data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/get-keys
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/get-keys data}))
|
||||
@@ -68,6 +74,14 @@
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/export-key data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/factory-reset
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/factory-reset data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/verify-pin
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/verify-pin data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
|
||||
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
|
||||
{:fx [[:dispatch
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
(ns status-im.contexts.keycard.factory-reset.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- reset-card
|
||||
[]
|
||||
(rf/dispatch
|
||||
[:keycard/factory-reset
|
||||
{:on-success (fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.factory-reset.success]))
|
||||
:on-failure (fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.factory-reset.fail]))}]))
|
||||
|
||||
(defn- connect-and-reset
|
||||
[key-uid]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success reset-card
|
||||
:on-error (fn [error]
|
||||
(if (or (= error :keycard/error.keycard-frozen)
|
||||
(= error :keycard/error.keycard-locked)
|
||||
(= error :keycard/error.keycard-unpaired))
|
||||
(reset-card)
|
||||
(do
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.keycard-wrong-profile)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.different-card]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))))}]))
|
||||
|
||||
(defn success-view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-reset-success)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/keycard-empty-ready)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/done)]]])
|
||||
|
||||
(defn failed-view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-reset-failed)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
||||
(defn sheet
|
||||
[]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])
|
||||
key-uid (rf/sub [:keycard/key-uid])
|
||||
[checked? set-checked] (rn/use-state false)]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/factory-reset-keycard)}]
|
||||
[quo/text
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-top 8
|
||||
:padding-bottom 8}}
|
||||
(i18n/label :t/factory-reset-warning)]
|
||||
[quo/disclaimer
|
||||
{:checked? checked?
|
||||
:container-style {:margin-horizontal 20}
|
||||
:on-change #(set-checked (not checked?))}
|
||||
(i18n/label :t/key-pair-erased)]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:disabled? (not checked?)
|
||||
:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(connect-and-reset key-uid))}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:type :grey
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet]))}}]]))
|
||||
@@ -0,0 +1,40 @@
|
||||
(ns status-im.contexts.keycard.manage.profile-keys.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.contexts.keycard.backup.view :as backup.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- backup-sheet
|
||||
[]
|
||||
[backup.view/sheet
|
||||
{:on-continue
|
||||
(fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch
|
||||
[:open-modal :screen/keycard.backup.scan-empty]))}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title profile-name}]
|
||||
[rn/view {:style {:margin-horizontal 20}}
|
||||
[rn/view {:style {:padding-top 8 :padding-bottom 20}}
|
||||
[quo/keycard {:holder-name ""}]]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/backup-keycard)
|
||||
:image :icon
|
||||
:image-props :i/profile
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet {:content backup-sheet}]))}]]]))
|
||||
@@ -3,23 +3,6 @@
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.check-empty-card
|
||||
(fn [{:keys [db]}]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid (get-in db [:profile/profile :key-uid])
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.profile-keys]))
|
||||
:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.empty]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
|
||||
|
||||
(defn get-application-info-and-continue
|
||||
[key-uid]
|
||||
(rf/dispatch [:keycard/get-application-info
|
||||
@@ -40,7 +23,7 @@
|
||||
(cond
|
||||
|
||||
(not initialized?)
|
||||
{:fx [[:keycard/init-card
|
||||
{:fx [[:effects.keycard/init-card
|
||||
{:pin pin
|
||||
:on-success #(get-application-info-and-continue key-uid)}]]}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -26,9 +27,7 @@
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (if initialized? (i18n/label :t/enter-keycard-pin) (i18n/label :t/scan-keycard))
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :not-keycard)}]]
|
||||
[rn/view {:padding-horizontal 20}
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/try-again)]]])
|
||||
|
||||
@@ -76,3 +76,16 @@
|
||||
args
|
||||
:on-success (get-on-success args)
|
||||
:on-failure (get-on-failure args)))
|
||||
|
||||
(defn keycard-address?
|
||||
[keypairs address]
|
||||
(let [find-keycard-keypair (fn [kps] (some #(when-not (empty? (:keycards %)) %) kps))
|
||||
keypair-addresses (fn [kp]
|
||||
(->> (:accounts kp)
|
||||
(map :address)
|
||||
set))]
|
||||
(-> keypairs
|
||||
vals
|
||||
find-keycard-keypair
|
||||
keypair-addresses
|
||||
(contains? (string/lower-case address)))))
|
||||
|
||||
@@ -107,6 +107,19 @@
|
||||
[:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]]
|
||||
[:onboarding/create-account-and-login])]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:onboarding/multiaccount-already-exists
|
||||
(fn [_ [key-uid]]
|
||||
{:fx [[:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
|
||||
;; Note - Profile selection is not working
|
||||
(re-frame/dispatch [:profile/profile-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :screen/profile.profiles])}]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:onboarding/seed-phrase-validated
|
||||
(fn [{:keys [db]} [seed-phrase key-uid]]
|
||||
@@ -115,14 +128,7 @@
|
||||
:onboarding/navigated-to-enter-seed-phrase-from-screen
|
||||
:screen/onboarding.create-profile)]
|
||||
(if (contains? (:profile/profiles-overview db) key-uid)
|
||||
{:fx [[:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
|
||||
(re-frame/dispatch [:profile/profile-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}]]}
|
||||
{:fx [[:dispatch [:onboarding/multiaccount-already-exists key-uid]]]}
|
||||
{:db (-> db
|
||||
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
|
||||
(assoc-in [:onboarding/profile :key-uid] key-uid)
|
||||
|
||||
@@ -23,29 +23,31 @@
|
||||
:key :title}
|
||||
{:type :select
|
||||
:key :networks
|
||||
:options [{:key 1}
|
||||
:options [{:key 0}
|
||||
{:key 1}
|
||||
{:key 2}
|
||||
{:key 3}]}
|
||||
{:type :boolean
|
||||
:key :blur?}])
|
||||
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:title "Tag"
|
||||
:status :default
|
||||
:networks 3})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[rn/view
|
||||
{:style {:align-self :center
|
||||
:justify-content :center
|
||||
:flex 1}}
|
||||
[quo/network-tags
|
||||
(assoc @state
|
||||
:networks
|
||||
(nth community-networks (dec (:networks @state))))]]])))
|
||||
(let [selected-networks-id (dec (:networks @state))]
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[rn/view
|
||||
{:style {:align-self :center
|
||||
:justify-content :center
|
||||
:flex 1}}
|
||||
[quo/network-tags
|
||||
(assoc @state
|
||||
:networks
|
||||
(when (pos? selected-networks-id)
|
||||
(nth community-networks selected-networks-id)))]]]))))
|
||||
|
||||
@@ -22,21 +22,29 @@
|
||||
[{:key :token-symbol
|
||||
:type :select
|
||||
:options [{:key :eth}
|
||||
{:key :snt}]}
|
||||
{:key :snt}
|
||||
{:key :gwei}
|
||||
{:key :units}]}
|
||||
{:key :currency
|
||||
:type :select
|
||||
:options [{:key "$"}
|
||||
{:key "€"}]}
|
||||
{:key :error?
|
||||
:type :boolean}
|
||||
{:key :show-token-icon?
|
||||
:type :boolean}
|
||||
{:key :swappable?
|
||||
:type :boolean}])
|
||||
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:token-symbol :eth
|
||||
:currency "$"
|
||||
:crypto? true
|
||||
:error? false})]
|
||||
(let [state (reagent/atom {:token-symbol :eth
|
||||
:currency "$"
|
||||
:crypto? true
|
||||
:error? false
|
||||
:show-token-icon? true
|
||||
:swappable? true})]
|
||||
(fn []
|
||||
(let [{:keys [currency token-symbol crypto? error?]} @state
|
||||
[input-state set-input-state] (rn/use-state controlled-input/init-state)
|
||||
@@ -67,18 +75,20 @@
|
||||
:component-container-style {:flex 1
|
||||
:justify-content :space-between}}
|
||||
[quo/token-input
|
||||
{:token-symbol token-symbol
|
||||
:currency-symbol (if crypto? token-symbol currency)
|
||||
:error? error?
|
||||
:value input-amount
|
||||
:converted-value converted-value
|
||||
:on-swap (fn []
|
||||
(swap! state assoc :crypto? (not crypto?))
|
||||
(swap-between-fiat-and-crypto))
|
||||
:hint-component [quo/network-tags
|
||||
{:networks networks
|
||||
:title title
|
||||
:status (when (:error? @state) :error)}]}]
|
||||
{:token-symbol token-symbol
|
||||
:currency-symbol (if crypto? token-symbol currency)
|
||||
:error? error?
|
||||
:value input-amount
|
||||
:converted-value converted-value
|
||||
:on-swap (fn []
|
||||
(swap! state assoc :crypto? (not crypto?))
|
||||
(swap-between-fiat-and-crypto))
|
||||
:hint-component [quo/network-tags
|
||||
{:networks networks
|
||||
:title title
|
||||
:status (when (:error? @state) :error)}]
|
||||
:show-token-icon? (:show-token-icon? @state)
|
||||
:swappable? (:swappable? @state)}]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style {:padding-bottom (safe-area/get-top)}
|
||||
:left-action :dot
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
:alchemyOptimismMainnetToken config/ALCHEMY_OPTIMISM_MAINNET_TOKEN
|
||||
:alchemyOptimismSepoliaToken config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN
|
||||
:alchemyArbitrumMainnetToken config/ALCHEMY_ARBITRUM_MAINNET_TOKEN
|
||||
:alchemyArbitrumSepoliaToken config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN})
|
||||
:alchemyArbitrumSepoliaToken config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN
|
||||
:alchemyBaseMainnetToken config/ALCHEMY_BASE_MAINNET_TOKEN
|
||||
:alchemyBaseSepoliaToken config/ALCHEMY_BASE_SEPOLIA_TOKEN})
|
||||
|
||||
(defn create
|
||||
[]
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
[quo/drawer-top
|
||||
{:type :context-tag
|
||||
:context-tag-type :default
|
||||
:title (i18n/label :t/add-nickname-title)
|
||||
:title (if has-nickname?
|
||||
(i18n/label :t/edit-nickname)
|
||||
(i18n/label :t/add-nickname-title))
|
||||
:full-name full-name
|
||||
:profile-picture profile-picture
|
||||
:customization-color customization-color}]
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn on-contact-request
|
||||
(defn on-send-contact-request
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [contact-request/view])}]))
|
||||
(let [main-event [:show-bottom-sheet {:content contact-request/view}]]
|
||||
(rf/dispatch [:profile/check-profile-update-prompt main-event])))
|
||||
|
||||
(defn on-contact-review
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [contact-review/view])}]))
|
||||
(rf/dispatch [:show-bottom-sheet {:content contact-review/view}]))
|
||||
|
||||
(defn view
|
||||
[{:keys [scroll-y]}]
|
||||
@@ -34,27 +33,27 @@
|
||||
profile-picture (profile.utils/photo contact)
|
||||
online? (rf/sub [:visibility-status-updates/online? public-key])
|
||||
theme (quo.theme/use-theme)
|
||||
contact-status (rn/use-memo (fn []
|
||||
(cond
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-mutual) :contact
|
||||
blocked? :blocked
|
||||
:else nil))
|
||||
[blocked? contact-request-state])
|
||||
on-start-chat (rn/use-callback #(rf/dispatch [:chat.ui/start-chat
|
||||
public-key
|
||||
ens-name])
|
||||
[ens-name public-key])
|
||||
on-unblock-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:contact/unblock-contact
|
||||
public-key])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :user-unblocked
|
||||
:type :positive
|
||||
:text (i18n/label :t/user-unblocked
|
||||
{:username
|
||||
full-name})}]))
|
||||
[public-key full-name])]
|
||||
contact-status (rn/use-memo
|
||||
(fn []
|
||||
(cond
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-mutual) :contact
|
||||
blocked? :blocked
|
||||
:else nil))
|
||||
[blocked? contact-request-state])
|
||||
on-start-chat (rn/use-callback
|
||||
#(rf/dispatch [:chat.ui/start-chat public-key ens-name])
|
||||
[ens-name public-key])
|
||||
on-unblock-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:contact/unblock-contact
|
||||
public-key])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :user-unblocked
|
||||
:type :positive
|
||||
:text (i18n/label :t/user-unblocked
|
||||
{:username full-name})}]))
|
||||
[public-key full-name])]
|
||||
[rn/view {:style style/header-container}
|
||||
[rn/view {:style style/header-top-wrapper}
|
||||
[rn/view {:style style/avatar-wrapper}
|
||||
@@ -93,14 +92,12 @@
|
||||
|
||||
(cond
|
||||
(and (not blocked?)
|
||||
(or
|
||||
(not contact-request-state)
|
||||
(= contact-request-state constants/contact-request-state-none)
|
||||
(= contact-request-state constants/contact-request-state-dismissed)))
|
||||
|
||||
(or (not contact-request-state)
|
||||
(= contact-request-state constants/contact-request-state-none)
|
||||
(= contact-request-state constants/contact-request-state-dismissed)))
|
||||
[quo/button
|
||||
{:container-style style/button-wrapper
|
||||
:on-press on-contact-request
|
||||
:on-press on-send-contact-request
|
||||
:customization-color customization-color
|
||||
:icon-left :i/add-user}
|
||||
(i18n/label :t/send-contact-request)]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.contexts.profile.contact.share.style :as style]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
@@ -9,32 +10,32 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn navigation-back [] (rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [universal-profile-url customization-color]
|
||||
:as profile} (rf/sub [:contacts/current-contact])
|
||||
abbreviated-url (rn/use-memo (fn []
|
||||
(address/get-abbreviated-profile-url universal-profile-url))
|
||||
[universal-profile-url])
|
||||
on-share-press (rn/use-callback #(rf/dispatch [:open-share
|
||||
{:options {:message universal-profile-url}}])
|
||||
[universal-profile-url])
|
||||
on-copy-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message
|
||||
(i18n/label
|
||||
:t/link-to-profile-copied)}]))
|
||||
[universal-profile-url])]
|
||||
abbreviated-url (rn/use-memo
|
||||
(fn []
|
||||
(address/get-abbreviated-profile-url universal-profile-url))
|
||||
[universal-profile-url])
|
||||
on-share-press (rn/use-callback
|
||||
#(rf/dispatch [:open-share
|
||||
{:options {:message universal-profile-url}}])
|
||||
[universal-profile-url])
|
||||
on-copy-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}]))
|
||||
[universal-profile-url])]
|
||||
[quo/overlay {:type :shell}
|
||||
[rn/view
|
||||
{:style {:padding-top (safe-area/get-top)}
|
||||
:key :share-community}
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press navigation-back
|
||||
:on-press events-helper/navigate-back
|
||||
:background :blur
|
||||
:accessibility-label :top-bar}]
|
||||
[quo/page-top
|
||||
|
||||
@@ -4,27 +4,35 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-accent-colour-success
|
||||
(fn [_ [customization-color]]
|
||||
(fn [_ [{:keys [customization-color navigate-back? show-toast?]}]]
|
||||
{:fx [[:dispatch [:profile/save-local-accent-color customization-color]]
|
||||
[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/accent-colour-updated)}]]]}))
|
||||
(when navigate-back?
|
||||
[:dispatch [:navigate-back]])
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/accent-colour-updated)}]])]}))
|
||||
|
||||
(rf/reg-event-fx :profile/save-local-accent-color
|
||||
(fn [{:keys [db]} [customization-color]]
|
||||
{:db (assoc-in db [:profile/profile :customization-color] customization-color)}))
|
||||
|
||||
(defn edit-accent-colour
|
||||
[{:keys [db]} [customization-color]]
|
||||
[{:keys [db]}
|
||||
[{:keys [color navigate-back? show-toast?]
|
||||
:or {navigate-back? true
|
||||
show-toast? true}}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setCustomizationColor"
|
||||
:params [{:customizationColor customization-color
|
||||
:params [{:customizationColor color
|
||||
:keyUid key-uid}]
|
||||
:on-success [:profile/edit-accent-colour-success customization-color]
|
||||
:on-success [:profile/edit-accent-colour-success
|
||||
{:customization-color color
|
||||
:navigate-back? navigate-back?
|
||||
:show-toast? show-toast?}]
|
||||
:on-error #(log/error "failed to edit accent color." {:error %})}]]]}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-accent-colour edit-accent-colour)
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
[{:method "wakuext_setCustomizationColor"
|
||||
:params [{:customizationColor new-color
|
||||
:keyUid key-uid}]
|
||||
:on-success [:profile/edit-accent-colour-success new-color]
|
||||
:on-success [:profile/edit-accent-colour-success
|
||||
{:customization-color new-color
|
||||
:navigate-back? true
|
||||
:show-toast? true}]
|
||||
:on-error fn?}]]]}]
|
||||
(is (match? expected
|
||||
(sut/edit-accent-colour cofx [new-color])))))
|
||||
(sut/edit-accent-colour cofx [{:color new-color}])))))
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
{:type :primary
|
||||
:customization-color @unsaved-custom-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:profile/edit-accent-colour @unsaved-custom-color]))}
|
||||
(rf/dispatch [:profile/edit-accent-colour
|
||||
{:color @unsaved-custom-color}]))}
|
||||
(i18n/label :t/save-colour)]]]]))))
|
||||
|
||||
(defn view
|
||||
|
||||
@@ -5,27 +5,28 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/update-local-picture
|
||||
(fn [{:keys [db now]} [images]]
|
||||
(fn [{:keys [db]} [images]]
|
||||
{:db (if images
|
||||
(assoc-in db
|
||||
[:profile/profile :images]
|
||||
(map #(assoc % :clock now) images))
|
||||
(assoc-in db [:profile/profile :images] images)
|
||||
(update db :profile/profile dissoc :images))}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-profile-picture-success
|
||||
(fn [_ [images]]
|
||||
(let [has-picture? (rf/sub [:profile/has-picture])]
|
||||
(fn [{db :db} [{:keys [show-toast?]} images]]
|
||||
(let [has-picture? (-> db :profile/profile :images count pos?)]
|
||||
{:fx [[:dispatch [:profile/update-local-picture (reverse images)]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label (if has-picture?
|
||||
:t/profile-picture-updated
|
||||
:t/profile-picture-added))}]]]})))
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label (if has-picture?
|
||||
:t/profile-picture-updated
|
||||
:t/profile-picture-added))}]])]})))
|
||||
|
||||
(defn edit-profile-picture
|
||||
[{:keys [db]} [picture crop-width crop-height]]
|
||||
[{:keys [db]}
|
||||
[{:keys [picture crop-width crop-height show-toast?]
|
||||
:or {show-toast? true}}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
crop-width (or crop-width profile-picture-picker/crop-size)
|
||||
crop-height (or crop-height profile-picture-picker/crop-size)
|
||||
@@ -33,25 +34,28 @@
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "multiaccounts_storeIdentityImage"
|
||||
:params [key-uid path 0 0 crop-width crop-height]
|
||||
:on-success [:profile/edit-profile-picture-success]}]]]}))
|
||||
:on-success [:profile/edit-profile-picture-success {:show-toast? show-toast?}]}]]]}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-picture edit-profile-picture)
|
||||
|
||||
(rf/reg-event-fx :profile/delete-profile-picture-success
|
||||
(fn [_]
|
||||
(fn [_ [{:keys [show-toast?]}]]
|
||||
{:fx [[:dispatch [:profile/update-local-picture nil]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/profile-picture-removed)}]]]}))
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/profile-picture-removed)}]])]}))
|
||||
|
||||
(defn delete-profile-picture
|
||||
[{:keys [db]}]
|
||||
[{:keys [db]}
|
||||
[{:keys [show-toast?]
|
||||
:or {show-toast? true}}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "multiaccounts_deleteIdentityImage"
|
||||
:params [key-uid]
|
||||
:on-success [:profile/delete-profile-picture-success]}]]]}))
|
||||
:on-success [:profile/delete-profile-picture-success {:show-toast? show-toast?}]}]]]}))
|
||||
|
||||
(rf/reg-event-fx :profile/delete-picture delete-profile-picture)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
[{:method "multiaccounts_storeIdentityImage"
|
||||
:params [key-uid picture 0 0 profile-picture-picker/crop-size
|
||||
profile-picture-picker/crop-size]
|
||||
:on-success [:profile/edit-profile-picture-success]}]]]}]
|
||||
:on-success [:profile/edit-profile-picture-success {:show-toast? true}]}]]]}]
|
||||
(is (match? expected
|
||||
(sut/edit-profile-picture cofx [picture])))))
|
||||
(sut/edit-profile-picture cofx [{:picture picture}])))))
|
||||
|
||||
(deftest delete-picture-test
|
||||
(let [key-uid "key-uid"
|
||||
@@ -22,6 +22,6 @@
|
||||
expected {:fx [[:json-rpc/call
|
||||
[{:method "multiaccounts_deleteIdentityImage"
|
||||
:params [key-uid]
|
||||
:on-success [:profile/delete-profile-picture-success]}]]]}]
|
||||
:on-success [:profile/delete-profile-picture-success {:show-toast? true}]}]]]}]
|
||||
(is (match? expected
|
||||
(sut/delete-profile-picture cofx)))))
|
||||
(sut/delete-profile-picture cofx [{}])))))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
has-picture? (rf/sub [:profile/has-picture])
|
||||
on-change-profile-pic (fn [picture]
|
||||
(if picture
|
||||
(rf/dispatch [:profile/edit-picture picture])
|
||||
(rf/dispatch [:profile/edit-picture {:picture picture}])
|
||||
(rf/dispatch [:profile/delete-picture])))]
|
||||
[rn/view
|
||||
{:key :edit-profile
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
(ns status-im.contexts.profile.edit.introduce-yourself.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn sheet
|
||||
[{:keys [pending-event]}]
|
||||
(let [on-accept (fn []
|
||||
(rf/dispatch [:open-modal :screen/profile.edit-profile-modal
|
||||
{:pending-event pending-event}]))
|
||||
on-reject #(rf/dispatch pending-event)]
|
||||
[:<>
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/text
|
||||
{:style {:padding-bottom 4}
|
||||
:size :heading-2
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/just-introduce-yourself)]
|
||||
[quo/text
|
||||
{:style {:padding-top 4 :padding-bottom 12}
|
||||
:size :paragraph-1
|
||||
:weight :regular}
|
||||
(i18n/label :t/add-display-name-and-picture)]]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:buttons-style {:flex-shrink 1 :flex-basis 0}
|
||||
:button-one-label (i18n/label :t/edit-profile)
|
||||
:button-one-props {:type :primary
|
||||
:on-press on-accept}
|
||||
:button-two-label (i18n/label :t/skip)
|
||||
:button-two-props {:type :grey
|
||||
:on-press on-reject}}]]))
|
||||
@@ -0,0 +1,62 @@
|
||||
(ns status-im.contexts.profile.edit.modal.events
|
||||
(:require [status-im.contexts.profile.edit.introduce-yourself.view :as introduce-yourself]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/edit-profile
|
||||
(fn [_ [{:keys [display-name picture color on-success]}]]
|
||||
{:fx (cond-> []
|
||||
display-name
|
||||
(conj [:dispatch
|
||||
[:profile/edit-name
|
||||
{:display-name display-name
|
||||
:navigate-back? false
|
||||
:show-toast? false}]])
|
||||
color
|
||||
(conj [:dispatch
|
||||
[:profile/edit-accent-colour
|
||||
{:color color
|
||||
:navigate-back? false
|
||||
:show-toast? false}]])
|
||||
picture
|
||||
(conj [:dispatch
|
||||
[:profile/edit-picture
|
||||
{:picture picture
|
||||
:show-toast? false}]])
|
||||
|
||||
(nil? picture)
|
||||
(conj [:dispatch [:profile/delete-picture {:show-toast? false}]])
|
||||
|
||||
:always
|
||||
(conj [:dispatch [:navigate-back]]
|
||||
[:dispatch on-success]))}))
|
||||
|
||||
(defn- profile-update-asked-storage-key
|
||||
[key-uid]
|
||||
(keyword :update-profile-asked key-uid))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/set-profile-update-as-asked
|
||||
(fn [{db :db}]
|
||||
(let [storage-key (-> db :profile/profile :key-uid profile-update-asked-storage-key)]
|
||||
{:fx [[:effects.async-storage/set {storage-key true}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/ask-profile-update
|
||||
(fn [_ [pending-event]]
|
||||
{:fx [[:dispatch [:profile/set-profile-update-as-asked]]
|
||||
[:dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[introduce-yourself/sheet {:pending-event pending-event}])}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/check-profile-update-prompt
|
||||
(fn [{db :db} [pending-event]]
|
||||
(let [storage-key (-> db :profile/profile :key-uid profile-update-asked-storage-key)]
|
||||
{:fx [[:effects.async-storage/get
|
||||
{:keys [storage-key]
|
||||
:cb (fn [profile-updated-data]
|
||||
(rf/dispatch (if (storage-key profile-updated-data)
|
||||
pending-event
|
||||
[:profile/ask-profile-update pending-event])))}]]})))
|
||||
@@ -0,0 +1,55 @@
|
||||
(ns status-im.contexts.profile.edit.modal.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def continue-button
|
||||
{:width "100%"
|
||||
:margin-left :auto
|
||||
:margin-top (if platform/android? :auto 0)
|
||||
:margin-right :auto})
|
||||
|
||||
(def button-container
|
||||
{:width "100%"
|
||||
:padding-left 20
|
||||
:padding-right 20
|
||||
:padding-top 12
|
||||
:align-self :flex-end
|
||||
:height 64})
|
||||
|
||||
(defn view-button-container
|
||||
[keyboard-shown?]
|
||||
(merge button-container
|
||||
(if platform/ios?
|
||||
{:margin-bottom (if keyboard-shown? 0 34)}
|
||||
{:margin-bottom (if keyboard-shown? 12 34)})))
|
||||
|
||||
(def blur-button-container
|
||||
(merge button-container
|
||||
(when platform/android? {:padding-bottom 12})))
|
||||
|
||||
(def page-container
|
||||
{:flex 1})
|
||||
|
||||
(def info-message
|
||||
{:margin-top 8})
|
||||
|
||||
(def title
|
||||
{:color colors/white
|
||||
:margin-top 12
|
||||
:margin-bottom 18})
|
||||
|
||||
(def color-title
|
||||
{:color colors/white-70-blur
|
||||
:margin-top 20
|
||||
:margin-bottom 16})
|
||||
|
||||
(def content-container
|
||||
{:padding-horizontal 20})
|
||||
|
||||
(def input-container
|
||||
{:align-items :flex-start})
|
||||
|
||||
(def profile-input-container
|
||||
{:flex-direction :row
|
||||
:justify-content :center})
|
||||
@@ -0,0 +1,266 @@
|
||||
(ns status-im.contexts.profile.edit.modal.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.avatar-picture-picker.view :as profile-picture-picker]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.validation.profile :as profile-validator]
|
||||
[status-im.constants :as c]
|
||||
[status-im.contexts.profile.edit.modal.events]
|
||||
[status-im.contexts.profile.edit.modal.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.responsiveness :as responsiveness]))
|
||||
|
||||
(def scroll-view-height (reagent/atom 0))
|
||||
(def content-container-height (reagent/atom 0))
|
||||
(def set-scroll-view-height #(reset! scroll-view-height %))
|
||||
|
||||
(defn set-content-container-height
|
||||
[e]
|
||||
(reset! content-container-height (oops/oget e "nativeEvent.layout.height")))
|
||||
|
||||
(defn show-button-background?
|
||||
[keyboard-height keyboard-shown content-scroll-y]
|
||||
(let [button-container-height 64
|
||||
keyboard-view-height (+ keyboard-height button-container-height)]
|
||||
(when keyboard-shown
|
||||
(cond
|
||||
platform/android?
|
||||
(< (- @scroll-view-height button-container-height) @content-container-height)
|
||||
|
||||
platform/ios?
|
||||
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
|
||||
|
||||
:else
|
||||
false))))
|
||||
|
||||
(defn button-container
|
||||
[show-keyboard? keyboard-shown show-background? keyboard-height children]
|
||||
(let [height (reagent/atom 0)]
|
||||
(reset! height (if show-keyboard? (if keyboard-shown keyboard-height 0) 0))
|
||||
[rn/view {:style {:margin-top :auto}}
|
||||
(cond
|
||||
(and (> @height 0) show-background?)
|
||||
[quo/blur
|
||||
(when keyboard-shown
|
||||
{:blur-amount 34
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
:background-color (if platform/android?
|
||||
colors/neutral-100
|
||||
colors/neutral-80-opa-1-blur)
|
||||
:style style/blur-button-container})
|
||||
children]
|
||||
|
||||
(and (> @height 0) (not show-background?))
|
||||
[rn/view {:style (style/view-button-container true)}
|
||||
children]
|
||||
|
||||
(not show-keyboard?)
|
||||
[rn/view {:style (style/view-button-container false)}
|
||||
children])]))
|
||||
|
||||
(defn- add-keyboard-listener
|
||||
[e callback]
|
||||
(oops/ocall rn/keyboard "addListener" e callback))
|
||||
|
||||
(defn- on-keyboard-show
|
||||
[f]
|
||||
(add-keyboard-listener (if platform/android? "keyboardDidShow" "keyboardWillShow") f))
|
||||
|
||||
(defn- on-keyboard-hide
|
||||
[f]
|
||||
(add-keyboard-listener (if platform/android? "keyboardDidHide" "keyboardWillHide") f))
|
||||
|
||||
(defn floating-button
|
||||
[{:keys [custom-color scroll-y on-submit disabled?]}]
|
||||
(reagent/with-let [show-keyboard? (reagent/atom false)
|
||||
show-listener (on-keyboard-show #(reset! show-keyboard? true))
|
||||
hide-listener (on-keyboard-hide #(reset! show-keyboard? false))]
|
||||
(let [{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
show-background? (show-button-background? keyboard-height
|
||||
keyboard-shown
|
||||
scroll-y)]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style {:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0}
|
||||
:pointer-events :box-none}
|
||||
[button-container @show-keyboard? keyboard-shown show-background? keyboard-height
|
||||
[quo/button
|
||||
{:accessibility-label :submit-create-profile-button
|
||||
:type :primary
|
||||
:customization-color custom-color
|
||||
:on-press on-submit
|
||||
:container-style style/continue-button
|
||||
:disabled? disabled?}
|
||||
(i18n/label :t/continue)]]])
|
||||
(finally
|
||||
(oops/ocall show-listener "remove")
|
||||
(oops/ocall hide-listener "remove"))))
|
||||
|
||||
(defn- content
|
||||
[{:keys [set-display-name set-validation-msg picture-picker]}]
|
||||
(let [open-picture-picker (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content picture-picker
|
||||
:shell? true
|
||||
:theme :dark}]))
|
||||
on-change-text (fn [s]
|
||||
(set-validation-msg s)
|
||||
(set-display-name s))]
|
||||
(fn [{:keys [profile-image custom-color display-name validation-msg valid-name?
|
||||
name-too-short? initial-display-name set-scroll set-scroll-height
|
||||
set-custom-color]}]
|
||||
(let [{window-width :width} (rn/get-window)
|
||||
info-type (cond
|
||||
validation-msg :error
|
||||
name-too-short? :default
|
||||
:else :success)
|
||||
info-message (or validation-msg
|
||||
(i18n/label :t/minimum-characters
|
||||
{:min-chars profile-validator/min-length}))
|
||||
full-name (if (seq display-name)
|
||||
display-name
|
||||
initial-display-name)]
|
||||
[rn/scroll-view
|
||||
{:on-layout set-scroll-height
|
||||
:on-scroll set-scroll
|
||||
:scroll-event-throttle 64
|
||||
:content-container-style {:flex-grow 1}}
|
||||
[rn/view {:on-layout set-content-container-height}
|
||||
[rn/view {:style style/content-container}
|
||||
[quo/text
|
||||
{:style style/title
|
||||
:size :heading-1
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/edit-profile)]
|
||||
[rn/view {:style style/input-container}
|
||||
[rn/view {:style style/profile-input-container}
|
||||
[quo/profile-input
|
||||
{:customization-color custom-color
|
||||
:placeholder initial-display-name
|
||||
:on-press open-picture-picker
|
||||
:image-picker-props {:profile-picture profile-image
|
||||
:full-name full-name
|
||||
:customization-color custom-color}
|
||||
:title-input-props {:default-value ""
|
||||
:auto-focus true
|
||||
:max-length c/profile-name-max-length
|
||||
:on-change-text on-change-text}}]]
|
||||
[quo/info-message
|
||||
{:status info-type
|
||||
:size :default
|
||||
:icon (if valid-name? :i/positive-state :i/info)
|
||||
:color (when (= :default info-type) colors/white-70-blur)
|
||||
:container-style style/info-message}
|
||||
info-message]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/color-title}
|
||||
(i18n/label :t/colour)]]]
|
||||
[quo/color-picker
|
||||
{:blur? true
|
||||
:default-selected custom-color
|
||||
:on-change set-custom-color
|
||||
:window-width window-width
|
||||
:container-style {:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
|
||||
window-width)}}]]]))))
|
||||
|
||||
(defn- submittable-state?
|
||||
[{:keys [new-color? new-picture? new-name? valid-name?]}]
|
||||
(let [acceptable-name? (or (not new-name?) valid-name?)]
|
||||
(or (and new-color? acceptable-name?)
|
||||
(and new-picture? acceptable-name?)
|
||||
(and new-name? valid-name?))))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [pending-event]} (rf/sub [:get-screen-params])
|
||||
{initial-display-name :display-name
|
||||
initial-color :customization-color
|
||||
[initial-image] :images} (rf/sub [:profile/profile])
|
||||
top (safe-area/get-top)
|
||||
scroll-y (reagent/atom 0)
|
||||
display-name (reagent/atom "")
|
||||
validation-msg (reagent/atom (profile-validator/validation-name @display-name))
|
||||
custom-color (reagent/atom (or initial-color c/profile-default-color))
|
||||
profile-image (reagent/atom initial-image)
|
||||
set-display-name #(reset! validation-msg (profile-validator/validation-name %))
|
||||
set-validation-msg #(reset! display-name (string/trim %))
|
||||
set-custom-color #(reset! custom-color %)
|
||||
set-scroll (fn [e]
|
||||
(reset! scroll-y (oops/oget e "nativeEvent.contentOffset.y")))
|
||||
set-scroll-height (fn [e]
|
||||
(reset! scroll-y 0)
|
||||
(-> e
|
||||
(oops/oget "nativeEvent.layout.height")
|
||||
set-scroll-view-height))
|
||||
picture-picker (fn []
|
||||
[profile-picture-picker/view
|
||||
{:on-result #(reset! profile-image %)
|
||||
:has-picture? (some? @profile-image)}])
|
||||
update-profile (fn []
|
||||
(rf/dispatch
|
||||
[:profile/edit-profile
|
||||
(cond-> {:on-success pending-event}
|
||||
(and (seq @display-name)
|
||||
(not= initial-display-name @display-name))
|
||||
(assoc :display-name @display-name)
|
||||
|
||||
(and (not= initial-image @profile-image))
|
||||
(assoc :picture @profile-image)
|
||||
|
||||
(not= initial-color @custom-color)
|
||||
(assoc :color @custom-color))]))
|
||||
on-close (fn []
|
||||
(events-helper/navigate-back)
|
||||
(rf/dispatch pending-event))]
|
||||
(fn []
|
||||
(let [name-too-short? (profile-validator/name-too-short? @display-name)
|
||||
valid-name? (and (not @validation-msg) (not name-too-short?))
|
||||
disabled? (not
|
||||
(submittable-state?
|
||||
{:new-color? (not= initial-color @custom-color)
|
||||
:new-picture? (not= @profile-image initial-image)
|
||||
:new-name? (and (not= initial-display-name @display-name)
|
||||
(seq @display-name))
|
||||
:valid-name? valid-name?}))]
|
||||
[quo/overlay {:type :shell}
|
||||
[rn/view {:style style/page-container}
|
||||
[quo/page-nav
|
||||
{:margin-top top
|
||||
:background :blur
|
||||
:icon-name :i/close
|
||||
:on-press on-close}]
|
||||
[content
|
||||
{:profile-image @profile-image
|
||||
:custom-color @custom-color
|
||||
:display-name @display-name
|
||||
:validation-msg @validation-msg
|
||||
:valid-name? valid-name?
|
||||
:name-too-short? name-too-short?
|
||||
:picture-picker picture-picker
|
||||
:initial-display-name initial-display-name
|
||||
:set-scroll set-scroll
|
||||
:set-scroll-height set-scroll-height
|
||||
:set-custom-color set-custom-color
|
||||
:set-display-name set-display-name
|
||||
:set-validation-msg set-validation-msg}]
|
||||
[floating-button
|
||||
{:custom-color @custom-color
|
||||
:scroll-y @scroll-y
|
||||
:on-submit update-profile
|
||||
:disabled? disabled?}]]]))))
|
||||
@@ -5,21 +5,26 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-profile-name-success
|
||||
(fn [_]
|
||||
{:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/name-updated)}]]]}))
|
||||
(fn [{:keys [db]} [display-name navigate-back? show-toast?]]
|
||||
{:db (assoc-in db [:profile/profile :display-name] display-name)
|
||||
:fx [(when navigate-back?
|
||||
[:dispatch [:navigate-back]])
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/name-updated)}]])]}))
|
||||
|
||||
(defn edit-profile-name
|
||||
[{:keys [db]} [name]]
|
||||
{:db (assoc-in db [:profile/profile :display-name] name)
|
||||
:fx [[:json-rpc/call
|
||||
[_
|
||||
[{:keys [display-name navigate-back? show-toast?]
|
||||
:or {navigate-back? true
|
||||
show-toast? true}}]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setDisplayName"
|
||||
:params [name]
|
||||
:on-success [:profile/edit-profile-name-success]}]]]})
|
||||
:params [display-name]
|
||||
:on-success [:profile/edit-profile-name-success display-name navigate-back? show-toast?]}]]]})
|
||||
|
||||
(rf/reg-event-fx :profile/edit-name edit-profile-name)
|
||||
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
(deftest edit-name-test
|
||||
(let [new-name "John Doe"
|
||||
cofx {:db {:profile/profile {:display-name "Old name"}}}
|
||||
expected {:db {:profile/profile {:display-name new-name}}
|
||||
:fx [[:json-rpc/call
|
||||
expected {:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setDisplayName"
|
||||
:params [name]
|
||||
:on-success [:profile/edit-profile-name-success]}]]]}]
|
||||
:on-success [:profile/edit-profile-name-success new-name true true]}]]]}]
|
||||
(is (match? expected
|
||||
(sut/edit-profile-name cofx [new-name])))))
|
||||
(sut/edit-profile-name cofx [{:display-name new-name}])))))
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
{:type :primary
|
||||
:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:profile/edit-name @full-name]))
|
||||
(rf/dispatch [:profile/edit-name {:display-name @full-name}])
|
||||
(rf/dispatch [:profile/set-profile-update-as-asked]))
|
||||
:disabled? (boolean (or @typing?
|
||||
(string/blank? @full-name)
|
||||
(not (string/blank? @error-msg))))}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
(ns status-im.contexts.profile.login.events
|
||||
(:require
|
||||
[legacy.status-im.data-store.settings :as data-store.settings]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[native-module.core :as native-module]
|
||||
[oops.core :as oops]
|
||||
[status-im.common.keychain.events :as keychain]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
@@ -10,7 +12,8 @@
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/reg-event-fx :profile.login/login
|
||||
(fn [{:keys [db]}]
|
||||
@@ -132,9 +135,12 @@
|
||||
:on-error #(log/error "node-info: failed error" %)}]]]})))
|
||||
|
||||
(rf/reg-event-fx :profile.login/messenger-started
|
||||
(fn [{:keys [db]} [_]]
|
||||
(let [new-account? (get db :onboarding/new-account?)]
|
||||
{:db (assoc db :messenger/started? true)
|
||||
(fn [{:keys [db]} [response-js]]
|
||||
(let [mailservers (transforms/js->clj (oops/oget response-js :mailservers))
|
||||
new-account? (get db :onboarding/new-account?)]
|
||||
{:db (-> db
|
||||
(assoc :messenger/started? true)
|
||||
(mailserver/add-mailservers mailservers))
|
||||
:fx [[:fetch-chats-preview
|
||||
{:chat-preview-type constants/chat-preview-type-non-community
|
||||
:on-success (fn [result]
|
||||
|
||||
@@ -129,10 +129,8 @@
|
||||
[:dispatch [:hide-bottom-sheet]]]})))
|
||||
|
||||
(rf/reg-event-fx :profile.settings/update-local-picture
|
||||
(fn [{:keys [db now]} [images]]
|
||||
{:db (assoc-in db
|
||||
[:profile/profile :images]
|
||||
(map #(assoc % :clock now) images))}))
|
||||
(fn [{:keys [db]} [images]]
|
||||
{:db (assoc-in db [:profile/profile :images] images)}))
|
||||
|
||||
(rf/reg-event-fx :profile.settings/mnemonic-was-shown
|
||||
(fn [_]
|
||||
|
||||
@@ -5,82 +5,42 @@
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.keycard.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn registered-keycard
|
||||
[{:keys [profile-name profile-image customization-color]}]
|
||||
[rn/view {:style style/keycard-row}
|
||||
[quo/icon :i/keycard-card
|
||||
{:size 20
|
||||
:color colors/white-70-blur}]
|
||||
[rn/view
|
||||
[quo/text profile-name]
|
||||
[rn/view {:style style/keycard-owner}
|
||||
[quo/user-avatar
|
||||
{:full-name profile-name
|
||||
:profile-picture profile-image
|
||||
:customization-color customization-color
|
||||
:status-indicator false
|
||||
:ring? false
|
||||
:size :xxxs}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/keycard-owner-name}
|
||||
profile-name]]]])
|
||||
|
||||
(defn registered-keycards
|
||||
[]
|
||||
(let [keycards (rf/sub [:keycard/registered-keycards])]
|
||||
[:<>
|
||||
[quo/divider-label
|
||||
{:counter? false
|
||||
:tight? true
|
||||
:blur? true}
|
||||
(i18n/label :t/registered-keycards)]
|
||||
[rn/view {:style style/registered-keycards-container}
|
||||
(for [keycard keycards]
|
||||
^{:key (:keycard-uid keycard)}
|
||||
[registered-keycard keycard])]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [keycard-profile? (rf/sub [:keycard/keycard-profile?])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard)}]
|
||||
(if keycard-profile?
|
||||
[registered-keycards]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/get-keycard)
|
||||
:subtitle (i18n/label :t/secure-wallet-card)
|
||||
:button-label (i18n/label :t/buy-keycard)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
|
||||
[rn/view {:style {:margin-top 24}}
|
||||
[quo/text
|
||||
{:style {:margin-bottom 1
|
||||
:color colors/white-opa-70}
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/own-keycard)]]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/setup-keycard)
|
||||
:subtitle (i18n/label :t/ready-keycard)
|
||||
:accessibility-label :setup-keycard
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:open-modal :screen/keycard.check
|
||||
{:on-press
|
||||
#(rf/dispatch
|
||||
[:keycard/migration.check-empty-card])}]))}]])]))
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard)}]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/get-keycard)
|
||||
:subtitle (i18n/label :t/secure-wallet-card)
|
||||
:button-label (i18n/label :t/buy-keycard)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
|
||||
[rn/view {:style {:margin-top 24}}
|
||||
[quo/text
|
||||
{:style {:margin-bottom 1
|
||||
:color colors/white-opa-70}
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/own-keycard)]]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/manage-keycard)
|
||||
:subtitle (i18n/label :t/setup-keycard-description)
|
||||
:accessibility-label :setup-keycard
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:open-modal :screen/keycard.check
|
||||
{:on-press
|
||||
#(rf/dispatch [:keycard/check-empty-card])}]))}]]])
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
[{:details (:optimism networks)
|
||||
:testnet-mode? testnet-mode?
|
||||
:testnet-label (i18n/label :t/sepolia-active)}
|
||||
{:details (:base networks)
|
||||
:testnet-mode? testnet-mode?
|
||||
:testnet-label (i18n/label :t/sepolia-active)}
|
||||
{:details (:arbitrum networks)
|
||||
:testnet-mode? testnet-mode?
|
||||
:testnet-label (i18n/label :t/sepolia-active)}])
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
:z-index (get shared-values
|
||||
(get shell.constants/stacks-z-index-keywords stack-id))})}
|
||||
(case stack-id
|
||||
:communities-stack [:f> communities/view]
|
||||
:chats-stack [:f> chat/view]
|
||||
:communities-stack [communities/view]
|
||||
:chats-stack [chat/view]
|
||||
:wallet-stack [wallet/view]
|
||||
:browser-stack [browser.stack/browser-stack]
|
||||
[:<>])])
|
||||
@@ -38,7 +38,7 @@
|
||||
(defn lazy-screen
|
||||
[stack-id shared-values]
|
||||
(when (load-stack? stack-id)
|
||||
[:f> f-stack-view stack-id shared-values]))
|
||||
[f-stack-view stack-id shared-values]))
|
||||
|
||||
(defn view
|
||||
[shared-values]
|
||||
|
||||
@@ -303,7 +303,7 @@
|
||||
;; By doing it, we skip a blink while visiting the collectible detail page.
|
||||
[:dispatch-later
|
||||
{:ms 17
|
||||
:dispatch [:navigate-to :screen/wallet.collectible]}]]})))
|
||||
:dispatch [:open-modal :screen/wallet.collectible]}]]})))
|
||||
|
||||
(defn- keep-not-empty-value
|
||||
[old-value new-value]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.wallet.collectible.utils
|
||||
(:require [status-im.config :as config]
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -79,3 +80,12 @@
|
||||
acc)))
|
||||
{})
|
||||
vals))
|
||||
|
||||
(defn sort-collectibles-by-name
|
||||
[collectibles]
|
||||
(sort-by (fn [collectible]
|
||||
(let [name (-> collectible :collectible-data :name)
|
||||
normalized-name (some-> name
|
||||
string/lower-case)]
|
||||
[(if (seq normalized-name) 0 1) normalized-name]))
|
||||
collectibles))
|
||||
|
||||
@@ -44,3 +44,18 @@
|
||||
:token-id token-id
|
||||
:test-networks-enabled? true})
|
||||
"https://testnets.opensea.io/assets/optimism-sepolia/0xC/0xT"))))
|
||||
|
||||
(deftest sort-collectibles-by-name-test
|
||||
(testing "Sorts collectibles by name, moving nil or empty names to the end"
|
||||
(let [collectibles [{:collectible-data {:name "Alpha"}}
|
||||
{:collectible-data {:name nil}}
|
||||
{:collectible-data {:name "Beta"}}
|
||||
{:collectible-data {:name ""}}
|
||||
{:collectible-data {:name "Zeta"}}]
|
||||
sorted-collectibles (utils/sort-collectibles-by-name collectibles)
|
||||
expected [{:collectible-data {:name "Alpha"}}
|
||||
{:collectible-data {:name "Beta"}}
|
||||
{:collectible-data {:name "Zeta"}}
|
||||
{:collectible-data {:name nil}}
|
||||
{:collectible-data {:name ""}}]]
|
||||
(is (= sorted-collectibles expected)))))
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
type :no-title}}]
|
||||
(let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
networks (rf/sub [:wallet/selected-network-details])
|
||||
sending-collectible? (rf/sub [:wallet/sending-collectible?])
|
||||
keycard? (rf/sub [:wallet/selected-keypair-keycard?])]
|
||||
sending-collectible? (rf/sub [:wallet/sending-collectible?])]
|
||||
[quo/page-nav
|
||||
{:type type
|
||||
:icon-name icon-name
|
||||
@@ -46,11 +45,7 @@
|
||||
(not watch-only?)
|
||||
show-dapps-button?)
|
||||
{:icon-name :i/dapps
|
||||
:on-press #(rf/dispatch
|
||||
(if keycard?
|
||||
[:keycard/feature-unavailable-show
|
||||
{:feature-name :wallet.show-connected-dapps}]
|
||||
[:navigate-to :screen/wallet.connected-dapps]))})
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})
|
||||
(when-not sending-collectible?
|
||||
{:content-type :account-switcher
|
||||
:customization-color color
|
||||
|
||||
@@ -10,15 +10,11 @@
|
||||
token-name :name
|
||||
total-balance :total-balance
|
||||
disabled? :bridge-disabled?
|
||||
fiat-value :fiat-value
|
||||
:as token}
|
||||
_ _
|
||||
{:keys [currency currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
|
||||
(let [fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
|
||||
{:keys [currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
|
||||
(let [crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
|
||||
[quo/token-network
|
||||
{:token token-symbol
|
||||
@@ -38,13 +34,11 @@
|
||||
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query search-text
|
||||
:chain-ids chain-ids}])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])]
|
||||
[gesture/flat-list
|
||||
{:data filtered-tokens
|
||||
:render-data {:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:render-data {:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:preselected-token-symbol preselected-token-symbol
|
||||
:prices-per-token prices-per-token}
|
||||
|
||||
@@ -409,13 +409,15 @@
|
||||
|
||||
(defn sort-tokens
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt (comp - :balance) priority) tokens)))
|
||||
(sort-by (comp - :balance) tokens))
|
||||
|
||||
(defn sort-tokens-by-fiat-value
|
||||
[tokens]
|
||||
(sort-by (comp - :fiat-value) tokens))
|
||||
|
||||
(defn sort-tokens-by-name
|
||||
[tokens]
|
||||
(let [priority #(get constants/token-sort-priority (:symbol %) ##Inf)]
|
||||
(sort-by (juxt :symbol priority) tokens)))
|
||||
(sort-by :symbol tokens))
|
||||
|
||||
(defn token-with-balance
|
||||
([token networks]
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
constants/optimism-mainnet-chain-id
|
||||
config/optimism-mainnet-tx-details-base-link
|
||||
|
||||
constants/base-mainnet-chain-id
|
||||
config/base-mainnet-tx-details-base-link
|
||||
|
||||
constants/ethereum-sepolia-chain-id
|
||||
config/mainnet-sepolia-tx-details-base-link
|
||||
|
||||
@@ -46,6 +49,9 @@
|
||||
constants/optimism-sepolia-chain-id
|
||||
config/optimism-sepolia-tx-details-base-link
|
||||
|
||||
constants/base-sepolia-chain-id
|
||||
config/base-sepolia-tx-details-base-link
|
||||
|
||||
config/mainnet-tx-details-base-link))
|
||||
|
||||
(defn get-link-to-tx-details
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
constants/optimism-mainnet-chain-id constants/optimism-network-name
|
||||
constants/optimism-sepolia-chain-id constants/optimism-network-name
|
||||
constants/arbitrum-mainnet-chain-id constants/arbitrum-network-name
|
||||
constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name})
|
||||
constants/arbitrum-sepolia-chain-id constants/arbitrum-network-name
|
||||
constants/base-mainnet-chain-id constants/base-network-name
|
||||
constants/base-sepolia-chain-id constants/base-network-name})
|
||||
|
||||
(defn- get-chain-id
|
||||
[{:keys [mainnet-chain-id sepolia-chain-id testnet-enabled?]}]
|
||||
@@ -46,6 +48,12 @@
|
||||
(get-chain-id
|
||||
{:mainnet-chain-id constants/arbitrum-mainnet-chain-id
|
||||
:sepolia-chain-id constants/arbitrum-sepolia-chain-id
|
||||
:testnet-enabled? testnet-enabled?})
|
||||
|
||||
#{constants/base-network-name (keyword constants/base-short-name)}
|
||||
(get-chain-id
|
||||
{:mainnet-chain-id constants/base-mainnet-chain-id
|
||||
:sepolia-chain-id constants/base-sepolia-chain-id
|
||||
:testnet-enabled? testnet-enabled?}))))
|
||||
|
||||
(defn network-list
|
||||
@@ -76,12 +84,14 @@
|
||||
{constants/mainnet-network-name constants/mainnet-short-name
|
||||
constants/optimism-network-name constants/optimism-short-name
|
||||
constants/arbitrum-network-name constants/arbitrum-short-name
|
||||
constants/ethereum-network-name constants/ethereum-short-name})
|
||||
constants/ethereum-network-name constants/ethereum-short-name
|
||||
constants/base-network-name constants/base-short-name})
|
||||
|
||||
(def short-name->network
|
||||
{constants/mainnet-short-name constants/mainnet-network-name
|
||||
constants/optimism-short-name constants/optimism-network-name
|
||||
constants/arbitrum-short-name constants/arbitrum-network-name})
|
||||
constants/arbitrum-short-name constants/arbitrum-network-name
|
||||
constants/base-short-name constants/base-network-name})
|
||||
|
||||
(defn short-names->network-preference-prefix
|
||||
[short-names]
|
||||
@@ -152,6 +162,15 @@
|
||||
:view-on-block-explorer-label :t/view-on-oeth
|
||||
:link-to-block-explorer-label :t/share-link-to-oeth})
|
||||
|
||||
(def base-network-details
|
||||
{:source (resources/get-network constants/base-network-name)
|
||||
:short-name constants/base-short-name
|
||||
:full-name constants/base-full-name
|
||||
:network-name constants/base-network-name
|
||||
:abbreviated-name constants/base-abbreviated-name
|
||||
:view-on-block-explorer-label :t/view-on-base
|
||||
:link-to-block-explorer-label :t/share-link-to-base})
|
||||
|
||||
(defn get-network-details
|
||||
[chain-id]
|
||||
(as-> chain-id $
|
||||
@@ -165,6 +184,9 @@
|
||||
#{constants/optimism-mainnet-chain-id constants/optimism-sepolia-chain-id}
|
||||
optimism-network-details
|
||||
|
||||
#{constants/base-mainnet-chain-id constants/base-sepolia-chain-id}
|
||||
base-network-details
|
||||
|
||||
nil)
|
||||
(when $
|
||||
(assoc $ :chain-id chain-id))))
|
||||
|
||||
@@ -345,3 +345,33 @@
|
||||
expected []]
|
||||
(is (= (utils/get-accounts-with-token-balance accounts token)
|
||||
expected)))))
|
||||
|
||||
(deftest sort-tokens-test
|
||||
(testing "Sort tokens by balance in descending order"
|
||||
(let [tokens [{:symbol "BTC" :balance 2}
|
||||
{:symbol "ETH" :balance 5}
|
||||
{:symbol "DAI" :balance 10}]
|
||||
expected [{:symbol "DAI" :balance 10}
|
||||
{:symbol "ETH" :balance 5}
|
||||
{:symbol "BTC" :balance 2}]]
|
||||
(is (= (utils/sort-tokens tokens) expected)))))
|
||||
|
||||
(deftest sort-tokens-by-fiat-value-test
|
||||
(testing "Sort tokens by fiat value in descending order"
|
||||
(let [tokens [{:symbol "BTC" :fiat-value 50000}
|
||||
{:symbol "ETH" :fiat-value 15000}
|
||||
{:symbol "DAI" :fiat-value 1000}]
|
||||
expected [{:symbol "BTC" :fiat-value 50000}
|
||||
{:symbol "ETH" :fiat-value 15000}
|
||||
{:symbol "DAI" :fiat-value 1000}]]
|
||||
(is (= (utils/sort-tokens-by-fiat-value tokens) expected)))))
|
||||
|
||||
(deftest sort-tokens-by-name-test
|
||||
(testing "Sort tokens by symbol in ascending order"
|
||||
(let [tokens [{:symbol "ETH"}
|
||||
{:symbol "DAI"}
|
||||
{:symbol "BTC"}]
|
||||
expected [{:symbol "BTC"}
|
||||
{:symbol "DAI"}
|
||||
{:symbol "ETH"}]]
|
||||
(is (= (utils/sort-tokens-by-name tokens) expected)))))
|
||||
|
||||
@@ -123,3 +123,10 @@
|
||||
(-> (sign-transaction-hashes hashes address password)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet/sign-message
|
||||
(fn [{:keys [message address password on-success on-error]}]
|
||||
(-> (wallet-rpc/sign-message message address (security/safe-unmask-data password))
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -41,18 +41,18 @@
|
||||
(rf/reg-event-fx :wallet/navigate-to-account
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
|
||||
:fx [[:dispatch [:navigate-to :screen/wallet.accounts address]]]}))
|
||||
:fx [[:dispatch [:navigate-to :screen/wallet.accounts]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/navigate-to-account-within-stack
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
|
||||
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack] address]]]}))
|
||||
:fx [[:dispatch [:navigate-to-within-stack [:screen/wallet.accounts :shell-stack]]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/navigate-to-new-account
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :current-viewing-account-address] address)
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:navigate-to :screen/wallet.accounts address]]
|
||||
[:dispatch [:navigate-to :screen/wallet.accounts]]
|
||||
[:dispatch [:wallet/show-account-created-toast address]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-account-tab
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
chain-id
|
||||
constants/transaction-pending-type-wallet-connect-transfer
|
||||
(transforms/js-stringify tx-args 0)
|
||||
signature))
|
||||
(utils.hex/normalize-hex signature)))
|
||||
|
||||
(defn sign-message
|
||||
[message address password]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user