Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7eaa8585b | ||
|
|
83f832d948 | ||
|
|
e5cd07a92b | ||
|
|
c5eda74b19 | ||
|
|
51ccf0acc8 | ||
|
|
b805cbcfe2 | ||
|
|
4aef76281c | ||
|
|
c62d7d501e | ||
|
|
65cdb0dfe7 | ||
|
|
ea18966f33 | ||
|
|
e1abe5c6e2 | ||
|
|
cac96b589f | ||
|
|
f8d4f56d2d | ||
|
|
0957fb6e0a | ||
|
|
5118a5095d | ||
|
|
01c5cf2498 | ||
|
|
fae4b34863 | ||
|
|
020d5cc1c1 |
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.9.12'
|
||||
library 'status-jenkins-lib@v1.9.13'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
|
||||
+5
@@ -253,6 +253,11 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.initializeApplication(request) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
private fun acceptTerms(callback: Callback) {
|
||||
Log.d(TAG, "acceptTerms")
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.acceptTerms() }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun logout() {
|
||||
|
||||
@@ -204,6 +204,14 @@ RCT_EXPORT_METHOD(initializeApplication:(NSString *)request
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(acceptTerms:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"acceptTerms() method called");
|
||||
#endif
|
||||
NSString *result = StatusgoAcceptTerms();
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) {
|
||||
#if DEBUG
|
||||
NSLog(@"OpenAccounts() method called");
|
||||
|
||||
@@ -761,6 +761,26 @@ void _Logout(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
}
|
||||
|
||||
void _AcceptTerms(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
|
||||
if (args.Length() != 0) {
|
||||
// Throw an Error that is passed back to JavaScript
|
||||
isolate->ThrowException(Exception::TypeError(
|
||||
String::NewFromUtf8Literal(isolate, "Wrong number of arguments for AcceptTerms")));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the argument types
|
||||
|
||||
// Call exported Go function, which returns a C string
|
||||
char *c = AcceptTerms();
|
||||
|
||||
Local<String> ret = String::NewFromUtf8(isolate, c).ToLocalChecked();
|
||||
args.GetReturnValue().Set(ret);
|
||||
delete c;
|
||||
}
|
||||
|
||||
void _HashMessage(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
@@ -1998,6 +2018,7 @@ void init(Local<Object> exports) {
|
||||
NODE_SET_METHOD(exports, "multiAccountStoreAccount", _MultiAccountStoreAccount);
|
||||
NODE_SET_METHOD(exports, "initKeystore", _InitKeystore);
|
||||
NODE_SET_METHOD(exports, "initializeApplication", _InitializeApplication);
|
||||
NODE_SET_METHOD(exports, "acceptTerms", _AcceptTerms);
|
||||
NODE_SET_METHOD(exports, "fleets", _Fleets);
|
||||
NODE_SET_METHOD(exports, "stopCPUProfiling", _StopCPUProfiling);
|
||||
NODE_SET_METHOD(exports, "encodeTransfer", _EncodeTransfer);
|
||||
|
||||
+10
-7
@@ -95,7 +95,8 @@
|
||||
;; otherwise sometimes you'll get weird errors when
|
||||
;; instrumenting functions.
|
||||
:static-fns false
|
||||
:infer-externs true}
|
||||
:infer-externs true
|
||||
:reader-features #{:mobile}}
|
||||
;; if you want to use a real device, set your local ip
|
||||
;; in the SHADOW_HOST env variable to make sure that
|
||||
;; it will use the right interface
|
||||
@@ -129,7 +130,8 @@
|
||||
:static-fns true
|
||||
:fn-invoke-direct true
|
||||
:optimizations :advanced
|
||||
:js-options {:js-provider :closure}}}}
|
||||
:js-options {:js-provider :closure}
|
||||
:reader-features #{:mobile}}}}
|
||||
;; the tests are ran with node, react-native dependencies are mocked
|
||||
;; by using node --require override.js, which uses the node-library
|
||||
;; produced by the target :mocks below and redefines node require
|
||||
@@ -169,12 +171,13 @@
|
||||
{;; needed because we override require and it
|
||||
;; messes with source-map which reports callstack
|
||||
;; exceeded exceptions instead of real issues
|
||||
:source-map false
|
||||
:source-map false
|
||||
;; needed because we use deref in tests
|
||||
:static-fns false
|
||||
:optimizations :simple
|
||||
:warnings {:fn-deprecated false}
|
||||
:infer-externs true}}
|
||||
:static-fns false
|
||||
:optimizations :simple
|
||||
:warnings {:fn-deprecated false}
|
||||
:infer-externs true
|
||||
:reader-features #{:mobile}}}
|
||||
|
||||
;; mock.js-dependencies is mocking the react-native libraries
|
||||
;; we build it as a node library so that it can be required by
|
||||
|
||||
@@ -79,6 +79,12 @@
|
||||
(types/clj->json request)
|
||||
#(callback (types/json->clj %))))
|
||||
|
||||
(defn accept-terms
|
||||
([]
|
||||
(native-utils/promisify-native-module-call accept-terms))
|
||||
([callback]
|
||||
(.acceptTerms ^js (account-manager) callback)))
|
||||
|
||||
(defn prepare-dir-and-update-config
|
||||
[key-uid config callback]
|
||||
(log/debug "[native-module] prepare-dir-and-update-config")
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
:seed :i/seed
|
||||
:key :i/password
|
||||
nil)
|
||||
:color :neutral
|
||||
:blur? true
|
||||
:border? true}]
|
||||
[rn/view
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.confirmation-drawer.style :as style]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -35,11 +36,12 @@
|
||||
close-button-text]}]
|
||||
(let [extra-action-selected? (reagent/atom false)]
|
||||
(fn []
|
||||
(let [{:keys [group-chat chat-id public-key color
|
||||
(let [{:keys [group-chat chat-id public-key color chat-type
|
||||
profile-picture name]} context
|
||||
id (or chat-id public-key)
|
||||
theme (quo.theme/use-theme)
|
||||
[primary-name _] (when-not group-chat
|
||||
[primary-name _] (when-not (or group-chat
|
||||
(= chat-type constants/public-chat-type))
|
||||
(rf/sub [:contacts/contact-two-names-by-identity id]))
|
||||
display-name (cond
|
||||
(= primary-name "Unknown")
|
||||
|
||||
@@ -232,12 +232,11 @@
|
||||
:sub-label nil
|
||||
:chevron? false})))
|
||||
|
||||
;; TODO(OmarBasem): Requires design input.
|
||||
(defn edit-name-image-entry
|
||||
[]
|
||||
[chat-id]
|
||||
(entry {:icon :i/edit
|
||||
:label (i18n/label :t/edit-name-and-image)
|
||||
:on-press #(js/alert "TODO: to be implemented, requires design input")
|
||||
:on-press #(rf/dispatch [:open-modal :screen/group-update chat-id])
|
||||
:danger? false
|
||||
:accessibility-label :edit-name-and-image
|
||||
:sub-label nil
|
||||
@@ -359,7 +358,7 @@
|
||||
(rf/dispatch [:chats-list/load-chat chat-id])
|
||||
(rf/dispatch [:pin-message/load-pin-messages chat-id])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:navigate-to :group-details chat-id]))
|
||||
(rf/dispatch [:navigate-to :screen/group-details chat-id]))
|
||||
:danger? false
|
||||
:accessibility-label :group-details
|
||||
:sub-label nil
|
||||
@@ -369,18 +368,17 @@
|
||||
[chat-id admin?]
|
||||
(entry {:icon :i/add-user
|
||||
:label (i18n/label (if admin? :t/manage-members :t/add-members))
|
||||
:on-press #(rf/dispatch [:open-modal :group-add-manage-members chat-id])
|
||||
:on-press #(rf/dispatch [:open-modal :screen/group-add-manage-members chat-id])
|
||||
:danger? false
|
||||
:accessibility-label :manage-members
|
||||
:sub-label nil
|
||||
:chevron? false}))
|
||||
|
||||
;; TODO(OmarBasem): to be implemented.
|
||||
(defn edit-group-entry
|
||||
[]
|
||||
[chat-id]
|
||||
(entry {:icon :i/edit
|
||||
:label (i18n/label :t/edit-name-and-image)
|
||||
:on-press #(js/alert "TODO: to be implemented")
|
||||
:on-press #(rf/dispatch [:open-modal :screen/group-update chat-id])
|
||||
:danger? false
|
||||
:accessibility-label :edit-group
|
||||
:sub-label nil
|
||||
@@ -398,10 +396,11 @@
|
||||
:chevron? false}))
|
||||
|
||||
(defn destructive-actions
|
||||
[{:keys [group-chat] :as item} inside-chat?]
|
||||
[{:keys [group-chat chat-type] :as item} inside-chat?]
|
||||
[(when (not group-chat)
|
||||
(close-chat-entry item inside-chat? (not group-chat)))
|
||||
(clear-history-entry item group-chat)
|
||||
(close-chat-entry item inside-chat? (not= chat-type constants/public-chat-type)))
|
||||
(when-not (= chat-type constants/public-chat-type)
|
||||
(clear-history-entry item group-chat))
|
||||
(when group-chat
|
||||
(leave-group-entry item nil))])
|
||||
|
||||
@@ -425,8 +424,7 @@
|
||||
(when inside-chat?
|
||||
(add-manage-members-entry chat-id admin?))
|
||||
(when (and admin? inside-chat?)
|
||||
(when config/show-not-implemented-features?
|
||||
(edit-group-entry)))
|
||||
(edit-group-entry chat-id))
|
||||
(when (and admin? inside-chat?)
|
||||
(when config/show-not-implemented-features?
|
||||
(group-privacy-entry)))]))
|
||||
@@ -438,6 +436,11 @@
|
||||
(notification-actions item inside-chat? true)
|
||||
(destructive-actions item inside-chat?)]])
|
||||
|
||||
(defn public-chat-actions
|
||||
[item inside-chat?]
|
||||
[quo/action-drawer
|
||||
[(destructive-actions item inside-chat?)]])
|
||||
|
||||
(defn private-group-chat-actions
|
||||
[item inside-chat?]
|
||||
[quo/action-drawer
|
||||
@@ -473,6 +476,8 @@
|
||||
[one-to-one-actions chat inside-chat?]
|
||||
constants/private-group-chat-type
|
||||
[private-group-chat-actions chat inside-chat?]
|
||||
constants/public-chat-type
|
||||
[public-chat-actions chat inside-chat?]
|
||||
constants/community-chat-type
|
||||
[communities-chat-actions/actions chat inside-chat? hide-show-members?]
|
||||
nil))
|
||||
@@ -480,13 +485,12 @@
|
||||
(chat-actions chat inside-chat? nil)))
|
||||
|
||||
(defn group-details-actions
|
||||
[{:keys [admins] :as group}]
|
||||
[{:keys [chat-id admins] :as group}]
|
||||
(let [current-pub-key (rf/sub [:multiaccount/public-key])
|
||||
admin? (get admins current-pub-key)]
|
||||
[quo/action-drawer
|
||||
[(when admin?
|
||||
[(when config/show-not-implemented-features?
|
||||
(edit-name-image-entry))])
|
||||
[(edit-name-image-entry chat-id)])
|
||||
[(when config/show-not-implemented-features?
|
||||
(notifications-entry admin?))]
|
||||
(destructive-actions group false)]]))
|
||||
|
||||
@@ -566,6 +566,7 @@
|
||||
(def ^:const bridge-name-erc-1155-transfer "ERC1155Transfer")
|
||||
(def ^:const bridge-name-hop "Hop")
|
||||
(def ^:const bridge-name-paraswap "Paraswap")
|
||||
(def ^:const bridge-name-celer "CBridge")
|
||||
|
||||
(def ^:const bridge-assets #{"ETH" "USDT" "USDC" "DAI"})
|
||||
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
|
||||
(defn centralized-metrics-interceptor
|
||||
[context]
|
||||
(when-let [event (tracking/tracked-event (interceptor/get-coeffect context :event))]
|
||||
(log/debug "tracking event" event)
|
||||
(when (push-event? (interceptor/get-coeffect context :db))
|
||||
(native-module/add-centralized-metric event)))
|
||||
(when (push-event? (interceptor/get-coeffect context :db))
|
||||
(when-let [event (tracking/metrics-event (interceptor/get-coeffect context :event))]
|
||||
(log/debug "tracking event" event)
|
||||
(if (or (seq? event) (vector? event))
|
||||
(doseq [e event]
|
||||
(native-module/add-centralized-metric e))
|
||||
(native-module/add-centralized-metric event))))
|
||||
context)
|
||||
|
||||
(def interceptor
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
(deftest centralized-metrics-interceptor-test
|
||||
(testing "processes context correctly"
|
||||
(with-redefs [tracking/tracked-event (fn [_] {:metric "mocked-event"})
|
||||
(with-redefs [tracking/metrics-event (fn [_] {:metric "mocked-event"})
|
||||
events/push-event? (fn [_] true)]
|
||||
(let [context {:coeffects {:event [:some-event]
|
||||
:db {:centralized-metrics/enabled? true}}}]
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
(ns status-im.contexts.centralized-metrics.tracking
|
||||
(:require
|
||||
[clojure.string]
|
||||
[legacy.status-im.utils.build :as build]
|
||||
[react-native.platform :as platform]))
|
||||
[react-native.platform :as platform]
|
||||
[status-im.navigation.screens :as screens]))
|
||||
|
||||
(defn key-value-event
|
||||
[event-name event-value]
|
||||
@@ -19,47 +21,54 @@
|
||||
[view-id]
|
||||
(key-value-event "navigation" {:viewId view-id}))
|
||||
|
||||
(defn screen-event
|
||||
[screen event-data]
|
||||
(let [screen-id (:name screen)
|
||||
view-id (get-in screen [:metrics :alias-id] screen-id)]
|
||||
{:metric
|
||||
{:eventName "navigation"
|
||||
:platform platform/os
|
||||
:appVersion build/app-short-version
|
||||
:eventValue (assoc event-data :viewId (name view-id))}}))
|
||||
|
||||
(def ^:const app-started-event "app-started")
|
||||
|
||||
(def ^:const view-ids-to-track
|
||||
#{;; Tabs
|
||||
:communities-stack
|
||||
:chats-stack
|
||||
:wallet-stack
|
||||
|
||||
;; Onboarding
|
||||
:screen/onboarding.intro
|
||||
:screen/onboarding.new-to-status
|
||||
:screen/onboarding.sync-or-recover-profile
|
||||
:screen/onboarding.enter-seed-phrase
|
||||
:screen/onboarding.create-profile
|
||||
:screen/onboarding.create-profile-password
|
||||
:screen/onboarding.enable-biometrics
|
||||
:screen/onboarding.generating-keys
|
||||
:screen/onboarding.enable-notifications
|
||||
:screen/onboarding.preparing-status
|
||||
:screen/onboarding.sign-in-intro
|
||||
:screen/onboarding.sign-in
|
||||
:screen/onboarding.syncing-progress
|
||||
:screen/onboarding.syncing-progress-intro
|
||||
:screen/onboarding.syncing-results
|
||||
:screen/onboarding.welcome})
|
||||
:wallet-stack})
|
||||
|
||||
(defn track-view-id-event
|
||||
[view-id]
|
||||
(when (contains? view-ids-to-track view-id)
|
||||
(navigation-event (name view-id))))
|
||||
(if-let [screen (get screens/screens-by-name view-id)]
|
||||
(when (get-in screen [:metrics :track?])
|
||||
(screen-event screen {}))
|
||||
(when (contains? view-ids-to-track view-id)
|
||||
(navigation-event (name view-id)))))
|
||||
|
||||
(defn tracked-event
|
||||
[[event-name second-parameter]]
|
||||
(case event-name
|
||||
(defn navigated-to-collectibles-tab-event
|
||||
[location]
|
||||
(key-value-event "navigated-to-collectibles-tab" {:location location}))
|
||||
|
||||
(defn metrics-event
|
||||
[[rf-event-name rf-event-parameter]]
|
||||
(case rf-event-name
|
||||
:profile/get-profiles-overview-success
|
||||
(user-journey-event app-started-event)
|
||||
|
||||
:centralized-metrics/toggle-centralized-metrics
|
||||
(key-value-event "events.metrics-enabled" {:enabled second-parameter})
|
||||
(key-value-event "events.metrics-enabled" {:enabled rf-event-parameter})
|
||||
|
||||
:set-view-id
|
||||
(track-view-id-event second-parameter)
|
||||
(track-view-id-event rf-event-parameter)
|
||||
|
||||
:wallet/select-account-tab
|
||||
(when (= rf-event-parameter :collectibles)
|
||||
(navigated-to-collectibles-tab-event :account))
|
||||
|
||||
:wallet/select-home-tab
|
||||
(when (= rf-event-parameter :collectibles)
|
||||
(navigated-to-collectibles-tab-event :home))
|
||||
|
||||
nil))
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
{:eventName "navigation"
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {:viewId "onboarding.create-profile"}}}
|
||||
:eventValue {:viewId "onboarding.create-profile-info"}}}
|
||||
(tracking/track-view-id-event :screen/onboarding.create-profile)))
|
||||
(is (nil? (tracking/track-view-id-event :unknown-stack)))))
|
||||
|
||||
@@ -63,17 +63,23 @@
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {:action tracking/app-started-event}}}
|
||||
(tracking/tracked-event [:profile/get-profiles-overview-success])))
|
||||
(tracking/metrics-event [:profile/get-profiles-overview-success])))
|
||||
(is (= {:metric
|
||||
{:eventName "events.metrics-enabled"
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {:enabled true}}}
|
||||
(tracking/tracked-event [:centralized-metrics/toggle-centralized-metrics true])))
|
||||
(tracking/metrics-event [:centralized-metrics/toggle-centralized-metrics true])))
|
||||
(is (= {:metric
|
||||
{:eventName "navigation"
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {:viewId "wallet-stack"}}}
|
||||
(tracking/tracked-event [:set-view-id :wallet-stack])))
|
||||
(is (nil? (tracking/tracked-event [:unknown-event])))))
|
||||
(tracking/metrics-event [:set-view-id :wallet-stack])))
|
||||
(is (nil? (tracking/metrics-event [:unknown-event])))
|
||||
(is (= {:metric
|
||||
{:eventName "navigation"
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {:viewId "onboarding.intro"}}}
|
||||
(tracking/metrics-event [:set-view-id :screen/onboarding.intro])))))
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.contacts.events :as contacts-store]
|
||||
status-im.contexts.chat.effects
|
||||
status-im.contexts.chat.group-create.events
|
||||
status-im.contexts.chat.group.events
|
||||
[status-im.contexts.chat.messenger.composer.link-preview.events :as link-preview]
|
||||
status-im.contexts.chat.messenger.messages.content.reactions.events
|
||||
[status-im.contexts.chat.messenger.messages.delete-message-for-me.events :as delete-for-me]
|
||||
@@ -33,8 +33,8 @@
|
||||
(multi-user-chat? (get-chat cofx chat-id))))
|
||||
|
||||
(defn public-chat?
|
||||
([chat]
|
||||
(:public? chat))
|
||||
([{:keys [chat-type]}]
|
||||
(= chat-type constants/public-chat-type))
|
||||
([cofx chat-id]
|
||||
(public-chat? (get-chat cofx chat-id))))
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
(defn group-chat?
|
||||
([chat]
|
||||
(and (multi-user-chat? chat)
|
||||
(not (public-chat? chat))))
|
||||
(not (:public? chat))))
|
||||
([cofx chat-id]
|
||||
(group-chat? (get-chat cofx chat-id))))
|
||||
|
||||
|
||||
+32
-35
@@ -1,13 +1,11 @@
|
||||
(ns status-im.contexts.chat.group-create.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
(ns status-im.contexts.chat.group.common.group-edit
|
||||
(:require [quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.avatar-picture-picker.view :as avatar-picture-picker]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.group-create.style :as style]
|
||||
[status-im.contexts.chat.group.common.style :as style]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[utils.debounce :as debounce]
|
||||
utils.emojilib
|
||||
@@ -41,35 +39,28 @@
|
||||
:i/camera]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[{:keys [default-group-name default-group-color default-group-image contacts
|
||||
submit-button-label submit-event back-button-icon chat-id close on-success editing-group?]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{window-width :width} (rn/get-window)
|
||||
profile (rf/sub [:profile/profile-with-image])
|
||||
contacts (rf/sub [:selected-group-contacts])
|
||||
contacts-count (count contacts)
|
||||
default-value (rn/use-memo
|
||||
(fn []
|
||||
(let [contact-string (string/join ", "
|
||||
(map
|
||||
profile.utils/displayed-name
|
||||
contacts))]
|
||||
(subs contact-string
|
||||
0
|
||||
(min (count contact-string)
|
||||
constants/max-group-chat-name-length))))
|
||||
[])
|
||||
[group-name set-group-name] (rn/use-state default-value)
|
||||
[group-name set-group-name] (rn/use-state default-group-name)
|
||||
[error-message
|
||||
set-error-message] (rn/use-state nil)
|
||||
group-name-empty? (not (and (string? group-name) (not-empty group-name)))
|
||||
[group-color set-group-color] (rn/use-state (rand-nth colors/account-colors))
|
||||
[group-image set-group-image] (rn/use-state nil)
|
||||
create-group-on-press (rn/use-callback #(debounce/throttle-and-dispatch
|
||||
[:group-chat/create group-name group-color
|
||||
group-image]
|
||||
[group-color set-group-color] (rn/use-state default-group-color)
|
||||
[group-image set-group-image] (rn/use-state default-group-image)
|
||||
on-submit (rn/use-callback #(debounce/throttle-and-dispatch
|
||||
[submit-event
|
||||
{:group-name group-name
|
||||
:group-color group-color
|
||||
:group-image (when (not= group-image
|
||||
default-group-image)
|
||||
group-image)
|
||||
:chat-id chat-id
|
||||
:on-success on-success}]
|
||||
300)
|
||||
[group-name group-color group-image])
|
||||
back-on-press (rn/use-callback #(rf/dispatch [:navigate-back]))
|
||||
on-change-text (rn/use-callback
|
||||
(fn [text]
|
||||
(if (boolean (re-find utils.emojilib/emoji-regex text))
|
||||
@@ -77,7 +68,13 @@
|
||||
{:check (i18n/label
|
||||
:t/emojis)}))
|
||||
(set-error-message nil))
|
||||
(set-group-name text)))]
|
||||
(set-group-name text)))
|
||||
disabled? (or group-name-empty?
|
||||
error-message
|
||||
(and editing-group?
|
||||
(= group-name default-group-name)
|
||||
(= group-color default-group-color)
|
||||
(= group-image default-group-image)))]
|
||||
[floating-button-page/view
|
||||
{:customization-color group-color
|
||||
:gradient-cover? true
|
||||
@@ -85,13 +82,13 @@
|
||||
:header [quo/page-nav
|
||||
{:background :photo
|
||||
:type :no-title
|
||||
:icon-name :i/arrow-left
|
||||
:on-press back-on-press}]
|
||||
:icon-name back-button-icon
|
||||
:on-press close}]
|
||||
:footer [quo/button
|
||||
{:customization-color group-color
|
||||
:disabled? (boolean (or group-name-empty? error-message))
|
||||
:on-press create-group-on-press}
|
||||
(i18n/label :t/create-group-chat)]}
|
||||
:disabled? disabled?
|
||||
:on-press on-submit}
|
||||
submit-button-label]}
|
||||
[:<>
|
||||
[avatar
|
||||
{:customization-color group-color
|
||||
@@ -99,7 +96,7 @@
|
||||
:set-group-image set-group-image}]
|
||||
[quo/title-input
|
||||
{:on-change-text on-change-text
|
||||
:default-value default-value
|
||||
:default-value default-group-name
|
||||
:container-style {:padding-horizontal 20 :padding-top 12 :padding-bottom (if error-message 0 16)}
|
||||
:placeholder (i18n/label :t/name-your-group)
|
||||
:max-length constants/max-group-chat-name-length}]
|
||||
@@ -126,9 +123,9 @@
|
||||
:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
|
||||
window-width)}}]]
|
||||
[quo/divider-label
|
||||
(i18n/label :t/n-m-people {:n (inc contacts-count) :m constants/max-group-chat-participants})]
|
||||
(i18n/label :t/n-m-people {:n contacts-count :m constants/max-group-chat-participants})]
|
||||
[rn/view {:style style/tags}
|
||||
(for [contact (conj contacts profile)]
|
||||
(for [contact contacts]
|
||||
^{:key contact}
|
||||
[quo/context-tag
|
||||
{:container-style style/tag
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.contexts.chat.group-create.style
|
||||
(ns status-im.contexts.chat.group.common.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def avatar {:width 88 :margin-top 12 :margin-left 20})
|
||||
@@ -0,0 +1,27 @@
|
||||
(ns status-im.contexts.chat.group.create.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.foundations.colors :as colors]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.group.common.group-edit :as group-edit]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[{:keys [close]}]
|
||||
(let [contacts (rf/sub [:selected-group-contacts])
|
||||
contact-string (string/join ", " (map profile.utils/displayed-name contacts))
|
||||
default-group-name (subs contact-string
|
||||
0
|
||||
(min (count contact-string) constants/max-group-chat-name-length))
|
||||
profile (rf/sub [:profile/profile-with-image])
|
||||
contacts (conj contacts profile)]
|
||||
[group-edit/view
|
||||
{:default-group-name default-group-name
|
||||
:default-group-color (rand-nth colors/account-colors)
|
||||
:contacts contacts
|
||||
:submit-button-label (i18n/label :t/create-group-chat)
|
||||
:submit-event :group-chat/create
|
||||
:back-button-icon :i/arrow-left
|
||||
:close close}]))
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.contexts.chat.group-details.style
|
||||
(ns status-im.contexts.chat.group.details.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
+7
-6
@@ -1,4 +1,4 @@
|
||||
(ns status-im.contexts.chat.group-details.view
|
||||
(ns status-im.contexts.chat.group.details.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
@@ -11,7 +11,7 @@
|
||||
[status-im.common.contact-list.view :as contact-list]
|
||||
[status-im.common.home.actions.view :as actions]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.group-details.style :as style]
|
||||
[status-im.contexts.chat.group.details.style :as style]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -54,7 +54,7 @@
|
||||
(let [theme (quo.theme/use-theme)
|
||||
selected-participants (rf/sub [:group-chat/selected-participants])
|
||||
deselected-members (rf/sub [:group-chat/deselected-members])
|
||||
chat-id (rf/sub [:get-screen-params :group-add-manage-members])
|
||||
chat-id (rf/sub [:get-screen-params :screen/group-add-manage-members])
|
||||
{:keys [admins] :as group} (rf/sub [:chats/chat-by-id chat-id])
|
||||
current-pk (rf/sub [:multiaccount/public-key])
|
||||
admin? (get admins current-pk)]
|
||||
@@ -123,9 +123,9 @@
|
||||
[_]
|
||||
[rn/view {:style {:height 8}}])
|
||||
|
||||
(defn group-details
|
||||
(defn view
|
||||
[]
|
||||
(let [chat-id (rf/sub [:get-screen-params :group-details])
|
||||
(let [chat-id (rf/sub [:get-screen-params :screen/group-details])
|
||||
{:keys [admins chat-id chat-name color muted contacts image]
|
||||
:as group} (rf/sub [:chats/chat-by-id chat-id])
|
||||
members (rf/sub [:contacts/group-members-sections chat-id])
|
||||
@@ -176,7 +176,8 @@
|
||||
:icon :i/add-user
|
||||
:label (i18n/label (if admin? :t/manage-members :t/add-members))
|
||||
:counter-value (count contacts)
|
||||
:on-press #(rf/dispatch [:open-modal :group-add-manage-members
|
||||
:on-press #(rf/dispatch [:open-modal
|
||||
:screen/group-add-manage-members
|
||||
chat-id])}]}]
|
||||
[rn/section-list
|
||||
{:key-fn :title
|
||||
+16
-18
@@ -1,12 +1,12 @@
|
||||
(ns status-im.contexts.chat.group-create.events
|
||||
(ns status-im.contexts.chat.group.events
|
||||
(:require [clojure.string :as string]
|
||||
[legacy.status-im.data-store.chats :as data-store.chats]
|
||||
[oops.core :as oops]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.common.avatar-picture-picker.view :as avatar-picture-picker]))
|
||||
[status-im.common.avatar-picture-picker.view :as avatar-picture-picker]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(rf/reg-event-fx :group-chat/create
|
||||
(fn [{:keys [db]} [group-name color image]]
|
||||
(fn [{:keys [db]} [{:keys [group-name group-color group-image]}]]
|
||||
(let [selected-contacts (:group/selected-contacts db)]
|
||||
{:json-rpc/call [{:method "wakuext_createGroupChatWithMembers"
|
||||
:params [nil group-name (into [] selected-contacts)]
|
||||
@@ -17,25 +17,23 @@
|
||||
(oops/oget :id))]
|
||||
(rf/dispatch [:chat-updated response])
|
||||
(rf/dispatch [:group-chat/edit
|
||||
{:chat-id chat-id
|
||||
:group-name group-name
|
||||
:color color
|
||||
:image image}])))}]})))
|
||||
|
||||
(rf/reg-event-fx :group-chat/edit-success
|
||||
(fn [{:keys [db]} [{:keys [chat-id name color image]}]]
|
||||
(let [new-chat {:name name :color color :image image}]
|
||||
{:db (update-in db [:chats chat-id] #(merge % new-chat))})))
|
||||
{:chat-id chat-id
|
||||
:group-name group-name
|
||||
:group-color group-color
|
||||
:group-image group-image}])))}]})))
|
||||
|
||||
(rf/reg-event-fx :group-chat/edit
|
||||
(fn [_ [{:keys [chat-id group-name color image]}]]
|
||||
(fn [_ [{:keys [chat-id group-name group-color group-image on-success]}]]
|
||||
{:json-rpc/call [{:method "chat_editChat"
|
||||
:params ["" chat-id group-name (name color)
|
||||
{:imagePath (when image (string/replace-first image #"file://" ""))
|
||||
:params ["" chat-id group-name (name group-color)
|
||||
{:imagePath (when group-image
|
||||
(string/replace-first group-image #"file://" ""))
|
||||
:x 0
|
||||
:y 0
|
||||
:width avatar-picture-picker/crop-size
|
||||
:height avatar-picture-picker/crop-size}]
|
||||
:js-response true
|
||||
:on-success #(rf/dispatch [:group-chat/edit-success
|
||||
(data-store.chats/<-rpc-js %)])}]}))
|
||||
:on-error #(log/error "failed to edit group" {:error %})
|
||||
:on-success (fn [response]
|
||||
(rf/dispatch [:chat-updated response true])
|
||||
(when on-success (on-success)))}]}))
|
||||
@@ -0,0 +1,23 @@
|
||||
(ns status-im.contexts.chat.group.update.view
|
||||
(:require
|
||||
[status-im.contexts.chat.group.common.group-edit :as group-edit]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[{:keys [close]}]
|
||||
(let [chat-id (rf/sub [:get-screen-params :screen/group-update])
|
||||
{:keys [chat-name color image]} (rf/sub [:chats/chat-by-id chat-id])
|
||||
contacts (rf/sub [:contacts/contacts-by-chat chat-id])]
|
||||
[group-edit/view
|
||||
{:default-group-name chat-name
|
||||
:default-group-color color
|
||||
:default-group-image image
|
||||
:contacts contacts
|
||||
:submit-button-label (i18n/label :t/update-group-chat)
|
||||
:submit-event :group-chat/edit
|
||||
:back-button-icon :i/close
|
||||
:chat-id chat-id
|
||||
:close close
|
||||
:on-success close
|
||||
:editing-group? true}]))
|
||||
@@ -237,11 +237,17 @@
|
||||
|
||||
(defn chat-item
|
||||
[{:keys [chat-id group-chat color name last-message timestamp muted image
|
||||
unviewed-messages-count]
|
||||
chat-type unviewed-messages-count]
|
||||
:as item}]
|
||||
(let [[primary-name secondary-name]
|
||||
(if group-chat
|
||||
(cond
|
||||
group-chat
|
||||
[name ""]
|
||||
|
||||
(= chat-type constants/public-chat-type)
|
||||
[(str "#" name) ""]
|
||||
|
||||
:else
|
||||
(rf/sub [:contacts/contact-two-names-by-identity chat-id]))
|
||||
{:keys [ens-verified added?] :as contact} (when-not group-chat
|
||||
(rf/sub [:contacts/contact-by-address chat-id]))
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
:on-press (fn []
|
||||
(if one-contact-selected?
|
||||
(rf/dispatch [:chat.ui/start-chat public-key])
|
||||
(rf/dispatch [:open-modal :group-create])))}
|
||||
(rf/dispatch [:open-modal :screen/group-create])))}
|
||||
(if one-contact-selected?
|
||||
(i18n/label :t/chat-with {:selected-user primary-name})
|
||||
(i18n/label :t/setup-group-chat))]])]))
|
||||
|
||||
+5
-2
@@ -12,10 +12,13 @@
|
||||
(defn view
|
||||
[{:keys [contact-id]}]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])
|
||||
[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity contact-id])
|
||||
{:keys [contact-request-state
|
||||
community-id]} (rf/sub [:chats/current-chat-chat-view])
|
||||
community-id
|
||||
chat-name]} (rf/sub [:chats/current-chat-chat-view])
|
||||
chat-type (rf/sub [:chats/chat-type])
|
||||
[primary-name _] (if (= chat-type :public-chat)
|
||||
[(str "#" chat-name) ""]
|
||||
(rf/sub [:contacts/contact-two-names-by-identity contact-id]))
|
||||
community-chat? (= chat-type :community-chat)
|
||||
joined (when community-chat?
|
||||
(rf/sub [:communities/community-joined community-id]))
|
||||
|
||||
@@ -11,66 +11,93 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- show-terms-of-use
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet {:content terms/terms-of-use :shell? true}]))
|
||||
|
||||
(defn- show-privacy-policy
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet {:content privacy/privacy-statement :shell? true}]))
|
||||
|
||||
(defn- terms
|
||||
[terms-accepted? set-terms-accepted?]
|
||||
[rn/view {:style style/terms-privacy-container}
|
||||
[rn/view
|
||||
{:accessibility-label :terms-privacy-checkbox-container}
|
||||
[quo/selectors
|
||||
{:type :checkbox
|
||||
:blur? true
|
||||
:checked? terms-accepted?
|
||||
:on-change #(set-terms-accepted? not)}]]
|
||||
[rn/view {:style style/text-container}
|
||||
[quo/text
|
||||
{:style style/plain-text
|
||||
:size :paragraph-2}
|
||||
(str (i18n/label :t/accept-status-tos-prefix) " ")]
|
||||
[quo/text
|
||||
{:on-press show-terms-of-use
|
||||
:style style/highlighted-text
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/terms-of-service)]
|
||||
[quo/text
|
||||
{:style style/plain-text
|
||||
:size :paragraph-2}
|
||||
" " (i18n/label :t/and) " "]
|
||||
[quo/text
|
||||
{:on-press show-privacy-policy
|
||||
:style style/highlighted-text
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/intro-privacy-policy)]]])
|
||||
|
||||
(defn- explore-new-status
|
||||
[]
|
||||
(rf/dispatch [:profile/explore-new-status]))
|
||||
|
||||
(defn- sync-or-recover-profile
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:open-modal :screen/onboarding.sync-or-recover-profile]))
|
||||
|
||||
(defn- create-profile
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:open-modal :screen/onboarding.new-to-status]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [[terms-accepted? set-terms-accepted?] (rn/use-state false)]
|
||||
(let [[terms-accepted? set-terms-accepted?] (rn/use-state false)
|
||||
has-profiles-and-unaccepted-terms? (rf/sub [:profile/has-profiles-and-unaccepted-terms?])]
|
||||
[rn/view {:style style/page-container}
|
||||
[background/view false]
|
||||
[quo/bottom-actions
|
||||
{:container-style (style/bottom-actions-container (safe-area/get-bottom))
|
||||
:actions :two-vertical-actions
|
||||
:description :top
|
||||
:description-top-text [rn/view
|
||||
{:style style/terms-privacy-container}
|
||||
[rn/view
|
||||
{:accessibility-label :terms-privacy-checkbox-container}
|
||||
[quo/selectors
|
||||
{:type :checkbox
|
||||
:blur? true
|
||||
:checked? terms-accepted?
|
||||
:on-change #(set-terms-accepted? not)}]]
|
||||
[rn/view {:style style/text-container}
|
||||
[quo/text
|
||||
{:style style/plain-text
|
||||
:size :paragraph-2}
|
||||
(str (i18n/label :t/accept-status-tos-prefix) " ")]
|
||||
[quo/text
|
||||
{:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content terms/terms-of-use
|
||||
:shell? true}])
|
||||
:style style/highlighted-text
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/terms-of-service)]
|
||||
[quo/text
|
||||
{:style style/plain-text
|
||||
:size :paragraph-2}
|
||||
" " (i18n/label :t/and) " "]
|
||||
[quo/text
|
||||
{:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content privacy/privacy-statement
|
||||
:shell? true}])
|
||||
:style style/highlighted-text
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/intro-privacy-policy)]]]
|
||||
:button-one-label (i18n/label :t/sync-or-recover-profile)
|
||||
:button-one-props {:type :dark-grey
|
||||
:disabled? (not terms-accepted?)
|
||||
:accessibility-label :already-use-status-button
|
||||
:on-press (fn []
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch
|
||||
[:open-modal
|
||||
:screen/onboarding.sync-or-recover-profile]))}
|
||||
:button-two-label (i18n/label :t/create-profile)
|
||||
:button-two-props {:accessibility-label :new-to-status-button
|
||||
:disabled? (not terms-accepted?)
|
||||
:on-press
|
||||
(fn []
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch
|
||||
[:open-modal :screen/onboarding.new-to-status]))}}]
|
||||
(cond->
|
||||
{:container-style (style/bottom-actions-container (safe-area/get-bottom))
|
||||
:actions :two-vertical-actions
|
||||
:description :top
|
||||
:description-top-text [terms terms-accepted? set-terms-accepted?]}
|
||||
|
||||
has-profiles-and-unaccepted-terms?
|
||||
(assoc
|
||||
:actions :one-action
|
||||
:button-one-label (i18n/label :t/explore-the-new-status)
|
||||
:button-one-props {:disabled? (not terms-accepted?)
|
||||
:accessibility-label :explore-new-status
|
||||
:on-press explore-new-status})
|
||||
|
||||
(not has-profiles-and-unaccepted-terms?)
|
||||
(assoc
|
||||
:actions :two-vertical-actions
|
||||
:button-one-label (i18n/label :t/sync-or-recover-profile)
|
||||
:button-one-props {:type :dark-grey
|
||||
:disabled? (not terms-accepted?)
|
||||
:accessibility-label :already-use-status-button
|
||||
:on-press sync-or-recover-profile}
|
||||
:button-two-label (i18n/label :t/create-profile)
|
||||
:button-two-props {:accessibility-label :new-to-status-button
|
||||
:disabled? (not terms-accepted?)
|
||||
:on-press create-profile}))]
|
||||
[overlay/view]]))
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
(ns status-im.contexts.profile.data-store)
|
||||
|
||||
(defn accepted-terms?
|
||||
[accounts]
|
||||
(some :hasAcceptedTerms accounts))
|
||||
@@ -0,0 +1,14 @@
|
||||
(ns status-im.contexts.profile.effects
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-fx :effects.profile/accept-terms
|
||||
(fn [{:keys [on-success]}]
|
||||
(-> (native-module/accept-terms)
|
||||
(promesa/then (fn []
|
||||
(rf/call-continuation on-success)))
|
||||
(promesa/catch (fn [error]
|
||||
(log/error "Failed to accept terms" {:error error}))))))
|
||||
@@ -4,10 +4,12 @@
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[native-module.core :as native-module]
|
||||
[status-im.config :as config]
|
||||
[status-im.contexts.profile.data-store :as profile.data-store]
|
||||
[status-im.contexts.profile.edit.accent-colour.events]
|
||||
[status-im.contexts.profile.edit.bio.events]
|
||||
[status-im.contexts.profile.edit.header.events]
|
||||
[status-im.contexts.profile.edit.name.events]
|
||||
status-im.contexts.profile.effects
|
||||
status-im.contexts.profile.login.events
|
||||
[status-im.contexts.profile.rpc :as profile.rpc]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -42,26 +44,27 @@
|
||||
(rf/reg-event-fx
|
||||
:profile/get-profiles-overview-success
|
||||
(fn [{:keys [db]} [{:keys [accounts] {:keys [userConfirmed enabled]} :centralizedMetricsInfo}]]
|
||||
(let [db-with-settings (assoc db
|
||||
:centralized-metrics/user-confirmed? userConfirmed
|
||||
:centralized-metrics/enabled? enabled)]
|
||||
(if (seq accounts)
|
||||
(let [profiles (reduce-profiles accounts)
|
||||
{:keys [key-uid]} (first (sort-by :timestamp > (vals profiles)))]
|
||||
{:db (if key-uid
|
||||
(-> db-with-settings
|
||||
(assoc :profile/profiles-overview profiles)
|
||||
(update :profile/login #(select-profile % key-uid)))
|
||||
db-with-settings)
|
||||
:fx [[:dispatch [:update-theme-and-init-root :screen/profile.profiles]]
|
||||
(when (and key-uid userConfirmed)
|
||||
[:effects.biometric/check-if-available
|
||||
{:key-uid key-uid
|
||||
:on-success (fn [auth-method]
|
||||
(rf/dispatch [:profile.login/check-biometric-success key-uid
|
||||
auth-method]))}])]})
|
||||
{:db db-with-settings
|
||||
:fx [[:dispatch [:update-theme-and-init-root :screen/onboarding.intro]]]}))))
|
||||
(let [db-with-settings (assoc db
|
||||
:centralized-metrics/user-confirmed? userConfirmed
|
||||
:centralized-metrics/enabled? enabled)
|
||||
profiles (reduce-profiles accounts)
|
||||
{:keys [key-uid]} (first (sort-by :timestamp > (vals profiles)))
|
||||
new-db (cond-> db-with-settings
|
||||
(seq profiles)
|
||||
(assoc :profile/profiles-overview profiles)
|
||||
|
||||
key-uid
|
||||
(update :profile/login #(select-profile % key-uid)))]
|
||||
{:db new-db
|
||||
:fx (if (profile.data-store/accepted-terms? accounts)
|
||||
[[:dispatch [:update-theme-and-init-root :screen/profile.profiles]]
|
||||
(when (and key-uid userConfirmed)
|
||||
[:effects.biometric/check-if-available
|
||||
{:key-uid key-uid
|
||||
:on-success (fn [auth-method]
|
||||
(rf/dispatch [:profile.login/check-biometric-success key-uid
|
||||
auth-method]))}])]
|
||||
[[:dispatch [:update-theme-and-init-root :screen/onboarding.intro]]])})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/update-setting-from-backup
|
||||
@@ -82,3 +85,8 @@
|
||||
:messages-from-contacts-only
|
||||
(not (get-in db [:profile/profile :messages-from-contacts-only]))
|
||||
{})))
|
||||
|
||||
(rf/reg-event-fx :profile/explore-new-status
|
||||
(fn []
|
||||
{:fx [[:effects.profile/accept-terms
|
||||
{:on-success [:navigate-to :screen/profile.profiles]}]]}))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
(defn- bridge-token-component
|
||||
[]
|
||||
(fn [{:keys [chain-id network-name]} {:keys [networks] :as token}]
|
||||
(fn [{:keys [chain-id network-name]} {:keys [supported-networks] :as token}]
|
||||
(let [network (rf/sub [:wallet/network-details-by-chain-id chain-id])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
@@ -28,7 +28,8 @@
|
||||
fiat-formatted (utils/get-standard-fiat-format crypto-value
|
||||
currency-symbol
|
||||
fiat-value)
|
||||
token-available-on-network? (network-utils/token-available-on-network? networks chain-id)]
|
||||
token-available-on-network? (network-utils/token-available-on-network? supported-networks
|
||||
chain-id)]
|
||||
[quo/network-list
|
||||
{:label (name network-name)
|
||||
:network-image (quo.resources/get-network (:network-name network))
|
||||
@@ -49,7 +50,10 @@
|
||||
mainnet (first network-details)
|
||||
layer-2-networks (rest network-details)
|
||||
account-token (some #(when (= token-symbol (:symbol %)) %) tokens)
|
||||
account-token (when account-token (assoc account-token :networks (:networks token)))
|
||||
account-token (when account-token
|
||||
(assoc account-token
|
||||
:networks (:networks token)
|
||||
:supported-networks (:supported-networks token)))
|
||||
bridge-to-title (i18n/label :t/bridge-to
|
||||
{:name (string/upper-case (str token-symbol))})]
|
||||
|
||||
|
||||
@@ -10,17 +10,14 @@
|
||||
[]
|
||||
[rn/view {:style style/bridge-send-wrapper}
|
||||
[input-amount/view
|
||||
{:current-screen-id :screen/wallet.bridge-input-amount
|
||||
:button-one-label (i18n/label :t/review-bridge)
|
||||
:button-one-props {:icon-left :i/bridge}
|
||||
:enabled-from-chain-ids (rf/sub
|
||||
[:wallet/bridge-from-chain-ids])
|
||||
:from-enabled-networks (rf/sub [:wallet/bridge-from-networks])
|
||||
:on-confirm (fn [amount]
|
||||
(rf/dispatch [:wallet/set-token-amount-to-bridge
|
||||
{:amount amount
|
||||
:stack-id :screen/wallet.bridge-input-amount}]))
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:wallet/clean-send-amount]))}]])
|
||||
{:current-screen-id :screen/wallet.bridge-input-amount
|
||||
:button-one-label (i18n/label :t/review-bridge)
|
||||
:button-one-props {:icon-left :i/bridge}
|
||||
:on-confirm (fn [amount]
|
||||
(rf/dispatch [:wallet/set-token-amount-to-bridge
|
||||
{:amount amount
|
||||
:stack-id :screen/wallet.bridge-input-amount}]))
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:wallet/clean-send-amount]))}]])
|
||||
|
||||
@@ -43,10 +43,18 @@
|
||||
|
||||
(defn flush-collectibles
|
||||
[{:keys [db]}]
|
||||
(let [collectibles-per-account (get-in db [:wallet :ui :collectibles :fetched])]
|
||||
(let [collectibles-per-account (get-in db [:wallet :ui :collectibles :fetched])
|
||||
updated-accounts (move-collectibles-to-accounts (get-in db [:wallet :accounts])
|
||||
collectibles-per-account)
|
||||
has-collectibles? (some (fn [account]
|
||||
(pos? (count (:collectibles account))))
|
||||
(vals updated-accounts))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :collectibles] dissoc :pending-requests :fetched)
|
||||
(update-in [:wallet :accounts] move-collectibles-to-accounts collectibles-per-account))}))
|
||||
(assoc-in [:wallet :accounts] updated-accounts))
|
||||
:fx [[:dispatch
|
||||
[:centralized-metrics/track :metric/wallet-collectibles-fetched
|
||||
{:has-collectibles? has-collectibles?}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/flush-collectibles-fetched flush-collectibles)
|
||||
|
||||
|
||||
@@ -77,12 +77,13 @@
|
||||
(defn token-value-drawer
|
||||
[token watch-only? entry-point]
|
||||
(let [token-symbol (:token token)
|
||||
token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query token-symbol}]))
|
||||
token-data (rf/sub [:wallet/token-by-symbol token-symbol])
|
||||
selected-account (rf/sub [:wallet/current-viewing-account-address])
|
||||
token-owners (rf/sub [:wallet/operable-addresses-with-token-symbol token-symbol])
|
||||
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
|
||||
account-owns-token? (rf/sub [:wallet/current-account-owns-token token-symbol])
|
||||
receive-token-symbol (if (= token-symbol "SNT") "ETH" "SNT")
|
||||
token-owned? (if selected-account account-owns-token? (seq token-owners))
|
||||
asset-to-receive (rf/sub [:wallet/token-by-symbol receive-token-symbol])
|
||||
params (cond-> {:start-flow? true
|
||||
:owners token-owners
|
||||
@@ -103,11 +104,12 @@
|
||||
(action-hide))]
|
||||
(not watch-only?)
|
||||
(concat [(action-buy)
|
||||
(when (seq token-owners)
|
||||
(when token-owned?
|
||||
(action-send params entry-point))
|
||||
(action-receive selected-account)
|
||||
(action-swap params)
|
||||
(when (seq token-owners)
|
||||
(when token-owned?
|
||||
(action-swap params))
|
||||
(when token-owned?
|
||||
(action-bridge (assoc params
|
||||
:bridge-disabled?
|
||||
(send-utils/bridge-disabled? token-symbol))))]))]]))
|
||||
|
||||
@@ -27,12 +27,18 @@
|
||||
[balance]
|
||||
(cut-fiat-balance balance 2))
|
||||
|
||||
(defn prettify-balance
|
||||
[currency-symbol balance]
|
||||
(defn prepend-curency-symbol-to-fiat-balance
|
||||
[fiat-balance currency-symbol]
|
||||
(let [formatted-symbol (if (> (count currency-symbol) 1)
|
||||
(str currency-symbol " ")
|
||||
currency-symbol)]
|
||||
(str formatted-symbol (cut-fiat-balance-to-two-decimals balance))))
|
||||
(str formatted-symbol fiat-balance)))
|
||||
|
||||
(defn prettify-balance
|
||||
[currency-symbol fiat-balance]
|
||||
(-> fiat-balance
|
||||
cut-fiat-balance-to-two-decimals
|
||||
(prepend-curency-symbol-to-fiat-balance currency-symbol)))
|
||||
|
||||
(defn get-derivation-path
|
||||
[number-of-accounts]
|
||||
@@ -104,11 +110,15 @@
|
||||
:else (number/remove-trailing-zeroes
|
||||
(.toFixed token-units standardized-decimals-count)))))
|
||||
|
||||
(defn add-token-symbol-to-crypto-balance
|
||||
[crypto-balance token-symbol]
|
||||
(str crypto-balance " " (string/upper-case token-symbol)))
|
||||
|
||||
(defn prettify-crypto-balance
|
||||
[token-symbol crypto-balance conversion-rate]
|
||||
(str (cut-crypto-decimals-to-fit-usd-cents crypto-balance conversion-rate)
|
||||
" "
|
||||
(string/upper-case token-symbol)))
|
||||
(-> crypto-balance
|
||||
(cut-crypto-decimals-to-fit-usd-cents conversion-rate)
|
||||
(add-token-symbol-to-crypto-balance token-symbol)))
|
||||
|
||||
(defn get-standard-crypto-format
|
||||
"For full details: https://github.com/status-im/status-mobile/issues/18225"
|
||||
@@ -495,9 +505,7 @@
|
||||
:TokenIDTo token-id-to
|
||||
:SlippagePercentage slippage-percentage))
|
||||
|
||||
(not (or (= bridge-name constants/bridge-name-erc-721-transfer)
|
||||
(= bridge-name constants/bridge-name-transfer)
|
||||
(= bridge-name constants/bridge-name-hop)))
|
||||
(= bridge-name constants/bridge-name-celer)
|
||||
(assoc :CbridgeTx
|
||||
(assoc tx-data
|
||||
:ChainID to-chain-id
|
||||
@@ -524,9 +532,10 @@
|
||||
[tokens networks chain-ids]
|
||||
(map (fn [token]
|
||||
(assoc token
|
||||
:networks (network-utils/network-list token networks)
|
||||
:available-balance (calculate-total-token-balance token)
|
||||
:total-balance (calculate-total-token-balance token chain-ids)))
|
||||
:networks (network-utils/network-list-with-positive-balance token networks)
|
||||
:supported-networks (network-utils/network-list token networks)
|
||||
:available-balance (calculate-total-token-balance token)
|
||||
:total-balance (calculate-total-token-balance token chain-ids)))
|
||||
tokens))
|
||||
|
||||
(defn estimated-time-format
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
(ns status-im.contexts.wallet.common.utils.networks
|
||||
(:require [clojure.string :as string]
|
||||
[quo.foundations.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.number]))
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.foundations.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.money :as money]
|
||||
[utils.number]))
|
||||
|
||||
(def ^:private last-comma-followed-by-text-to-end-regex #",\s(?=[^,]+$)")
|
||||
|
||||
@@ -63,12 +65,21 @@
|
||||
|
||||
(defn network-list
|
||||
[{:keys [balances-per-chain]} networks]
|
||||
(into #{}
|
||||
(mapv (fn [chain-id]
|
||||
(first (filter #(or (= (:chain-id %) chain-id)
|
||||
(= (:related-chain-id %) chain-id))
|
||||
networks)))
|
||||
(keys balances-per-chain))))
|
||||
(->> balances-per-chain
|
||||
keys
|
||||
(map (fn [chain-id]
|
||||
(first (filter #(or (= (:chain-id %) chain-id)
|
||||
(= (:related-chain-id %) chain-id))
|
||||
networks))))
|
||||
set))
|
||||
|
||||
(defn network-list-with-positive-balance
|
||||
"Same as `network-list`, but only returns the networks that have a positive token balance"
|
||||
[{:keys [balances-per-chain] :as token} networks]
|
||||
(as-> balances-per-chain $
|
||||
(filter #(-> % second :raw-balance (money/greater-than 0)) $)
|
||||
(assoc token :balances-per-chain $)
|
||||
(network-list $ networks)))
|
||||
|
||||
(defn get-default-chain-ids-by-mode
|
||||
[{:keys [test-networks-enabled? is-goerli-enabled?]}]
|
||||
|
||||
@@ -72,11 +72,32 @@
|
||||
(update :testPreferredChainIds chain-ids-set->string)
|
||||
(dissoc :watch-only? :default-account? :operable? :tokens :collectibles)))
|
||||
|
||||
(defn add-missing-balance-per-chain-values
|
||||
"Adds any missing chain balance (0) to the balance-per-chain map based on token supported chains as
|
||||
status-go returns balance for that chain only if the balance is positive."
|
||||
[balances-per-chain supported-chains]
|
||||
(let [zero-balance-per-chain (fn [chain-id]
|
||||
{:chain-id chain-id
|
||||
:raw-balance (money/->bignumber 0)
|
||||
:balance "0"})]
|
||||
(reduce
|
||||
(fn [result chain-id]
|
||||
(if (contains? result chain-id)
|
||||
result
|
||||
(assoc result chain-id (zero-balance-per-chain chain-id))))
|
||||
balances-per-chain
|
||||
supported-chains)))
|
||||
|
||||
(defn- rpc->balances-per-chain
|
||||
[token]
|
||||
[token supported-chains]
|
||||
(-> token
|
||||
(update :balances-per-chain update-vals #(update % :raw-balance money/bignumber))
|
||||
(update :balances-per-chain update-keys (comp utils.number/parse-int name))))
|
||||
(update :balances-per-chain update-keys (comp utils.number/parse-int name))
|
||||
(update :balances-per-chain #(add-missing-balance-per-chain-values % supported-chains))))
|
||||
|
||||
(defn- update-balances-per-chain
|
||||
[tokens supported-chains-by-token-symbol]
|
||||
(mapv #(rpc->balances-per-chain % (get supported-chains-by-token-symbol (:symbol %))) tokens))
|
||||
|
||||
(defn- remove-tokens-with-empty-values
|
||||
[tokens]
|
||||
@@ -85,12 +106,12 @@
|
||||
tokens))
|
||||
|
||||
(defn rpc->tokens
|
||||
[tokens]
|
||||
[tokens supported-chains-by-token-symbol]
|
||||
(-> tokens
|
||||
(update-keys name)
|
||||
(update-vals #(cske/transform-keys transforms/->kebab-case-keyword %))
|
||||
(update-vals remove-tokens-with-empty-values)
|
||||
(update-vals #(mapv rpc->balances-per-chain %))))
|
||||
(update-vals #(update-balances-per-chain % supported-chains-by-token-symbol))))
|
||||
|
||||
(defn rpc->network
|
||||
[network]
|
||||
|
||||
@@ -10,4 +10,8 @@
|
||||
;; Note: we set it to nil by default to differentiate when the user logs
|
||||
;; in and the device is offline, versus re-fetching when offline and
|
||||
;; tokens already exist in the app-db.
|
||||
:tokens-loading nil}})
|
||||
:tokens-loading nil
|
||||
:active-tab :assets
|
||||
:screens {:input-amount-screen
|
||||
{:crypto-currency? true
|
||||
:input-value ""}}}})
|
||||
|
||||
@@ -59,6 +59,10 @@
|
||||
(fn [{:keys [db]} [tab]]
|
||||
{:db (assoc-in db [:wallet :ui :account-page :active-tab] tab)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-home-tab
|
||||
(fn [{:keys [db]} [tab]]
|
||||
{:db (assoc-in db [:wallet :ui :active-tab] tab)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clear-account-tab
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:wallet :ui :account-page :active-tab] nil)}))
|
||||
@@ -225,14 +229,17 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/store-wallet-token
|
||||
(fn [{:keys [db]} [address raw-tokens-data]]
|
||||
(let [tokens (data-store/rpc->tokens raw-tokens-data)
|
||||
add-tokens (fn [stored-accounts tokens-per-account]
|
||||
(reduce-kv (fn [accounts address tokens-data]
|
||||
(if (contains? accounts address)
|
||||
(update accounts address assoc :tokens tokens-data)
|
||||
accounts))
|
||||
stored-accounts
|
||||
tokens-per-account))]
|
||||
(let [supported-chains-by-token-symbol (get-in db [:wallet :tokens :supported-chains-by-symbol])
|
||||
tokens (data-store/rpc->tokens raw-tokens-data
|
||||
supported-chains-by-token-symbol)
|
||||
add-tokens (fn [stored-accounts tokens-per-account]
|
||||
(reduce-kv
|
||||
(fn [accounts address tokens-data]
|
||||
(if (contains? accounts address)
|
||||
(update accounts address assoc :tokens tokens-data)
|
||||
accounts))
|
||||
stored-accounts
|
||||
tokens-per-account))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :accounts] add-tokens tokens)
|
||||
(assoc-in [:wallet :ui :tokens-loading address] false))})))
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
(when (ff/enabled? ::ff/wallet.home-activity)
|
||||
{:id :activity :label (i18n/label :t/activity) :accessibility-label :activity-tab})])
|
||||
|
||||
(defn- change-tab [id] (rf/dispatch [:wallet/select-home-tab id]))
|
||||
|
||||
(defn- render-cards
|
||||
[cards ref]
|
||||
[rn/flat-list
|
||||
@@ -64,15 +66,15 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [[selected-tab set-selected-tab] (rn/use-state (:id (first tabs-data)))
|
||||
account-list-ref (rn/use-ref-atom nil)
|
||||
tokens-loading? (rf/sub [:wallet/home-tokens-loading?])
|
||||
networks (rf/sub [:wallet/selected-network-details])
|
||||
account-cards-data (rf/sub [:wallet/account-cards-data])
|
||||
cards (conj account-cards-data (new-account-card-data))
|
||||
[init-loaded? set-init-loaded] (rn/use-state false)
|
||||
{:keys [formatted-balance]} (rf/sub [:wallet/aggregated-token-values-and-balance])
|
||||
theme (quo.theme/use-theme)]
|
||||
(let [selected-tab (rf/sub [:wallet/home-tab])
|
||||
account-list-ref (rn/use-ref-atom nil)
|
||||
tokens-loading? (rf/sub [:wallet/home-tokens-loading?])
|
||||
networks (rf/sub [:wallet/selected-network-details])
|
||||
account-cards-data (rf/sub [:wallet/account-cards-data])
|
||||
cards (conj account-cards-data (new-account-card-data))
|
||||
[init-loaded? set-init-loaded] (rn/use-state false)
|
||||
{:keys [formatted-balance]} (rf/sub [:wallet/aggregated-token-values-and-balance])
|
||||
theme (quo.theme/use-theme)]
|
||||
(rn/use-effect (fn []
|
||||
(when (and @account-list-ref (pos? (count cards)))
|
||||
(.scrollToOffset ^js @account-list-ref
|
||||
@@ -104,7 +106,7 @@
|
||||
(when (ff/enabled? ::ff/wallet.graph)
|
||||
[quo/wallet-graph {:time-frame :empty}])
|
||||
[render-cards cards account-list-ref]
|
||||
[render-tabs tabs-data set-selected-tab selected-tab]]
|
||||
[render-tabs tabs-data change-tab selected-tab]]
|
||||
:content-container-style style/list-container
|
||||
:sticky-header-indices [0]
|
||||
:data []
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
routes-available? (pos? (count chosen-route))
|
||||
token-networks (:networks token)
|
||||
token-networks (:supported-networks token)
|
||||
token-networks-ids (when token-networks
|
||||
(map #(:chain-id %) token-networks))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain
|
||||
@@ -190,17 +190,21 @@
|
||||
;; `token` is a map extracted from the sender, but in the wallet home page we don't know the
|
||||
;; sender yet, so we only provide the `token-symbol`, later in
|
||||
;; `:wallet/select-from-account` the `token` key will be set.
|
||||
(let [{:keys [networks]} token
|
||||
receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
|
||||
token-networks-ids (map :chain-id networks)
|
||||
unsupported-token? (not-any? (set receiver-networks) token-networks-ids)
|
||||
unique-owner (when (= (count owners) 1)
|
||||
(first owners))
|
||||
unique-owner-tokens (get-in db [:wallet :accounts unique-owner :tokens])
|
||||
token-data (or token
|
||||
(when (and token-symbol unique-owner)
|
||||
(some #(when (= (:symbol %) token-symbol) %)
|
||||
unique-owner-tokens)))]
|
||||
(let [{:keys [networks]} token
|
||||
receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
|
||||
token-networks-ids (map :chain-id networks)
|
||||
unsupported-token? (not-any? (set receiver-networks) token-networks-ids)
|
||||
unique-owner (when (= (count owners) 1)
|
||||
(first owners))
|
||||
unique-owner-tokens (get-in db [:wallet :accounts unique-owner :tokens])
|
||||
token-data (or token
|
||||
(when (and token-symbol unique-owner)
|
||||
(some #(when (= (:symbol %) token-symbol) %)
|
||||
unique-owner-tokens)))
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
network-details (-> (get-in db
|
||||
[:wallet :networks (if test-networks-enabled? :test :prod)])
|
||||
(network-utils/sorted-networks-with-details))]
|
||||
(when (or token-data token-symbol)
|
||||
{:db (cond-> db
|
||||
:always (update-in [:wallet :ui :send]
|
||||
@@ -211,7 +215,11 @@
|
||||
token-symbol (assoc-in [:wallet :ui :send :token-symbol] token-symbol)
|
||||
token-data (update-in [:wallet :ui :send]
|
||||
#(assoc %
|
||||
:token token-data
|
||||
:token (assoc token-data
|
||||
:supported-networks
|
||||
(network-utils/network-list
|
||||
token-data
|
||||
network-details))
|
||||
:token-display-name (:symbol token-data)))
|
||||
unique-owner (assoc-in [:wallet :current-viewing-account-address] unique-owner)
|
||||
entry-point (assoc-in [:wallet :ui :send :entry-point] entry-point))
|
||||
@@ -230,7 +238,7 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/edit-token-to-send
|
||||
(fn [{:keys [db]} [token]]
|
||||
(let [{token-networks :networks
|
||||
(let [{token-networks :supported-networks
|
||||
token-symbol :symbol} token
|
||||
receiver-networks (get-in db [:wallet :ui :send :receiver-networks])
|
||||
token-networks-ids (map :chain-id token-networks)
|
||||
@@ -426,7 +434,7 @@
|
||||
{:balances-per-chain balances-per-chain
|
||||
:disabled-chain-ids disabled-from-chain-ids
|
||||
:only-with-balance? false}))
|
||||
token-networks-ids (when token (map #(:chain-id %) (:networks token)))
|
||||
token-networks-ids (when token (map #(:chain-id %) (:supported-networks token)))
|
||||
sender-network-values (when sender-token-available-networks-for-suggested-routes
|
||||
(send-utils/loading-network-amounts
|
||||
{:valid-networks
|
||||
@@ -708,7 +716,11 @@
|
||||
;; account, so we extract the token data from the picked account.
|
||||
(let [token (utils/get-token-from-account db token-symbol address)]
|
||||
(assoc token
|
||||
:networks (network-utils/network-list token network-details)
|
||||
:networks (network-utils/network-list-with-positive-balance
|
||||
token
|
||||
network-details)
|
||||
:supported-networks (network-utils/network-list token
|
||||
network-details)
|
||||
:total-balance (utils/calculate-total-token-balance token))))
|
||||
bridge-tx? (= tx-type :tx/bridge)
|
||||
flow-id (if bridge-tx?
|
||||
|
||||
@@ -79,11 +79,14 @@
|
||||
(h/deftest-event :wallet/edit-token-to-send
|
||||
[event-id dispatch]
|
||||
(let [token-symbol "ETH"
|
||||
token {:symbol "ETH"
|
||||
:name "Ether"
|
||||
:networks #{{:chain-id 421614}
|
||||
{:chain-id 11155420}
|
||||
{:chain-id 11155111}}}
|
||||
token {:symbol "ETH"
|
||||
:name "Ether"
|
||||
:networks #{{:chain-id 421614}
|
||||
{:chain-id 11155420}
|
||||
{:chain-id 11155111}}
|
||||
:supported-networks #{{:chain-id 421614}
|
||||
{:chain-id 11155420}
|
||||
{:chain-id 11155111}}}
|
||||
receiver-networks [421614 11155420]]
|
||||
(testing "can be called with :token"
|
||||
(let [initial-db {:wallet {:ui {:send {:receiver-networks receiver-networks
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
:wallet/wallet-send-tx-type :tx/send
|
||||
:wallet/wallet-send-fee-fiat-formatted "$5,00"
|
||||
:wallet/sending-collectible? false
|
||||
:wallet/total-amount (money/bignumber "250")})
|
||||
:wallet/total-amount-in-to-chains (money/bignumber "250")})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
(ns status-im.contexts.wallet.send.input-amount.controlled-input-logic
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[utils.money :as money]))
|
||||
|
||||
(def ^:private default-max-limit 12)
|
||||
|
||||
(def ^:private not-digits-or-dot-pattern
|
||||
#"[^0-9+\.]")
|
||||
|
||||
(def ^:private dot ".")
|
||||
|
||||
(defn- can-add-character?
|
||||
[input-value character max-length]
|
||||
(let [length-overflow? (>= (count input-value) max-length)
|
||||
extra-dot? (and (= character dot) (string/includes? input-value dot))
|
||||
extra-leading-zero? (and (= input-value "0") (= "0" (str character)))
|
||||
non-numeric? (re-find not-digits-or-dot-pattern (str character))]
|
||||
(not (or non-numeric? extra-dot? extra-leading-zero? length-overflow?))))
|
||||
|
||||
(defn- normalize-value-as-numeric
|
||||
[value character]
|
||||
(cond
|
||||
(and (string/blank? value) (= character dot))
|
||||
(str "0" character)
|
||||
|
||||
(and (= value "0") (not= character dot))
|
||||
(str character)
|
||||
|
||||
:else
|
||||
(str value character)))
|
||||
|
||||
(defn add-character
|
||||
([input-value character]
|
||||
(add-character input-value character default-max-limit))
|
||||
([input-value character max-length]
|
||||
(if (can-add-character? input-value character max-length)
|
||||
(normalize-value-as-numeric input-value character)
|
||||
input-value)))
|
||||
|
||||
(defn delete-last
|
||||
([input-value]
|
||||
(delete-last input-value ""))
|
||||
([input-value default-value]
|
||||
(let [new-value (subs input-value 0 (dec (count input-value)))]
|
||||
(if (string/blank? new-value)
|
||||
default-value
|
||||
new-value))))
|
||||
|
||||
(defn upper-limit-exceeded?
|
||||
[input-value upper-limit]
|
||||
(and upper-limit
|
||||
(when (money/bignumber? (money/bignumber input-value))
|
||||
(money/greater-than (money/bignumber input-value) (money/bignumber upper-limit)))))
|
||||
|
||||
(defn lower-limit-exceeded?
|
||||
[input-value lower-limit]
|
||||
(and lower-limit
|
||||
(when (money/bignumber? (money/bignumber input-value))
|
||||
(money/less-than (money/bignumber input-value) (money/bignumber lower-limit)))))
|
||||
|
||||
(defn value-out-of-limits?
|
||||
[input-value upper-limit lower-limit]
|
||||
(or (upper-limit-exceeded? input-value upper-limit)
|
||||
(lower-limit-exceeded? input-value lower-limit)))
|
||||
|
||||
(defn value-numeric
|
||||
[input-value]
|
||||
(or (parse-double input-value) 0))
|
||||
|
||||
(defn empty-value?
|
||||
[input-value]
|
||||
(or (string/blank? input-value) (<= (value-numeric input-value) 0)))
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
(ns status-im.contexts.wallet.send.input-amount.events
|
||||
(:require
|
||||
[status-im.contexts.wallet.send.input-amount.controlled-input-logic :as controlled-input-logic]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def input-value-path [:wallet :ui :screens :input-amount-screen :input-value])
|
||||
(def crypto-currency?-path [:wallet :ui :screens :input-amount-screen :crypto-currency?])
|
||||
|
||||
(rf/reg-event-fx :send-input-amount-screen/set-token-input-value
|
||||
(fn [{:keys [db]} [v]]
|
||||
{:db (assoc-in db input-value-path v)}))
|
||||
|
||||
(rf/reg-event-fx :send-input-amount-screen/swap-between-fiat-and-crypto
|
||||
(fn [{:keys [db]} [token-input-converted-value]]
|
||||
{:db (update-in db crypto-currency?-path not)
|
||||
:fx [[:dispatch
|
||||
[:send-input-amount-screen/set-token-input-value token-input-converted-value]]]}))
|
||||
|
||||
(rf/reg-event-fx :send-input-amount-screen/token-input-add-character
|
||||
(fn [{:keys [db]} [c max-decimals]]
|
||||
(let [input-value (get-in db input-value-path)
|
||||
new-text (str input-value c)
|
||||
regex-pattern (str "^\\d*\\.?\\d{0," max-decimals "}$")
|
||||
regex (re-pattern regex-pattern)]
|
||||
(when (re-matches regex new-text)
|
||||
{:db (update-in db input-value-path #(controlled-input-logic/add-character % c))}))))
|
||||
|
||||
(rf/reg-event-fx :send-input-amount-screen/token-input-delete-last
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db input-value-path controlled-input-logic/delete-last)}))
|
||||
|
||||
(rf/reg-event-fx :send-input-amount-screen/token-input-delete-all
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db input-value-path "")}))
|
||||
|
||||
|
||||
@@ -1,67 +1,56 @@
|
||||
(ns status-im.contexts.wallet.send.input-amount.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.controlled-input.utils :as controlled-input]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.common.asset-list.view :as asset-list]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.input-amount.events]
|
||||
[status-im.contexts.wallet.send.input-amount.style :as style]
|
||||
[status-im.contexts.wallet.send.routes.view :as routes]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[status-im.contexts.wallet.sheets.unpreferred-networks-alert.view :as unpreferred-networks-alert]
|
||||
[status-im.feature-flags :as ff]
|
||||
[status-im.setup.hot-reload :as hot-reload]
|
||||
[status-im.subs.wallet.screens.input-amount]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- estimated-fees
|
||||
[{:keys [loading-routes? fees amount]}]
|
||||
[rn/view {:style style/estimated-fees-container}
|
||||
(when (ff/enabled? ::ff/wallet.advanced-sending)
|
||||
[rn/view {:style style/estimated-fees-content-container}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :outline
|
||||
:size 32
|
||||
:inner-style {:opacity 1}
|
||||
:accessibility-label :advanced-button
|
||||
:disabled? loading-routes?
|
||||
:on-press #(js/alert "Not implemented yet")}
|
||||
:i/advanced]])
|
||||
[quo/data-item
|
||||
{:container-style style/fees-data-item
|
||||
:status (if loading-routes? :loading :default)
|
||||
:size :small
|
||||
:title (i18n/label :t/fees)
|
||||
:subtitle fees}]
|
||||
[quo/data-item
|
||||
{:container-style style/amount-data-item
|
||||
:status (if loading-routes? :loading :default)
|
||||
:size :small
|
||||
:title (i18n/label :t/recipient-gets)
|
||||
:subtitle amount}]])
|
||||
|
||||
(defn- every-network-value-is-zero?
|
||||
[sender-network-values]
|
||||
(every? (fn [{:keys [total-amount]}]
|
||||
(and
|
||||
total-amount
|
||||
(money/bignumber? total-amount)
|
||||
(money/equal-to total-amount
|
||||
(money/bignumber "0"))))
|
||||
sender-network-values))
|
||||
[]
|
||||
(let [loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
fees (rf/sub [:send-input-amount-screen/fee-formatted])
|
||||
amount (rf/sub [:send-input-amount-screen/recipient-gets-amount])]
|
||||
[rn/view {:style style/estimated-fees-container}
|
||||
(when (ff/enabled? ::ff/wallet.advanced-sending)
|
||||
[rn/view {:style style/estimated-fees-content-container}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :outline
|
||||
:size 32
|
||||
:inner-style {:opacity 1}
|
||||
:accessibility-label :advanced-button
|
||||
:disabled? loading-routes?
|
||||
:on-press #(js/alert "Not implemented yet")}
|
||||
:i/advanced]])
|
||||
[quo/data-item
|
||||
{:container-style style/fees-data-item
|
||||
:status (if loading-routes? :loading :default)
|
||||
:size :small
|
||||
:title (i18n/label :t/fees)
|
||||
:subtitle fees}]
|
||||
[quo/data-item
|
||||
{:container-style style/amount-data-item
|
||||
:status (if loading-routes? :loading :default)
|
||||
:size :small
|
||||
:title (i18n/label :t/recipient-gets)
|
||||
:subtitle amount}]]))
|
||||
|
||||
(defn select-asset-bottom-sheet
|
||||
[clear-input!]
|
||||
[]
|
||||
(let [{preselected-token-symbol :symbol} (rf/sub [:wallet/wallet-send-token])]
|
||||
[:<> ;; Need to be a `:<>` to keep `asset-list` scrollable.
|
||||
[quo/drawer-top
|
||||
@@ -73,15 +62,19 @@
|
||||
:preselected-token-symbol preselected-token-symbol
|
||||
:on-token-press (fn [token]
|
||||
(rf/dispatch [:wallet/edit-token-to-send token])
|
||||
(clear-input!))}]]))
|
||||
(rf/dispatch
|
||||
[:send-input-amount-screen/token-input-delete-all]))}]]))
|
||||
|
||||
(defn- token-not-available
|
||||
[token-symbol receiver-networks token-networks]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
add-token-networks (fn []
|
||||
(let [chain-ids (concat receiver-networks
|
||||
(mapv #(:chain-id %) token-networks))]
|
||||
(rf/dispatch [:wallet/update-receiver-networks chain-ids])))]
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{token-symbol :symbol
|
||||
token-networks :networks} (rf/sub [:wallet/wallet-send-token])
|
||||
receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||
add-token-networks (fn []
|
||||
(let [chain-ids (concat receiver-networks
|
||||
(mapv #(:chain-id %) token-networks))]
|
||||
(rf/dispatch [:wallet/update-receiver-networks chain-ids])))]
|
||||
[rn/view {:style (style/token-not-available-container theme)}
|
||||
[rn/view
|
||||
[quo/icon :i/alert
|
||||
@@ -140,163 +133,117 @@
|
||||
|
||||
:else (rf/dispatch [:wallet/stop-and-clean-suggested-routes])))
|
||||
|
||||
(defn- get-fee-formatted
|
||||
[route]
|
||||
(when-let [native-currency-symbol (-> route first :from :native-currency-symbol)]
|
||||
(rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])))
|
||||
(defn token-input
|
||||
[]
|
||||
(let [show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn [] [select-asset-bottom-sheet])}])
|
||||
{:keys [input-value crypto-currency?]} (rf/sub [:send-input-amount-screen/state])
|
||||
from-enabled-networks (rf/sub [:send-input-amount-screen/from-enabled-networks])
|
||||
{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-symbol :symbol} (rf/sub [:wallet/wallet-send-token])
|
||||
input-value-converted (rf/sub [:send-input-amount-screen/input-value-converted])
|
||||
converted-value-prettified (rf/sub
|
||||
[:send-input-amount-screen/converted-value-prettified])
|
||||
value-out-of-limits? (rf/sub [:send-input-amount-screen/value-out-of-limits?])
|
||||
upper-limit-prettified (rf/sub
|
||||
[:send-input-amount-screen/upper-limit-prettified])]
|
||||
[quo/token-input
|
||||
{:container-style style/input-container
|
||||
:token-symbol token-symbol
|
||||
:value input-value
|
||||
:on-swap #(rf/dispatch [:send-input-amount-screen/swap-between-fiat-and-crypto
|
||||
input-value-converted])
|
||||
:on-token-press show-select-asset-sheet
|
||||
:error? value-out-of-limits?
|
||||
:currency-symbol (if crypto-currency? token-symbol fiat-currency)
|
||||
:converted-value converted-value-prettified
|
||||
:hint-component [quo/network-tags
|
||||
{:networks (seq from-enabled-networks)
|
||||
:title (i18n/label
|
||||
:t/send-limit
|
||||
{:limit upper-limit-prettified})
|
||||
:status (when value-out-of-limits? :error)}]}]))
|
||||
(defn routes-view
|
||||
[current-screen-id]
|
||||
(let [token-by-symbol (rf/sub [:send-input-amount-screen/token-by-symbol])
|
||||
token (rf/sub [:wallet/wallet-send-token])
|
||||
routes (rf/sub [:send-input-amount-screen/routes])
|
||||
valid-input? (rf/sub [:send-input-amount-screen/valid-input?])
|
||||
amount-in-crypto (rf/sub [:send-input-amount-screen/amount-in-crypto])
|
||||
limit-exceeded? (rf/sub [:send-input-amount-screen/upper-limit-exceeded?])
|
||||
unsupported-token-in-receiver? (rf/sub
|
||||
[:send-input-amount-screen/unsupported-token-in-receiver?])
|
||||
request-fetch-routes (fn [bounce-duration-ms]
|
||||
(fetch-routes
|
||||
{:amount amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:bounce-duration-ms bounce-duration-ms
|
||||
:token token
|
||||
:reset-amounts-to-zero? (and limit-exceeded?
|
||||
(some? routes))}))]
|
||||
[routes/view
|
||||
{:token token-by-symbol
|
||||
:send-amount-in-crypto amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:token-not-supported-in-receiver-networks? unsupported-token-in-receiver?
|
||||
:current-screen-id current-screen-id
|
||||
:request-fetch-routes request-fetch-routes}]))
|
||||
|
||||
(defn bottom-actions
|
||||
[button-one-label button-one-props on-confirm]
|
||||
(let [token-by-symbol (rf/sub [:send-input-amount-screen/token-by-symbol])
|
||||
loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
amount-in-crypto (rf/sub [:send-input-amount-screen/amount-in-crypto])
|
||||
sending-to-unpreferred-networks? (rf/sub
|
||||
[:send-input-amount-screen/sending-to-unpreferred-networks?])
|
||||
current-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
not-enough-asset? (rf/sub [:send-input-amount-screen/not-enough-asset?])
|
||||
should-try-again? (rf/sub [:send-input-amount-screen/should-try-again?])
|
||||
confirm-disabled? (rf/sub [:send-input-amount-screen/confirm-disabled?])]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (if should-try-again?
|
||||
(i18n/label :t/try-again)
|
||||
button-one-label)
|
||||
:button-one-props (merge (when-not should-try-again?
|
||||
button-one-props)
|
||||
{:disabled? (or not-enough-asset?
|
||||
loading-routes?
|
||||
(and (not should-try-again?)
|
||||
confirm-disabled?))
|
||||
:on-press (cond
|
||||
should-try-again?
|
||||
#(rf/dispatch [:wallet/start-get-suggested-routes
|
||||
{:amount amount-in-crypto
|
||||
:updated-token token-by-symbol}])
|
||||
sending-to-unpreferred-networks?
|
||||
#(show-unpreferred-networks-alert on-confirm)
|
||||
:else
|
||||
#(on-confirm amount-in-crypto))
|
||||
:customization-color current-color}
|
||||
(when should-try-again?
|
||||
{:type :grey}))}]))
|
||||
|
||||
(defn- insufficient-asset-amount?
|
||||
[{:keys [token-symbol owned-eth-token input-state no-routes-found? limit-exceeded?
|
||||
sender-network-values enough-assets?]}]
|
||||
(let [eth-selected? (= token-symbol (string/upper-case constants/mainnet-short-name))
|
||||
zero-owned-eth? (money/equal-to (:total-balance owned-eth-token) 0)
|
||||
input-at-max-owned-amount? (money/equal-to
|
||||
(controlled-input/value-bn input-state)
|
||||
(controlled-input/upper-limit-bn input-state))
|
||||
exceeded-input? (if eth-selected?
|
||||
input-at-max-owned-amount?
|
||||
zero-owned-eth?)]
|
||||
(and (or no-routes-found? limit-exceeded?)
|
||||
(seq sender-network-values)
|
||||
(or exceeded-input? (not enough-assets?)))))
|
||||
|
||||
(defn view
|
||||
;; crypto-decimals, limit-crypto and initial-crypto-currency? args are needed
|
||||
;; for component tests only
|
||||
[{default-on-confirm :on-confirm
|
||||
default-limit-crypto :limit-crypto
|
||||
default-crypto-decimals :crypto-decimals
|
||||
on-navigate-back :on-navigate-back
|
||||
button-one-label :button-one-label
|
||||
button-one-props :button-one-props
|
||||
current-screen-id :current-screen-id
|
||||
initial-crypto-currency? :initial-crypto-currency?
|
||||
enabled-from-chain-ids :enabled-from-chain-ids
|
||||
from-enabled-networks :from-enabled-networks
|
||||
:or {initial-crypto-currency? true}}]
|
||||
(let [view-id (rf/sub [:view-id])
|
||||
active-screen? (= view-id current-screen-id)
|
||||
bottom (safe-area/get-bottom)
|
||||
[crypto-currency?
|
||||
set-crypto-currency] (rn/use-state initial-crypto-currency?)
|
||||
handle-on-confirm (fn [amount]
|
||||
(rf/dispatch [:wallet/set-token-amount-to-send
|
||||
{:amount amount
|
||||
:stack-id current-screen-id}]))
|
||||
{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-symbol :symbol
|
||||
token-networks :networks
|
||||
:as token} (rf/sub [:wallet/wallet-send-token])
|
||||
send-from-locked-amounts (rf/sub [:wallet/wallet-send-from-locked-amounts])
|
||||
{:keys [total-balance]
|
||||
:as token-by-symbol} (rf/sub [:wallet/token-by-symbol
|
||||
(str token-symbol)
|
||||
enabled-from-chain-ids])
|
||||
token-balance (or default-limit-crypto total-balance)
|
||||
usd-conversion-rate (utils/token-usd-price token)
|
||||
currency (rf/sub [:profile/currency])
|
||||
conversion-rate (-> token
|
||||
:market-values-per-currency
|
||||
currency
|
||||
:price)
|
||||
token-decimals (-> token
|
||||
utils/token-usd-price
|
||||
utils/one-cent-value
|
||||
utils/calc-max-crypto-decimals)
|
||||
[input-state set-input-state] (rn/use-state controlled-input/init-state)
|
||||
clear-input! #(set-input-state controlled-input/delete-all)
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or token-decimals default-crypto-decimals)
|
||||
max-limit (if crypto-currency?
|
||||
(utils/cut-crypto-decimals-to-fit-usd-cents
|
||||
token-balance
|
||||
usd-conversion-rate)
|
||||
(utils/cut-fiat-balance-to-two-decimals
|
||||
(money/crypto->fiat token-balance conversion-rate)))
|
||||
input-value (controlled-input/input-value input-state)
|
||||
valid-input? (not (or (controlled-input/empty-value? input-state)
|
||||
(controlled-input/input-error input-state)))
|
||||
amount-in-crypto (if crypto-currency?
|
||||
input-value
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed (/ input-value conversion-rate)
|
||||
crypto-decimals)))
|
||||
total-amount-receiver (rf/sub [:wallet/total-amount true])
|
||||
amount-text (str (number/remove-trailing-zeroes
|
||||
(.toFixed total-amount-receiver
|
||||
(min token-decimals 6)))
|
||||
" "
|
||||
token-symbol)
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])
|
||||
sender-network-values (rf/sub [:wallet/wallet-send-sender-network-values])
|
||||
receiver-network-values (rf/sub [:wallet/wallet-send-receiver-network-values])
|
||||
tx-type (rf/sub [:wallet/wallet-send-tx-type])
|
||||
unsupported-token-in-receiver? (and (not= tx-type :tx/bridge)
|
||||
(->> receiver-network-values
|
||||
(remove #(= (:type %) :add))
|
||||
(every? #(= (:type %) :not-available))))
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
no-routes-found? (and
|
||||
(every-network-value-is-zero? sender-network-values)
|
||||
(some? routes)
|
||||
(not loading-routes?)
|
||||
(not unsupported-token-in-receiver?))
|
||||
receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||
receiver-preferred-networks (rf/sub [:wallet/wallet-send-receiver-preferred-networks])
|
||||
receiver-preferred-network? (set receiver-preferred-networks)
|
||||
sending-to-unpreferred-networks? (some (comp not receiver-preferred-network?)
|
||||
receiver-networks)
|
||||
input-error (controlled-input/input-error input-state)
|
||||
limit-exceeded? (controlled-input/upper-limit-exceeded? input-state)
|
||||
current-address (rf/sub [:wallet/current-viewing-account-address])
|
||||
current-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
enough-assets? (rf/sub [:wallet/wallet-send-enough-assets?])
|
||||
owned-eth-token (rf/sub [:wallet/token-by-symbol
|
||||
(string/upper-case constants/mainnet-short-name)
|
||||
enabled-from-chain-ids])
|
||||
not-enough-asset? (insufficient-asset-amount?
|
||||
{:enough-assets? enough-assets?
|
||||
:token-symbol token-symbol
|
||||
:owned-eth-token owned-eth-token
|
||||
:input-state input-state
|
||||
:no-routes-found? no-routes-found?
|
||||
:limit-exceeded? limit-exceeded?
|
||||
:sender-network-values sender-network-values})
|
||||
should-try-again? (and (not limit-exceeded?)
|
||||
no-routes-found?
|
||||
(not not-enough-asset?))
|
||||
show-no-routes? (and (or no-routes-found? limit-exceeded?)
|
||||
(not-empty sender-network-values)
|
||||
(not not-enough-asset?))
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(not valid-input?))
|
||||
fee-formatted (when (or (not confirm-disabled?) not-enough-asset?)
|
||||
(get-fee-formatted route))
|
||||
request-fetch-routes (fn [bounce-duration-ms]
|
||||
(fetch-routes
|
||||
{:amount amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:bounce-duration-ms bounce-duration-ms
|
||||
:token token
|
||||
:reset-amounts-to-zero? (and limit-exceeded?
|
||||
(some? routes))}))
|
||||
swap-between-fiat-and-crypto (fn []
|
||||
(if crypto-currency?
|
||||
(set-input-state
|
||||
#(controlled-input/->fiat % conversion-rate))
|
||||
(set-input-state
|
||||
#(controlled-input/->crypto % conversion-rate)))
|
||||
(set-crypto-currency (not crypto-currency?)))]
|
||||
[{on-confirm :on-confirm
|
||||
on-navigate-back :on-navigate-back
|
||||
button-one-label :button-one-label
|
||||
button-one-props :button-one-props
|
||||
current-screen-id :current-screen-id}]
|
||||
(let [view-id (rf/sub [:view-id])
|
||||
active-screen? (= view-id current-screen-id)
|
||||
bottom (safe-area/get-bottom)
|
||||
max-decimals (rf/sub [:send-input-amount-screen/max-decimals])
|
||||
value-out-of-limits? (rf/sub [:send-input-amount-screen/value-out-of-limits?])
|
||||
current-address (rf/sub [:wallet/current-viewing-account-address])
|
||||
not-enough-asset? (rf/sub [:send-input-amount-screen/not-enough-asset?])
|
||||
show-no-routes? (rf/sub [:send-input-amount-screen/show-no-routes?])
|
||||
show-estimated-fees? (rf/sub [:send-input-amount-screen/show-estimated-fees?])
|
||||
token-not-available? (rf/sub [:send-input-amount-screen/token-not-available?])]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when active-screen?
|
||||
@@ -310,125 +257,48 @@
|
||||
(hot-reload/use-safe-unmount on-navigate-back)
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(set-input-state #(controlled-input/set-upper-limit % max-limit)))
|
||||
[max-limit])
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when input-error
|
||||
(when value-out-of-limits?
|
||||
(rf/dispatch [:wallet/stop-get-suggested-routes])
|
||||
(debounce/clear-all)))
|
||||
[input-error])
|
||||
[value-out-of-limits?])
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(clear-input!)
|
||||
(rf/dispatch [:send-input-amount-screen/token-input-delete-all])
|
||||
(rf/dispatch [:wallet/stop-and-clean-suggested-routes])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks]))
|
||||
[current-address])
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(request-fetch-routes 0))
|
||||
[send-from-locked-amounts])
|
||||
[rn/view
|
||||
{:style style/screen
|
||||
:accessibility-label (str "container"
|
||||
(when (controlled-input/input-error input-state) "-error"))}
|
||||
(when value-out-of-limits? "-error"))}
|
||||
[account-switcher/view
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:switcher-type :select-account}]
|
||||
[quo/token-input
|
||||
{:container-style style/input-container
|
||||
:token-symbol token-symbol
|
||||
:value input-value
|
||||
:on-swap swap-between-fiat-and-crypto
|
||||
:on-token-press show-select-asset-sheet
|
||||
:error? (controlled-input/input-error input-state)
|
||||
:currency-symbol (if crypto-currency? token-symbol fiat-currency)
|
||||
:converted-value (if crypto-currency?
|
||||
(utils/prettify-balance
|
||||
currency-symbol
|
||||
(money/crypto->fiat input-value
|
||||
conversion-rate))
|
||||
(utils/prettify-crypto-balance
|
||||
(or (clj->js token-symbol) "")
|
||||
(money/fiat->crypto input-value
|
||||
conversion-rate)
|
||||
conversion-rate))
|
||||
:hint-component [quo/network-tags
|
||||
{:networks (seq from-enabled-networks)
|
||||
:title (i18n/label
|
||||
:t/send-limit
|
||||
{:limit (if crypto-currency?
|
||||
(utils/prettify-crypto-balance
|
||||
(or (clj->js token-symbol) "")
|
||||
(controlled-input/upper-limit-bn input-state)
|
||||
conversion-rate)
|
||||
(utils/prettify-balance currency-symbol
|
||||
(controlled-input/upper-limit-bn
|
||||
input-state)))})
|
||||
:status (when (controlled-input/input-error input-state) :error)}]}]
|
||||
[routes/view
|
||||
{:token token-by-symbol
|
||||
:send-amount-in-crypto amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:token-not-supported-in-receiver-networks? unsupported-token-in-receiver?
|
||||
:current-screen-id current-screen-id
|
||||
:request-fetch-routes request-fetch-routes}]
|
||||
(when (and (not loading-routes?)
|
||||
sender-network-values
|
||||
unsupported-token-in-receiver?)
|
||||
[token-not-available token-symbol receiver-networks token-networks])
|
||||
[token-input]
|
||||
[routes-view current-screen-id]
|
||||
(when token-not-available?
|
||||
[token-not-available])
|
||||
(when not-enough-asset?
|
||||
[not-enough-asset])
|
||||
(when (or (and (not no-routes-found?) (or loading-routes? route))
|
||||
not-enough-asset?)
|
||||
[estimated-fees
|
||||
{:loading-routes? loading-routes?
|
||||
:fees fee-formatted
|
||||
:amount amount-text}])
|
||||
(when show-estimated-fees?
|
||||
[estimated-fees])
|
||||
(when show-no-routes?
|
||||
[no-routes-found])
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (if should-try-again?
|
||||
(i18n/label :t/try-again)
|
||||
button-one-label)
|
||||
:button-one-props (merge (when-not should-try-again?
|
||||
button-one-props)
|
||||
{:disabled? (or not-enough-asset?
|
||||
loading-routes?
|
||||
(and (not should-try-again?)
|
||||
confirm-disabled?))
|
||||
:on-press (cond
|
||||
should-try-again?
|
||||
#(rf/dispatch [:wallet/start-get-suggested-routes
|
||||
{:amount amount-in-crypto
|
||||
:updated-token token-by-symbol}])
|
||||
sending-to-unpreferred-networks?
|
||||
#(show-unpreferred-networks-alert on-confirm)
|
||||
:else
|
||||
#(on-confirm amount-in-crypto))
|
||||
:customization-color current-color}
|
||||
(when should-try-again?
|
||||
{:type :grey}))}]
|
||||
[bottom-actions button-one-label button-one-props on-confirm]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style (style/keyboard-container bottom)
|
||||
:left-action :dot
|
||||
:delete-key? true
|
||||
:on-press (fn [c]
|
||||
(let [new-text (str input-value c)
|
||||
max-decimals (if crypto-currency? crypto-decimals 2)
|
||||
regex-pattern (str "^\\d*\\.?\\d{0," max-decimals "}$")
|
||||
regex (re-pattern regex-pattern)]
|
||||
(when (re-matches regex new-text)
|
||||
(debounce/clear-all)
|
||||
(set-input-state #(controlled-input/add-character % c)))))
|
||||
(rf/dispatch [:send-input-amount-screen/token-input-add-character c
|
||||
max-decimals]))
|
||||
:on-delete (fn []
|
||||
(debounce/clear-all)
|
||||
(set-input-state controlled-input/delete-last)
|
||||
(rf/dispatch [:send-input-amount-screen/token-input-delete-last])
|
||||
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes]))
|
||||
:on-long-press-delete (fn []
|
||||
(debounce/clear-all)
|
||||
(set-input-state controlled-input/delete-all)
|
||||
(rf/dispatch [:send-input-amount-screen/token-input-delete-all])
|
||||
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes]))}]]))
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
receiver-preferred-networks (rf/sub
|
||||
[:wallet/wallet-send-receiver-preferred-networks])
|
||||
{token-symbol :symbol
|
||||
token-networks :networks} (rf/sub [:wallet/wallet-send-token])
|
||||
token-networks :supported-networks} (rf/sub [:wallet/wallet-send-token])
|
||||
token-chain-ids-set (set (mapv #(:chain-id %) token-networks))
|
||||
[selected-receiver-networks
|
||||
set-selected-receiver-networks] (rn/use-state receiver-networks)
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
(defn view
|
||||
[]
|
||||
[input-amount/view
|
||||
{:current-screen-id :screen/wallet.send-input-amount
|
||||
:button-one-label (i18n/label :t/review-send)
|
||||
:enabled-from-chain-ids (rf/sub [:wallet/wallet-send-enabled-from-chain-ids])
|
||||
:from-enabled-networks (rf/sub [:wallet/wallet-send-enabled-networks])
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:wallet/clean-from-locked-amounts])
|
||||
(rf/dispatch [:wallet/clean-send-amount]))}])
|
||||
{:current-screen-id :screen/wallet.send-input-amount
|
||||
:button-one-label (i18n/label :t/review-send)
|
||||
:on-confirm (fn [amount]
|
||||
(rf/dispatch [:wallet/set-token-amount-to-send
|
||||
{:amount amount
|
||||
:stack-id :screen/wallet.send-input-amount}]))
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch-sync [:wallet/stop-and-clean-suggested-routes])
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:wallet/clean-from-locked-amounts])
|
||||
(rf/dispatch [:wallet/clean-send-amount]))}])
|
||||
|
||||
@@ -223,7 +223,7 @@
|
||||
bridge-to-chain-id]))
|
||||
loading-suggested-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
total-amount-receiver (rf/sub [:wallet/total-amount true])
|
||||
total-amount-receiver (rf/sub [:wallet/total-amount-in-to-chains])
|
||||
from-account-props {:customization-color account-color
|
||||
:size 32
|
||||
:emoji (:emoji account)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
(fn [{:keys [db]} [{:keys [network asset-to-receive open-new-screen?] :as data}]]
|
||||
(let [{:keys [wallet]} db
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
view-id (:view-id db)
|
||||
account (swap-utils/wallet-account wallet)
|
||||
asset-to-pay (if (get-in data [:asset-to-pay :networks])
|
||||
(:asset-to-pay data)
|
||||
@@ -30,12 +31,13 @@
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :swap :asset-to-pay] asset-to-pay)
|
||||
(assoc-in [:wallet :ui :swap :asset-to-receive] asset-to-receive)
|
||||
(assoc-in [:wallet :ui :swap :network] network'))
|
||||
(assoc-in [:wallet :ui :swap :network] network')
|
||||
(assoc-in [:wallet :ui :swap :launch-screen] view-id))
|
||||
:fx (if network'
|
||||
[[:dispatch [:wallet/switch-current-viewing-account (:address account)]]
|
||||
[:dispatch
|
||||
(if open-new-screen?
|
||||
[:navigate-to :screen/wallet.setup-swap]
|
||||
[:open-modal :screen/wallet.setup-swap]
|
||||
[:navigate-to-within-stack
|
||||
[:screen/wallet.setup-swap :screen/wallet.swap-select-asset-to-pay]])]
|
||||
[:dispatch [:wallet.swap/set-default-slippage]]]
|
||||
@@ -204,12 +206,6 @@
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui] dissoc :swap)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/on-swap-done
|
||||
(fn [_]
|
||||
{:fx [[:dispatch [:wallet/select-account-tab :activity]]
|
||||
[:dispatch [:wallet/clean-swap]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [wallet-address (get-in db
|
||||
@@ -299,6 +295,7 @@
|
||||
:screen/wallet.swap-set-spending-cap
|
||||
:screen/wallet.swap-confirmation)])
|
||||
(when-not approval-required?
|
||||
(rf/dispatch [:wallet/end-swap-flow])
|
||||
(debounce/debounce-and-dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-transaction-pending
|
||||
@@ -424,3 +421,12 @@
|
||||
:last-request-uuid
|
||||
:approved-amount
|
||||
:approval-transaction-id)))})))
|
||||
|
||||
(rf/reg-event-fx :wallet/end-swap-flow
|
||||
(fn [{:keys [db]}]
|
||||
(let [launch-screen (get-in db [:wallet :ui :swap :launch-screen])
|
||||
address (get-in db [:wallet :current-viewing-account-address])]
|
||||
{:fx [(when (= launch-screen :wallet-stack)
|
||||
[:dispatch [:wallet/navigate-to-account-within-stack address]])
|
||||
[:dispatch [:wallet/fetch-activities-for-current-account]]
|
||||
[:dispatch [:wallet/select-account-tab :activity]]]})))
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
(let [pay-token-symbol (:symbol token)
|
||||
asset-to-receive (if (= pay-token-symbol "SNT") eth-token snt-token)]
|
||||
(rf/dispatch [:wallet.swap/start
|
||||
{:asset-to-pay token
|
||||
{:asset-to-pay {:symbol pay-token-symbol}
|
||||
:asset-to-receive asset-to-receive
|
||||
:open-new-screen? false}])))]
|
||||
[:<>
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
:valid-input? valid-pay-input?
|
||||
:clean-approval-transaction? true}))
|
||||
[pay-input-amount])]
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/on-swap-done]))
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/clean-swap]))
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(request-fetch-swap-proposal))
|
||||
|
||||
@@ -65,7 +65,11 @@
|
||||
:tokens
|
||||
(filter #(= token-symbol (:symbol %)))
|
||||
first)]
|
||||
(assoc token :networks (network-utils/network-list token networks))))
|
||||
(assoc token
|
||||
:networks
|
||||
(network-utils/network-list-with-positive-balance
|
||||
token
|
||||
networks))))
|
||||
|
||||
(defn select-default-asset-to-receive
|
||||
"Selects an asset to receive if it was not provided explicitly.
|
||||
|
||||
@@ -20,38 +20,50 @@
|
||||
|
||||
(defn store-token-list
|
||||
[{:keys [db]} [{:keys [data]}]]
|
||||
(let [chain-ids (chain/chain-ids db)
|
||||
tokens (reduce (fn [{:keys [by-address by-symbol] :as data}
|
||||
{:keys [name source version tokens]}]
|
||||
(-> data
|
||||
(update :sources
|
||||
conj
|
||||
{:name name
|
||||
:source source
|
||||
:version version
|
||||
:tokens-count (count tokens)})
|
||||
(update :by-address
|
||||
merge
|
||||
(tokens-data/tokens-by-address
|
||||
{:added-tokens by-address
|
||||
:source-name name
|
||||
:tokens tokens
|
||||
:chain-ids chain-ids}))
|
||||
(update :by-symbol
|
||||
merge
|
||||
(tokens-data/tokens-by-symbol
|
||||
{:added-tokens by-symbol
|
||||
:source-name name
|
||||
:tokens tokens
|
||||
:chain-ids chain-ids}))))
|
||||
{:sources []
|
||||
:by-address {}
|
||||
:by-symbol {}}
|
||||
data)
|
||||
symbols (->> tokens
|
||||
:by-symbol
|
||||
keys
|
||||
(remove utils.address/address?))]
|
||||
(let [chain-ids (chain/chain-ids db)
|
||||
tokens (reduce (fn [{:keys [by-address by-symbol] :as data}
|
||||
{:keys [name source version tokens]}]
|
||||
(-> data
|
||||
(update :sources
|
||||
conj
|
||||
{:name name
|
||||
:source source
|
||||
:version version
|
||||
:tokens-count (count tokens)})
|
||||
(update :by-address
|
||||
merge
|
||||
(tokens-data/tokens-by-address
|
||||
{:added-tokens by-address
|
||||
:source-name name
|
||||
:tokens tokens
|
||||
:chain-ids chain-ids}))
|
||||
(update :by-symbol
|
||||
merge
|
||||
(tokens-data/tokens-by-symbol
|
||||
{:added-tokens by-symbol
|
||||
:source-name name
|
||||
:tokens tokens
|
||||
:chain-ids chain-ids}))))
|
||||
{:sources []
|
||||
:by-address {}
|
||||
:by-symbol {}}
|
||||
data)
|
||||
symbols (->> tokens
|
||||
:by-symbol
|
||||
vals
|
||||
(map :symbol)
|
||||
set
|
||||
vec)
|
||||
by-symbol-vals (-> tokens :by-symbol vals)
|
||||
supported-chains-by-symbol (reduce
|
||||
(fn [result
|
||||
{token-symbol :symbol
|
||||
:keys [chain-id]}]
|
||||
(if (contains? result token-symbol)
|
||||
(update result token-symbol conj chain-id)
|
||||
(assoc result token-symbol #{chain-id})))
|
||||
{}
|
||||
by-symbol-vals)]
|
||||
{:fx [[:effects.wallet.tokens/fetch-market-values
|
||||
{:symbols symbols
|
||||
:currency constants/profile-default-currency
|
||||
@@ -68,9 +80,10 @@
|
||||
:on-error [:wallet.tokens/fetch-prices-failed]}]]
|
||||
:db (-> db
|
||||
(assoc-in [:wallet :tokens]
|
||||
{:sources (:sources tokens)
|
||||
:by-address (-> tokens :by-address vals)
|
||||
:by-symbol (-> tokens :by-symbol vals)})
|
||||
{:sources (:sources tokens)
|
||||
:supported-chains-by-symbol supported-chains-by-symbol
|
||||
:by-address (-> tokens :by-address vals)
|
||||
:by-symbol by-symbol-vals})
|
||||
(assoc-in [:wallet :ui :loading]
|
||||
{:token-list false
|
||||
:market-values true
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
(match?
|
||||
(:db (tokens.events/store-token-list cofx [{:data data}]))
|
||||
{:wallet {:networks {:prod [{:chain-id 1}]}
|
||||
:tokens {:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}]
|
||||
:tokens {:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}]
|
||||
:by-address '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000000"
|
||||
@@ -73,28 +73,29 @@
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ETH"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000001"
|
||||
:decimals 18
|
||||
:key "1-SNT"
|
||||
:community-id nil
|
||||
:symbol "SNT"
|
||||
:sources ["native"]
|
||||
:name "Status Network Token"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil})}
|
||||
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ETH"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000001"
|
||||
:decimals 18
|
||||
:key "1-SNT"
|
||||
:community-id nil
|
||||
:symbol "SNT"
|
||||
:sources ["native"]
|
||||
:name "Status Network Token"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:supported-chains-by-symbol {"ETH" #{1} "SNT" #{1}}}
|
||||
:ui {:loading {:token-list false
|
||||
:market-values true
|
||||
:details true
|
||||
@@ -109,12 +110,13 @@
|
||||
:db
|
||||
:wallet
|
||||
:tokens)
|
||||
{:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}]
|
||||
:by-address nil
|
||||
:by-symbol nil}))))
|
||||
{:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}]
|
||||
:by-address nil
|
||||
:by-symbol nil
|
||||
:supported-chains-by-symbol {}}))))
|
||||
(testing "response contains two lists"
|
||||
(let [cofx {:db {:wallet {:networks {:prod [{:chain-id 1}]}}}}
|
||||
data [{:name "native"
|
||||
@@ -131,80 +133,81 @@
|
||||
:db
|
||||
:wallet
|
||||
:tokens)
|
||||
{:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}
|
||||
{:name "second"
|
||||
:source "second"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}]
|
||||
:by-address '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000000"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000001"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000001"
|
||||
:community-id nil
|
||||
:symbol "SNT"
|
||||
:sources ["native" "second"]
|
||||
:name "Status Network Token"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000002"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000002"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["second"]
|
||||
:name "Another Token 1"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ETH"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000001"
|
||||
:decimals 18
|
||||
:key "1-SNT"
|
||||
:community-id nil
|
||||
:symbol "SNT"
|
||||
:sources ["native" "second"]
|
||||
:name "Status Network Token"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000002"
|
||||
:decimals 18
|
||||
:key "1-ANOTHER1"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["second"]
|
||||
:name "Another Token 1"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})}))))
|
||||
{:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}
|
||||
{:name "second"
|
||||
:source "second"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}]
|
||||
:by-address '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000000"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000001"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000001"
|
||||
:community-id nil
|
||||
:symbol "SNT"
|
||||
:sources ["native" "second"]
|
||||
:name "Status Network Token"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000002"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000002"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["second"]
|
||||
:name "Another Token 1"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ETH"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000001"
|
||||
:decimals 18
|
||||
:key "1-SNT"
|
||||
:community-id nil
|
||||
:symbol "SNT"
|
||||
:sources ["native" "second"]
|
||||
:name "Status Network Token"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000002"
|
||||
:decimals 18
|
||||
:key "1-ANOTHER1"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["second"]
|
||||
:name "Another Token 1"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:supported-chains-by-symbol {"ETH" #{1} "SNT" #{1} "ANOTHER1" #{1}}}))))
|
||||
(testing "second list contains a token that replaces the one that was added before"
|
||||
(let [cofx {:db {:wallet {:networks {:prod [{:chain-id 1}]}}}}
|
||||
data [{:name "native"
|
||||
@@ -221,55 +224,56 @@
|
||||
:db
|
||||
:wallet
|
||||
:tokens)
|
||||
{:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}
|
||||
{:name "second"
|
||||
:source "second"
|
||||
:version "1.0.0"
|
||||
:tokens-count 1}]
|
||||
:by-address '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000000"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["native" "second"]
|
||||
:name "Another Token 2"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000002"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000002"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["native"]
|
||||
:name "Another Token 1"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ETH"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ANOTHER1"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["native" "second"]
|
||||
:name "Another Token 2"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})})))))
|
||||
{:sources [{:name "native"
|
||||
:source "native"
|
||||
:version "1.0.0"
|
||||
:tokens-count 2}
|
||||
{:name "second"
|
||||
:source "second"
|
||||
:version "1.0.0"
|
||||
:tokens-count 1}]
|
||||
:by-address '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000000"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["native" "second"]
|
||||
:name "Another Token 2"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000002"
|
||||
:decimals 18
|
||||
:key "1-0x0000000000000000000000000000000000000002"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["native"]
|
||||
:name "Another Token 1"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:by-symbol '({:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ETH"
|
||||
:community-id nil
|
||||
:symbol "ETH"
|
||||
:sources ["native"]
|
||||
:name "Ether"
|
||||
:type :erc20
|
||||
:verified? true
|
||||
:chain-id 1
|
||||
:image nil}
|
||||
{:address "0x0000000000000000000000000000000000000000"
|
||||
:decimals 18
|
||||
:key "1-ANOTHER1"
|
||||
:community-id nil
|
||||
:symbol "ANOTHER1"
|
||||
:sources ["native" "second"]
|
||||
:name "Another Token 2"
|
||||
:type :erc20
|
||||
:verified? false
|
||||
:chain-id 1
|
||||
:image nil})
|
||||
:supported-chains-by-symbol {"ETH" #{1} "ANOTHER1" #{1}}})))))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
(ns status-im.setup.interceptor-metrics
|
||||
(:require
|
||||
#?@(:mobile
|
||||
[[re-frame.core :as re-frame]
|
||||
[status-im.contexts.centralized-metrics.events :as centralized-metrics]])))
|
||||
|
||||
(defn setup-centralized-metrics-interceptor
|
||||
[]
|
||||
#?(:mobile
|
||||
(re-frame/reg-global-interceptor centralized-metrics/interceptor)))
|
||||
@@ -2,13 +2,13 @@
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[re-frame.std-interceptors :as std-interceptors]
|
||||
[status-im.contexts.centralized-metrics.events :as centralized-metrics]
|
||||
[status-im.setup.interceptor-metrics :as interceptor-metrics]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn register-global-interceptors
|
||||
[]
|
||||
(re-frame/reg-global-interceptor rf/debug-handlers-names)
|
||||
(re-frame/reg-global-interceptor centralized-metrics/interceptor)
|
||||
(interceptor-metrics/setup-centralized-metrics-interceptor)
|
||||
(re-frame/reg-global-interceptor (re-frame/inject-cofx :now))
|
||||
|
||||
;; Interceptor `trim-v` removes the first element of the event vector.
|
||||
|
||||
@@ -125,7 +125,8 @@
|
||||
:<- [:contacts/blocked-set]
|
||||
:<- [:contacts/contacts-raw]
|
||||
:<- [:chat/inputs]
|
||||
(fn [[{:keys [group-chat chat-id] :as current-chat} my-public-key community blocked-users-set contacts
|
||||
(fn [[{:keys [group-chat chat-id chat-name name] :as current-chat} my-public-key community
|
||||
blocked-users-set contacts
|
||||
inputs]]
|
||||
(when current-chat
|
||||
(cond-> current-chat
|
||||
@@ -140,6 +141,9 @@
|
||||
(assoc :able-to-send-message? true
|
||||
:member? true)
|
||||
|
||||
(not chat-name)
|
||||
(assoc :chat-name name)
|
||||
|
||||
(not group-chat)
|
||||
(assoc
|
||||
:contact-request-state (get-in contacts [chat-id :contact-request-state])
|
||||
@@ -164,6 +168,7 @@
|
||||
(condp apply [current-chat]
|
||||
chat.events/community-chat? :community-chat
|
||||
chat.events/group-chat? :group-chat
|
||||
chat.events/public-chat? :public-chat
|
||||
:chat)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.pixel-ratio :as pixel-ratio]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.profile.data-store :as profile.data-store]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
@@ -17,6 +18,15 @@
|
||||
(fn [{:keys [customization-color]}]
|
||||
(or customization-color constants/profile-default-color)))
|
||||
|
||||
;; A profile can only be created without accepting terms in Status v1. In Status
|
||||
;; v2, the terms may be unaccepted because we intentionally created a migration
|
||||
;; resetting the flag in case the privacy policy changed.
|
||||
(re-frame/reg-sub :profile/has-profiles-and-unaccepted-terms?
|
||||
:<- [:profile/profiles-overview]
|
||||
(fn [profiles-overview]
|
||||
(and (seq profiles-overview)
|
||||
(not (profile.data-store/accepted-terms? (vals profiles-overview))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:profile/currency
|
||||
:<- [:profile/profile]
|
||||
|
||||
@@ -76,14 +76,13 @@
|
||||
network-values))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/total-amount
|
||||
:wallet/total-amount-in-to-chains
|
||||
:<- [:wallet/wallet-send]
|
||||
(fn [{:keys [from-values-by-chain to-values-by-chain]} [_ to-values?]]
|
||||
(let [network-values (if to-values? to-values-by-chain from-values-by-chain)]
|
||||
(reduce
|
||||
(fn [acc amount]
|
||||
(if (money/bignumber? amount)
|
||||
(money/add acc amount)
|
||||
acc))
|
||||
(money/bignumber 0)
|
||||
(vals network-values)))))
|
||||
(fn [{:keys [to-values-by-chain]}]
|
||||
(reduce
|
||||
(fn [acc amount]
|
||||
(if (money/bignumber? amount)
|
||||
(money/add acc amount)
|
||||
acc))
|
||||
(money/bignumber 0)
|
||||
(vals to-values-by-chain))))
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
(ns status-im.subs.wallet.screens.input-amount
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.input-amount.controlled-input-logic :as controlled-input-logic]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/state
|
||||
:<- [:wallet/wallet-screens]
|
||||
:-> :input-amount-screen)
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/enabled-from-chain-ids
|
||||
:<- [:wallet/wallet-send-tx-type]
|
||||
:<- [:wallet/wallet-send-enabled-from-chain-ids]
|
||||
:<- [:wallet/bridge-from-chain-ids]
|
||||
(fn [[tx-type send-chain-ids bridge-chain-ids]]
|
||||
(if (= tx-type :tx/bridge)
|
||||
bridge-chain-ids
|
||||
send-chain-ids)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/from-enabled-networks
|
||||
:<- [:wallet/wallet-send-tx-type]
|
||||
:<- [:wallet/wallet-send-enabled-networks]
|
||||
:<- [:wallet/bridge-from-networks]
|
||||
(fn [[tx-type send-enabled-networks bridge-enabled-networks]]
|
||||
(if (= tx-type :tx/bridge)
|
||||
bridge-enabled-networks
|
||||
send-enabled-networks)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/token-by-symbol
|
||||
:<- [:send-input-amount-screen/enabled-from-chain-ids]
|
||||
:<- [:wallet/wallet-send-token]
|
||||
(fn [[enabled-from-chain-ids
|
||||
{token-symbol :symbol}]]
|
||||
(rf/sub [:wallet/token-by-symbol
|
||||
(str token-symbol)
|
||||
enabled-from-chain-ids])))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/total-balance
|
||||
:<- [:send-input-amount-screen/token-by-symbol]
|
||||
(fn [{:keys [total-balance]}]
|
||||
total-balance))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/conversion-rate
|
||||
:<- [:wallet/wallet-send-token]
|
||||
:<- [:profile/currency]
|
||||
(fn [[token
|
||||
currency]]
|
||||
(-> token
|
||||
:market-values-per-currency
|
||||
currency
|
||||
:price)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/usd-conversion-rate
|
||||
:<- [:wallet/wallet-send-token]
|
||||
(fn [token]
|
||||
(utils/token-usd-price token)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/token-decimals
|
||||
:<- [:wallet/wallet-send-token]
|
||||
(fn [token]
|
||||
(-> token
|
||||
utils/token-usd-price
|
||||
utils/one-cent-value
|
||||
utils/calc-max-crypto-decimals)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/max-decimals
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/token-decimals]
|
||||
(fn [[{:keys [crypto-currency?]}
|
||||
token-decimals]]
|
||||
(if crypto-currency? token-decimals 2)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/upper-limit
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/conversion-rate]
|
||||
:<- [:send-input-amount-screen/usd-conversion-rate]
|
||||
:<- [:send-input-amount-screen/total-balance]
|
||||
(fn [[{:keys [crypto-currency?]}
|
||||
conversion-rate
|
||||
usd-conversion-rate
|
||||
total-balance]]
|
||||
(if crypto-currency?
|
||||
(utils/cut-crypto-decimals-to-fit-usd-cents
|
||||
total-balance
|
||||
usd-conversion-rate)
|
||||
(utils/cut-fiat-balance-to-two-decimals
|
||||
(money/crypto->fiat total-balance conversion-rate)))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/upper-limit-prettified
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:profile/currency-symbol]
|
||||
:<- [:wallet/wallet-send-token]
|
||||
:<- [:send-input-amount-screen/conversion-rate]
|
||||
:<- [:send-input-amount-screen/upper-limit]
|
||||
(fn [[{:keys [crypto-currency?]}
|
||||
currency-symbol
|
||||
{token-symbol :symbol}
|
||||
conversion-rate
|
||||
upper-limit]]
|
||||
(if crypto-currency?
|
||||
(utils/prettify-crypto-balance
|
||||
(or (clj->js token-symbol) "")
|
||||
(money/bignumber upper-limit)
|
||||
conversion-rate)
|
||||
(utils/prettify-balance currency-symbol
|
||||
(money/bignumber upper-limit)))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/upper-limit-exceeded?
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/upper-limit]
|
||||
(fn [[{:keys [input-value]}
|
||||
upper-limit]]
|
||||
(controlled-input-logic/upper-limit-exceeded?
|
||||
input-value
|
||||
upper-limit)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/value-out-of-limits?
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/upper-limit]
|
||||
(fn [[{:keys [input-value]}
|
||||
upper-limit]]
|
||||
(controlled-input-logic/value-out-of-limits? input-value upper-limit 0)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/valid-input?
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/value-out-of-limits?]
|
||||
(fn [[{:keys [input-value]}
|
||||
value-out-of-limits?]]
|
||||
(not (or (controlled-input-logic/empty-value? input-value) value-out-of-limits?))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/upper-limit-equals-input-value?
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/upper-limit]
|
||||
(fn [[{:keys [input-value]}
|
||||
upper-limit]]
|
||||
(money/equal-to
|
||||
(money/bignumber input-value)
|
||||
(money/bignumber upper-limit))))
|
||||
|
||||
|
||||
(defn- fiat->crypto
|
||||
[value conversion-rate]
|
||||
(-> value
|
||||
(money/fiat->crypto conversion-rate)
|
||||
(utils/cut-crypto-decimals-to-fit-usd-cents conversion-rate)))
|
||||
|
||||
(defn- crypto->fiat
|
||||
[value conversion-rate]
|
||||
(-> value
|
||||
(money/crypto->fiat conversion-rate)
|
||||
(utils/cut-fiat-balance-to-two-decimals)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/input-value-converted
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/conversion-rate]
|
||||
(fn [[{:keys [crypto-currency? input-value]}
|
||||
conversion-rate]]
|
||||
(if crypto-currency?
|
||||
(crypto->fiat input-value conversion-rate)
|
||||
(fiat->crypto input-value conversion-rate))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/converted-value-prettified
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/input-value-converted]
|
||||
:<- [:profile/currency-symbol]
|
||||
:<- [:wallet/wallet-send-token]
|
||||
(fn [[{:keys [crypto-currency?]}
|
||||
token-input-converted-value
|
||||
currency-symbol
|
||||
{token-symbol :symbol}]]
|
||||
(if crypto-currency?
|
||||
(utils/prepend-curency-symbol-to-fiat-balance token-input-converted-value currency-symbol)
|
||||
(utils/add-token-symbol-to-crypto-balance token-input-converted-value
|
||||
(or (clj->js token-symbol) "")))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/amount-in-crypto
|
||||
:<- [:send-input-amount-screen/state]
|
||||
:<- [:send-input-amount-screen/conversion-rate]
|
||||
:<- [:send-input-amount-screen/token-decimals]
|
||||
(fn [[{:keys [crypto-currency? input-value]}
|
||||
conversion-rate
|
||||
token-decimals]]
|
||||
(if crypto-currency?
|
||||
input-value
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed (/ input-value conversion-rate) token-decimals)))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/recipient-gets-amount
|
||||
:<- [:send-input-amount-screen/conversion-rate]
|
||||
:<- [:wallet/total-amount-in-to-chains]
|
||||
:<- [:wallet/wallet-send-token]
|
||||
(fn [[conversion-rate
|
||||
total-amount-receiver
|
||||
{token-symbol :symbol}]]
|
||||
(utils/prettify-crypto-balance
|
||||
token-symbol
|
||||
total-amount-receiver
|
||||
conversion-rate)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/routes
|
||||
:<- [:wallet/wallet-send-suggested-routes]
|
||||
(fn [suggested-routes]
|
||||
(when suggested-routes
|
||||
(or (:best suggested-routes) []))))
|
||||
|
||||
(defn- every-network-value-is-zero?
|
||||
[sender-network-values]
|
||||
(every? (fn [{:keys [total-amount]}]
|
||||
(and
|
||||
total-amount
|
||||
(money/bignumber? total-amount)
|
||||
(money/equal-to total-amount
|
||||
(money/bignumber "0"))))
|
||||
sender-network-values))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/unsupported-token-in-receiver?
|
||||
:<- [:wallet/wallet-send-receiver-network-values]
|
||||
:<- [:wallet/wallet-send-tx-type]
|
||||
(fn [[receiver-network-values
|
||||
tx-type]]
|
||||
(and (not= tx-type :tx/bridge)
|
||||
(->> receiver-network-values
|
||||
(remove #(= (:type %) :add))
|
||||
(every? #(= (:type %) :not-available))))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/no-routes-found?
|
||||
:<- [:wallet/wallet-send-sender-network-values]
|
||||
:<- [:send-input-amount-screen/routes]
|
||||
:<- [:wallet/wallet-send-loading-suggested-routes?]
|
||||
:<- [:send-input-amount-screen/unsupported-token-in-receiver?]
|
||||
(fn [[sender-network-values
|
||||
routes
|
||||
loading-routes?
|
||||
unsupported-token-in-receiver?]]
|
||||
(and
|
||||
(every-network-value-is-zero? sender-network-values)
|
||||
(some? routes)
|
||||
(not loading-routes?)
|
||||
(not unsupported-token-in-receiver?))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/sending-to-unpreferred-networks?
|
||||
:<- [:wallet/wallet-send-receiver-networks]
|
||||
:<- [:wallet/wallet-send-receiver-preferred-networks]
|
||||
(fn [[receiver-networks
|
||||
receiver-preferred-networks]]
|
||||
(some (comp not (set receiver-preferred-networks)) receiver-networks)))
|
||||
|
||||
(defn- insufficient-asset-amount?
|
||||
[{:keys [token-symbol owned-eth-token upper-limit-equals-input-value? no-routes-found? limit-exceeded?
|
||||
sender-network-values enough-assets?]}]
|
||||
(let [eth-selected? (= token-symbol (string/upper-case constants/mainnet-short-name))
|
||||
zero-owned-eth? (money/equal-to (:total-balance owned-eth-token) 0)
|
||||
exceeded-input? (if eth-selected?
|
||||
upper-limit-equals-input-value?
|
||||
zero-owned-eth?)]
|
||||
(and (or no-routes-found? limit-exceeded?)
|
||||
(seq sender-network-values)
|
||||
(or exceeded-input? (not enough-assets?)))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/not-enough-asset?
|
||||
:<- [:wallet/wallet-send-sender-network-values]
|
||||
:<- [:wallet/wallet-send-enough-assets?]
|
||||
:<- [:wallet/wallet-send-token]
|
||||
:<- [:send-input-amount-screen/upper-limit-equals-input-value?]
|
||||
:<- [:send-input-amount-screen/no-routes-found?]
|
||||
:<- [:send-input-amount-screen/upper-limit-exceeded?]
|
||||
:<- [:send-input-amount-screen/enabled-from-chain-ids]
|
||||
(fn [[sender-network-values
|
||||
enough-assets?
|
||||
{token-symbol :symbol}
|
||||
upper-limit-equals-input-value?
|
||||
no-routes-found?
|
||||
limit-exceeded?
|
||||
enabled-from-chain-ids]]
|
||||
(let [owned-eth-token (rf/sub [:wallet/token-by-symbol
|
||||
(string/upper-case constants/mainnet-short-name)
|
||||
enabled-from-chain-ids])]
|
||||
(insufficient-asset-amount?
|
||||
{:enough-assets? enough-assets?
|
||||
:token-symbol token-symbol
|
||||
:owned-eth-token owned-eth-token
|
||||
:upper-limit-equals-input-value? upper-limit-equals-input-value?
|
||||
:no-routes-found? no-routes-found?
|
||||
:limit-exceeded? limit-exceeded?
|
||||
:sender-network-values sender-network-values}))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/should-try-again?
|
||||
:<- [:send-input-amount-screen/upper-limit-exceeded?]
|
||||
:<- [:send-input-amount-screen/no-routes-found?]
|
||||
:<- [:send-input-amount-screen/not-enough-asset?]
|
||||
(fn [[limit-exceeded?
|
||||
no-routes-found?
|
||||
not-enough-asset?]]
|
||||
(and (not limit-exceeded?)
|
||||
no-routes-found?
|
||||
(not not-enough-asset?))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/show-no-routes?
|
||||
:<- [:send-input-amount-screen/upper-limit-exceeded?]
|
||||
:<- [:send-input-amount-screen/no-routes-found?]
|
||||
:<- [:send-input-amount-screen/not-enough-asset?]
|
||||
:<- [:wallet/wallet-send-sender-network-values]
|
||||
(fn [[limit-exceeded?
|
||||
no-routes-found?
|
||||
not-enough-asset?
|
||||
sender-network-values]]
|
||||
(and (or no-routes-found? limit-exceeded?)
|
||||
(not-empty sender-network-values)
|
||||
(not not-enough-asset?))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/confirm-disabled?
|
||||
:<- [:wallet/wallet-send-route]
|
||||
:<- [:send-input-amount-screen/valid-input?]
|
||||
(fn [[route
|
||||
valid-input?]]
|
||||
(or (nil? route)
|
||||
(empty? route)
|
||||
(not valid-input?))))
|
||||
|
||||
(defn- get-fee-formatted
|
||||
[route]
|
||||
(when-let [native-currency-symbol (-> route first :from :native-currency-symbol)]
|
||||
(rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/fee-formatted
|
||||
:<- [:wallet/wallet-send-route]
|
||||
:<- [:send-input-amount-screen/confirm-disabled?]
|
||||
:<- [:send-input-amount-screen/not-enough-asset?]
|
||||
(fn [[route
|
||||
confirm-disabled?
|
||||
not-enough-asset?]]
|
||||
(when (or (not confirm-disabled?) not-enough-asset?)
|
||||
(get-fee-formatted route))))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/show-estimated-fees?
|
||||
:<- [:wallet/wallet-send-route]
|
||||
:<- [:send-input-amount-screen/no-routes-found?]
|
||||
:<- [:send-input-amount-screen/not-enough-asset?]
|
||||
:<- [:wallet/wallet-send-loading-suggested-routes?]
|
||||
(fn [[route
|
||||
no-routes-found?
|
||||
not-enough-asset?
|
||||
loading-routes?]]
|
||||
(or (and (not no-routes-found?) (or loading-routes? route))
|
||||
not-enough-asset?)))
|
||||
|
||||
(rf/reg-sub :send-input-amount-screen/token-not-available?
|
||||
:<- [:wallet/wallet-send-sender-network-values]
|
||||
:<- [:send-input-amount-screen/unsupported-token-in-receiver?]
|
||||
:<- [:wallet/wallet-send-loading-suggested-routes?]
|
||||
(fn [[sender-network-values unsupported-token-in-receiver?
|
||||
loading-routes?]]
|
||||
(and (not loading-routes?)
|
||||
sender-network-values
|
||||
unsupported-token-in-receiver?)))
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
:<- [:wallet/ui]
|
||||
:-> :send)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-screens
|
||||
:<- [:wallet/ui]
|
||||
:-> :screens)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/send-recipient
|
||||
:<- [:wallet/wallet-send]
|
||||
|
||||
@@ -144,11 +144,12 @@
|
||||
(remove disabled-from-chain-ids?)
|
||||
set)]
|
||||
(some-> token
|
||||
(assoc :networks (network-utils/network-list token networks)
|
||||
:available-balance (utils/calculate-total-token-balance token)
|
||||
:total-balance (utils/calculate-total-token-balance
|
||||
token
|
||||
enabled-from-chain-ids))))))
|
||||
(assoc :networks (network-utils/network-list-with-positive-balance token networks)
|
||||
:supported-networks (network-utils/network-list token networks)
|
||||
:available-balance (utils/calculate-total-token-balance token)
|
||||
:total-balance (utils/calculate-total-token-balance
|
||||
token
|
||||
enabled-from-chain-ids))))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-token-symbol
|
||||
@@ -450,17 +451,20 @@
|
||||
(map
|
||||
(fn [token]
|
||||
(assoc token
|
||||
:bridge-disabled? (and (= tx-type :tx/bridge)
|
||||
(send-utils/bridge-disabled? (:symbol
|
||||
token)))
|
||||
:networks (cond->> (network-utils/network-list token
|
||||
networks)
|
||||
chain-ids
|
||||
(filter #(some #{(:chain-id %)} chain-ids)))
|
||||
:bridge-disabled? (and (= tx-type :tx/bridge)
|
||||
(send-utils/bridge-disabled? (:symbol
|
||||
token)))
|
||||
:networks (cond->>
|
||||
(network-utils/network-list-with-positive-balance
|
||||
token
|
||||
networks)
|
||||
chain-ids
|
||||
(filter #(some #{(:chain-id %)} chain-ids)))
|
||||
:supported-networks (network-utils/network-list token networks)
|
||||
:available-balance (utils/calculate-total-token-balance token)
|
||||
:total-balance (utils/calculate-total-token-balance
|
||||
token
|
||||
chain-ids))))
|
||||
:total-balance (utils/calculate-total-token-balance
|
||||
token
|
||||
chain-ids))))
|
||||
(filter (fn [{:keys [networks]}]
|
||||
(pos? (count networks))))
|
||||
(remove #(when hide-token-fn (hide-token-fn constants/swap-tokens-my %))))
|
||||
@@ -575,12 +579,26 @@
|
||||
tokens))
|
||||
addresses-tokens)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/current-account-owns-token
|
||||
(fn [[_ token-symbol]]
|
||||
[(rf/subscribe [:wallet/current-viewing-account-address])
|
||||
(rf/subscribe [:wallet/operable-addresses-with-token-symbol token-symbol])])
|
||||
(fn [[address addresses-with-token]]
|
||||
(-> addresses-with-token set (contains? address))))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/account-tab
|
||||
:<- [:wallet/ui]
|
||||
(fn [ui]
|
||||
(get-in ui [:account-page :active-tab])))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/home-tab
|
||||
:<- [:wallet/ui]
|
||||
(fn [ui]
|
||||
(:active-tab ui)))
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/aggregated-tokens
|
||||
:<- [:wallet/accounts-without-watched-accounts]
|
||||
|
||||
@@ -70,6 +70,9 @@
|
||||
{:initializeApplication
|
||||
(fn [request callback]
|
||||
(callback (.initializeApplication native-status request)))
|
||||
:acceptTerms
|
||||
(fn [callback]
|
||||
(callback (.acceptTerms native-status)))
|
||||
:createAccountAndLogin
|
||||
(fn [request] (.createAccountAndLogin native-status request))
|
||||
:restoreAccountAndLogin
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v3.3.0",
|
||||
"commit-sha1": "43659f0c7e1a64102e7f8e38bd532b72714c5819",
|
||||
"src-sha256": "01fpviw1g22f4ni3li2wnhyz0l517jfipvnyfysckds6yi94l0hf"
|
||||
"version": "v3.5.0",
|
||||
"commit-sha1": "39511298cdc8f50e7659ac8079d5bc8a4763ddc7",
|
||||
"src-sha256": "1nn8gq9d91ix5mzndr306rq3n68rzj4drym3pfaxzaa73k4v9r07"
|
||||
}
|
||||
|
||||
@@ -1002,6 +1002,7 @@
|
||||
"expand-all": "Expand all",
|
||||
"experienced-web3": "Experienced in Web3?",
|
||||
"explore-the-decentralized-web": "Explore and interact with the decentralized web",
|
||||
"explore-the-new-status": "Explore the new Status",
|
||||
"export-account": "Export account",
|
||||
"export-key": "Export private key",
|
||||
"external-link": "External link",
|
||||
@@ -2646,6 +2647,7 @@
|
||||
"untrustworthy": "Untrustworthy",
|
||||
"update": "Update",
|
||||
"update-account-name": "Update account name",
|
||||
"update-group-chat": "Update group chat",
|
||||
"update-nickname-title": "Update nickname",
|
||||
"update-to-listen-audio": "Update to latest version to listen to an audio message here!",
|
||||
"update-to-see-image": "Update to latest version to see a nice image here!",
|
||||
|
||||
Reference in New Issue
Block a user