Compare commits

..
Author SHA1 Message Date
Icaro Motta 3c3eabf2d3 feat(onboarding): Present Terms to users upgrading from v1 (#21124)
We now show the onboarding intro requesting the user to accept the Terms of Use
& Privacy Policy with the new button "Explore the new Status" if the user had
installed any version of Status older than the one from this PR and had at
least one profile.

Fixes https://github.com/status-im/status-mobile/issues/21113

status-go PR https://github.com/status-im/status-go/pull/5766

In practice, this means:

- Users coming from Status v1 who had at least one profile will see the
  modified onboarding intro screen and will need to accept the terms to proceed.
- Users who already installed v2 and are upgrading to this PR build (devs & QAs
  mostly) and who had at least one profile will also see the modified intro
  screen and will need to accept the terms to proceed.

Areas that may be impacted

- Onboarding

Steps to test:

The criteria used during development:

1. Given that user Alice had installed v1 and had one or more profiles.
2. When she installs v2 and opens it, she sees the new onboarding intro and must
   agree to the terms to enable the button "Explore the new Status".
3. After pressing the button, she can login as usual in any of her profiles.

1. Given that user Alice already upgraded from v1 and accepted the terms.
2. When she reopens the app she does not need to accept terms again and can
   immediately sign-in with any of her profiles.

1. Given that user Alice already upgraded from v1 and accepted the terms.
2. When she deletes all profiles, she sees the onboarding intro for users who
   have not upgraded, i.e. she has to agree to terms and she sees the usual two
   buttons "Create profile" and "Sync or recover profile".

1. Given that user Alice never installed Status.
2. When she installs v2, she sees the normal onboarding intro screen, where she
   has to accept the terms and she sees two buttons "Create profile" and "Sync
   or recover profile".
3. When she reopens the app, she doesn't see anymore the screen to accept terms.
2024-08-28 06:45:00 -03:00
Sean Hagstrom ac186e27de fix: change verbiage from privacy statement to privacy policy 2024-08-26 13:10:08 +00:00
Sean Hagstrom 917f10955a fix: adjust spacing and verbiage for terms-of-use and privacy-statement onboarding checkbox 2024-08-26 12:50:11 +01:00
Ulises M 8638a2266d Add link to Privacy Policy in onboarding flow 2024-08-26 12:04:42 +01:00
Sean Hagstrom baab56946e chore: update icons for android (#21112)
This change updates the Android icon assets for all builds (debug, PR, and release). This change attempts to support the Android adaptive icons and the monochrome/themeable icons for upcoming Android releases.
2024-08-26 10:52:46 +01:00
Sean Hagstrom d10a026908 chore: update icons for iOS and iPadOS release apps (#21111)
This commit updates the iOS and iPadOS icon assets for V2, and it also updates some app assets for the app logo.
2024-08-26 10:33:26 +01:00
Lungu Cristian 2cb50fcbf6 fix: send collectible token-id hex conversion (#21094) 2024-08-22 18:15:44 +03:00
111 changed files with 776 additions and 604 deletions
+1
View File
@@ -36,6 +36,7 @@
android:allowBackup="false"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.AppSplash"
android:name=".MainApplication"
android:largeHeap="true"
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 B

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 940 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 B

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 972 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 B

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 B

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 B

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 123 KiB

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_background"/>
<foreground android:drawable="@mipmap/ic_foreground"/>
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>
@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_background"/>
<foreground android:drawable="@mipmap/ic_foreground"/>
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 B

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 970 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 25 KiB

+3 -3
View File
@@ -1115,7 +1115,7 @@ PODS:
- React-perflogger (= 0.73.5)
- ReactNativeAudioToolkit (2.0.3):
- React
- ReactNativeCameraKit (14.0.0-beta15):
- ReactNativeCameraKit (14.0.0-beta13):
- React-Core
- ReactNativeNavigation (7.39.0):
- HMSegmentedControl
@@ -1485,7 +1485,7 @@ SPEC CHECKSUMS:
FBLazyVector: 56e0e498dbb513b96c40bac6284729ba4e62672d
FBReactNativeSpec: 146c741a3f40361f6bc13a4ba284678cbedb5881
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 36c15c01d70ed395c6e4f3619f98a23ee415b07a
glog: 530710e7949eb12c82670bd09e946becf50a3c2a
hermes-engine: 1d1835b2cc54c381909d94d1b3c8e0a2f1a94a0e
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
@@ -1551,7 +1551,7 @@ SPEC CHECKSUMS:
React-utils: 987a4526a2fc0acdfaf87888adfe0bf9d0452066
ReactCommon: 2947b0bffd82ea0e58ca7928881152d4c6dae9af
ReactNativeAudioToolkit: de9610f323e855ac6574be8c99621f3d57c5df06
ReactNativeCameraKit: 71343efc1256720184ce980f164c7eedb78d5c16
ReactNativeCameraKit: d95d3e19c514526a234d9f93c6db7e7f10eef9ea
ReactNativeNavigation: 679d8c8bf3b8ae98d285bce810964d10da85dbdb
RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb
RNCClipboard: 60fed4b71560d7bfe40e9d35dea9762b024da86d
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 413 KiB

@@ -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);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 64 KiB

+6
View File
@@ -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")
@@ -6,20 +6,16 @@
(h/describe "Wallet: Token Input"
(h/test "Token label renders"
(h/render-with-theme-provider [token-input/view
{:token-symbol :snt
:currency-symbol :snt
:on-swap nil
:error? false
:value "1"
:converted-value "10"}])
{:token :snt
:currency :eur
:currency-symbol "€"
:conversion 1}])
(h/is-truthy (h/get-by-text "SNT")))
(h/test "Amount renders"
(h/render-with-theme-provider [token-input/view
{:token-symbol :snt
:currency-symbol :snt
:on-swap nil
:error? false
:value "1"
:converted-value "€0.00"}])
{:token :snt
:currency :eur
:currency-symbol "€"
:conversion 1}])
(h/is-truthy (h/get-by-text "€0.00"))))
@@ -4,14 +4,15 @@
[:=>
[:catn
[:props
[:map {:closed true}
[:token-symbol [:maybe [:or :string :keyword]]]
[:currency-symbol [:maybe [:or :string :keyword]]]
[:hint-component {:optional true} [:maybe :schema.common/hiccup]]
[:on-token-press {:optional true} [:maybe fn?]]
[:on-swap [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:error? [:maybe :boolean]]
[:value [:maybe :string]]
[:converted-value [:maybe :string]]]]]
[:map
[:token {:optional true} [:maybe [:or :string :keyword]]]
[:currency {:optional true} [:maybe [:or :string :keyword]]]
[:error? {:optional true} [:maybe :boolean]]
[:title {:optional true} [:maybe :string]]
[:conversion {:optional true} [:maybe :double]]
[:show-keyboard? {:optional true} [:maybe :boolean]]
[:networks {:optional true}
[:maybe [:sequential [:map [:source [:maybe :schema.common/image-source]]]]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:value {:optional true} [:maybe :string]]]]]
:any])
@@ -25,11 +25,9 @@
(defn input-container
[window-width]
{:width (- window-width 120)
:margin-left 8
:margin-right 8
:flex-direction :row
:align-items :flex-end})
{:width (- window-width 120)
:margin-left 8
:margin-right 8})
(def text-input-dimensions
(-> typography/heading-1
@@ -67,6 +65,6 @@
:justify-content :space-between
:align-items :center})
(defn converted-amount
(defn fiat-amount
[theme]
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
+123 -53
View File
@@ -1,15 +1,57 @@
(ns quo.components.wallet.token-input.view
(:require
[clojure.string :as string]
[oops.core :as oops]
[quo.components.buttons.button.view :as button]
[quo.components.dividers.divider-line.view :as divider-line]
[quo.components.markdown.text :as text]
[quo.components.tags.network-tags.view :as network-tag]
[quo.components.utilities.token.view :as token]
[quo.components.wallet.token-input.schema :as component-schema]
[quo.components.wallet.token-input.style :as style]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]))
[schema.core :as schema]
[utils.number :as number]))
(defn fiat-format
[currency-symbol num-value conversion]
(str currency-symbol (.toFixed (* num-value conversion) 2)))
(defn crypto-format
[num-value conversion crypto-decimals token]
(str (number/remove-trailing-zeroes
(.toFixed (/ num-value conversion) (or crypto-decimals 2)))
" "
(string/upper-case (or (clj->js token) ""))))
(defn calc-value
[{:keys [crypto? currency-symbol token value conversion crypto-decimals]}]
(let [num-value (if (string? value)
(or (parse-double value) 0)
value)]
(if crypto?
(fiat-format currency-symbol num-value conversion)
(crypto-format num-value conversion crypto-decimals token))))
(defn- data-info
[{:keys [theme token crypto-decimals conversion networks title crypto? currency-symbol amount
error?]}]
[rn/view {:style style/data-container}
[network-tag/view
{:networks networks
:title title
:status (when error? :error)}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/fiat-amount theme)}
(calc-value {:crypto? crypto?
:currency-symbol currency-symbol
:token token
:value amount
:conversion conversion
:crypto-decimals crypto-decimals})]])
(defn- token-name-text
[theme text]
@@ -20,63 +62,91 @@
(string/upper-case (or (clj->js text) ""))])
(defn input-section
[{:keys [token-symbol on-token-press value error? on-swap currency-symbol]}]
(let [theme (quo.theme/use-theme)
window-width (:width (rn/get-window))]
[rn/pressable
{:style {:width "100%"
:flex-direction :row}
:on-press on-token-press}
[token/view
{:token token-symbol
:size :size-32}]
[rn/view {:style (style/input-container window-width)}
[rn/text-input
{:style (style/text-input theme error?)
:placeholder-text-color (style/placeholder-text theme)
:placeholder "0"
:keyboard-type :numeric
:editable false
:value value}]
[token-name-text theme currency-symbol]]
[button/button
{:icon true
:icon-only? true
:size 32
:on-press #(when on-swap (on-swap))
:type :outline
:accessibility-label :reorder}
:i/reorder]]))
[{:keys [on-change-text value value-internal set-value-internal on-selection-change
on-token-press]}]
(let [input-ref (atom nil)
set-ref #(reset! input-ref %)
focus-input #(when-let [ref ^js @input-ref]
(.focus ref))
controlled-input? (some? value)
handle-on-change-text (fn [v]
(when-not controlled-input?
(set-value-internal v))
(when on-change-text
(on-change-text v)))
handle-selection-change (fn [^js e]
(when on-selection-change
(-> e
(oops/oget "nativeEvent.selection")
(js->clj :keywordize-keys true)
(on-selection-change))))]
(fn [{:keys [token customization-color show-keyboard? crypto? currency value error? selection
handle-on-swap allow-selection?]
:or {show-keyboard? true
allow-selection? true}}]
(let [theme (quo.theme/use-theme)
window-width (:width (rn/get-window))]
[rn/pressable
{:style {:width "100%"
:flex-direction :row}
:on-press on-token-press}
[token/view
{:token token
:size :size-32}]
[rn/view {:style (style/input-container window-width)}
[rn/pressable
{:style style/text-input-container
:on-press focus-input}
[rn/text-input
(cond-> {:style (style/text-input theme error?)
:placeholder-text-color (style/placeholder-text theme)
:auto-focus true
:ref set-ref
:placeholder "0"
:keyboard-type :numeric
:on-change-text handle-on-change-text
:selection-color customization-color
:show-soft-input-on-focus show-keyboard?
:on-selection-change handle-selection-change
:selection (clj->js selection)
:editable allow-selection?}
controlled-input? (assoc :value value)
(not controlled-input?) (assoc :default-value value-internal))]
[token-name-text theme (if crypto? token currency)]]]
[button/button
{:icon true
:icon-only? true
:size 32
:on-press handle-on-swap
:type :outline
:accessibility-label :reorder}
:i/reorder]]))))
(defn- view-internal
[{:keys [token-symbol
value
on-token-press
error?
container-style
on-swap
converted-value
hint-component
currency-symbol]}]
(let [theme (quo.theme/use-theme)
width (:width (rn/get-window))]
[{:keys [container-style value on-swap] :as props}]
(let [theme (quo.theme/use-theme)
width (:width (rn/get-window))
[value-internal set-value-internal] (rn/use-state nil)
[crypto? set-crypto] (rn/use-state true)
handle-on-swap (rn/use-callback
(fn []
(set-crypto (not crypto?))
(when on-swap (on-swap (not crypto?))))
[crypto? on-swap])]
[rn/view {:style (merge (style/main-container width) container-style)}
[rn/view {:style style/amount-container}
[input-section
{:theme theme
:token-symbol token-symbol
:on-token-press on-token-press
:value value
:error? error?
:on-swap on-swap
:currency-symbol currency-symbol}]]
(assoc props
:value-internal value-internal
:theme theme
:set-value-internal set-value-internal
:handle-on-swap handle-on-swap
:crypto? crypto?)]]
[divider-line/view {:container-style (style/divider theme)}]
[rn/view {:style style/data-container}
hint-component
[text/text
{:size :paragraph-2
:weight :medium
:style (style/converted-amount theme)}
converted-value]]]))
[data-info
(assoc props
:theme theme
:crypto? crypto?
:amount (or value value-internal))]]))
(def view (schema/instrument #'view-internal component-schema/?schema))
@@ -1,8 +1,6 @@
(ns status-im.common.controlled-input.utils
(:require
[clojure.string :as string]
[status-im.contexts.wallet.common.utils :as wallet-utils]
[utils.money :as money]))
[clojure.string :as string]))
(def init-state
{:value ""
@@ -16,7 +14,7 @@
(defn numeric-value
[state]
(money/bignumber (input-value state)))
(or (parse-double (input-value state)) 0))
(defn input-error
[state]
@@ -28,29 +26,23 @@
(defn upper-limit
[state]
(money/bignumber (:upper-limit state)))
(:upper-limit state))
(defn lower-limit
[state]
(money/bignumber (:lower-limit state)))
(:lower-limit state))
(defn upper-limit-exceeded?
[state]
(let [num-value (numeric-value state)]
(and
(upper-limit state)
(if (money/bignumber? num-value)
(money/greater-than (numeric-value state) (upper-limit state))
false))))
(and
(upper-limit state)
(> (numeric-value state) (upper-limit state))))
(defn- lower-limit-exceeded?
(defn lower-limit-exceeded?
[state]
(let [num-value (numeric-value state)]
(and
(lower-limit state)
(if (money/bignumber? num-value)
(money/less-than (numeric-value state) (lower-limit state))
false))))
(and
(lower-limit state)
(< (numeric-value state) (lower-limit state))))
(defn- recheck-errorness
[state]
@@ -83,11 +75,13 @@
(defn increase
[state]
(set-input-value state (str (money/add (numeric-value state) 1))))
(let [new-val (inc (numeric-value state))]
(set-input-value state (str new-val))))
(defn decrease
[state]
(set-input-value state (str (money/add (numeric-value state) -1))))
(let [new-val (dec (numeric-value state))]
(set-input-value state (str new-val))))
(def ^:private not-digits-or-dot-pattern
#"[^0-9+\.]")
@@ -136,29 +130,3 @@
(defn empty-value?
[state]
(string/blank? (:value state)))
(defn- fiat->crypto
[value conversion-rate]
(-> value
(money/fiat->crypto conversion-rate)
(wallet-utils/cut-crypto-decimals-to-fit-usd-cents conversion-rate)))
(defn- crypto->fiat
[value conversion-rate]
(-> value
(money/crypto->fiat conversion-rate)
(wallet-utils/cut-fiat-balance-to-two-decimals)))
(defn ->crypto
[state conversion-rate]
(-> state
(set-input-value (fiat->crypto (input-value state) conversion-rate))
(set-upper-limit (fiat->crypto (upper-limit state) conversion-rate))
(set-lower-limit (fiat->crypto (lower-limit state) conversion-rate))))
(defn ->fiat
[state conversion-rate]
(-> state
(set-input-value (crypto->fiat (input-value state) conversion-rate))
(set-upper-limit (crypto->fiat (upper-limit state) conversion-rate))
(set-lower-limit (crypto->fiat (lower-limit state) conversion-rate))))
@@ -4,7 +4,7 @@
{:margin-top 11
:margin-horizontal 20
:gap 21
:margin-bottom 15})
:margin-bottom 8})
(def item-text
{:margin-top 10
@@ -12,3 +12,9 @@
(def info-text
{:margin-top -5})
(def privacy-policy
{:margin-top 4
:margin-horizontal 20
:margin-bottom 20
:align-items :center})
@@ -1,6 +1,7 @@
(ns status-im.common.metrics-confirmation-modal.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
[status-im.common.metrics-confirmation-modal.style :as style]
@@ -52,14 +53,36 @@
(toggle-metrics false)
(hide-bottom-sheet))
(declare view)
(defn- on-privacy-policy-press
[]
[settings?]
(rf/dispatch
[:show-bottom-sheet
{:content (fn []
[quo.theme/provider :dark
[privacy/privacy-statement]])
:shell? true}]))
{:content (fn []
[quo.theme/provider :dark
[privacy/privacy-statement]])
:on-close (fn []
(rf/dispatch [:show-bottom-sheet
{:content (fn []
[quo.theme/provider :dark
[view {:settings? settings?}]])
:shell? true}]))
:shell? true}]))
(defn- privacy-policy-text
[settings?]
[rn/view {:style style/privacy-policy}
[quo/text
[quo/text
{:style {:color colors/white-opa-50}
:size :paragraph-2}
(i18n/label :t/more-details-in-privacy-policy-1)]
[quo/text
{:size :paragraph-2
:weight :bold
:on-press #(on-privacy-policy-press settings?)}
(i18n/label :t/more-details-in-privacy-policy-2)]]])
(defn view
[{:keys [settings?]}]
@@ -79,22 +102,18 @@
[quo/text
{:size :paragraph-2
:style style/info-text}
(i18n/label :t/usage-data-shared-from-all-profiles)
(i18n/label :t/more-details-in-privacy-policy-1)
[quo/text
{:size :paragraph-2
:weight :bold
:on-press on-privacy-policy-press}
(i18n/label :t/more-details-in-privacy-policy-2)]]
(i18n/label :t/usage-data-shared-from-all-profiles)]
[quo/text
{:size :paragraph-2
:style style/info-text}
(i18n/label :t/usage-data-shared-from-all-profiles)
(i18n/label :t/sharing-usage-data-can-be-turned-off)])]
[quo/bottom-actions
{:actions :two-actions
:blur? true
:button-one-label (i18n/label :t/share-usage-data)
:button-one-props {:on-press on-share-usage}
:button-two-label (i18n/label (if settings? :t/do-not-share :t/not-now))
:button-two-label (i18n/label :t/not-now)
:button-two-props {:type :grey
:on-press on-do-not-share}}]])
:on-press on-do-not-share}}]
[privacy-policy-text settings?]])
@@ -10,12 +10,13 @@
{:flex 1
:flex-direction :row
:flex-wrap :wrap
:align-self :center})
:align-self :flex-start})
(def terms-privacy-container
{:gap 8
{:flex-direction :row
:padding-horizontal 20
:padding-vertical 8})
:padding-vertical 8
:gap 8})
(def plain-text
{:color colors/white-opa-70})
@@ -11,68 +11,92 @@
[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)
from-v1-without-terms-accepted? (rf/sub [:profile/from-status-v1-without-terms-accepted?])]
[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
:flex-direction :row}
[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 {:flex 1}}
[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}
" & "]
[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-statement)]]]]
: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?]}
from-v1-without-terms-accepted?
(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 from-v1-without-terms-accepted?)
(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]]))
@@ -2,13 +2,9 @@
(:require
[quo.core :as quo]
[quo.foundations.resources :as resources]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.controlled-input.utils :as controlled-input]
[status-im.contexts.preview.quo.preview :as preview]
[status-im.contexts.wallet.common.utils :as utils]
[utils.money :as money]))
[status-im.contexts.preview.quo.preview :as preview]))
(def networks
[{:source (resources/get-network :arbitrum)}
@@ -16,75 +12,47 @@
{:source (resources/get-network :ethereum)}])
(def title "Max: 200 SNT")
(def conversion-rate 3450.28)
(def descriptor
[{:key :token-symbol
[{:key :token
:type :select
:options [{:key :eth}
{:key :snt}]}
{:key :currency
:type :select
:options [{:key "$"}
{:key "€"}]}
:options [{:key :usd}
{:key :eur}]}
{:key :error?
:type :boolean}
{:key :allow-selection?
:type :boolean}])
(defn view
[]
(let [state (reagent/atom {:token-symbol :eth
:currency "$"
:crypto? true
:error? false})]
(let [state (reagent/atom {:token :eth
:currency :usd
:conversion 0.02
:networks networks
:title title
:customization-color :blue
:show-keyboard? false
:allow-selection? true})
value (reagent/atom "")
set-value (fn [v]
(swap! value str v))
delete (fn [_]
(swap! value #(subs % 0 (dec (count %)))))]
(fn []
(let [{:keys [currency token-symbol crypto? error?]} @state
[input-state set-input-state] (rn/use-state controlled-input/init-state)
input-amount (controlled-input/input-value input-state)
swap-between-fiat-and-crypto (fn []
(if crypto?
(set-input-state #(controlled-input/->fiat
%
conversion-rate))
(set-input-state
#(controlled-input/->crypto
%
conversion-rate))))
converted-value (if crypto?
(utils/prettify-balance currency
(money/crypto->fiat
input-amount
conversion-rate))
(utils/prettify-crypto-balance
(or (clj->js token-symbol) "")
(money/fiat->crypto input-amount
conversion-rate)
conversion-rate))]
[preview/preview-container
{:state state
:descriptor descriptor
:full-screen? true
:component-container-style {:flex 1
:justify-content :space-between}}
[quo/token-input
{:token-symbol token-symbol
:currency-symbol (if crypto? token-symbol currency)
:error? error?
:value input-amount
:converted-value converted-value
:on-swap (fn []
(swap! state assoc :crypto? (not crypto?))
(swap-between-fiat-and-crypto))
:hint-component [quo/network-tags
{:networks networks
:title title
:status (when (:error? @state) :error)}]}]
[quo/numbered-keyboard
{:container-style {:padding-bottom (safe-area/get-top)}
:left-action :dot
:delete-key? true
:on-press (fn [c]
(set-input-state #(controlled-input/add-character % c)))
:on-delete (fn []
(set-input-state controlled-input/delete-last))}]]))))
[preview/preview-container
{:state state
:descriptor descriptor
:full-screen? true
:component-container-style {:flex 1
:justify-content :space-between}}
[quo/token-input (assoc @state :value @value)]
[quo/numbered-keyboard
{:container-style {:padding-bottom (safe-area/get-top)}
:left-action :dot
:delete-key? true
:on-press set-value
:on-delete delete}]])))
@@ -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}))))))
+28 -20
View File
@@ -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]}]]}))
+36 -58
View File
@@ -12,17 +12,14 @@
[full-name]
(first (string/split full-name #" ")))
(defn cut-fiat-balance-to-two-decimals
[balance]
(defn prettify-balance
[currency-symbol balance]
(let [valid-balance? (and balance
(or (number? balance) (.-toFixed balance)))]
(as-> balance $
(if valid-balance? $ 0)
(.toFixed $ 2))))
(defn prettify-balance
[currency-symbol balance]
(str currency-symbol (cut-fiat-balance-to-two-decimals balance)))
(.toFixed $ 2)
(str currency-symbol $))))
(defn get-derivation-path
[number-of-accounts]
@@ -50,8 +47,8 @@
nil))
(defn calc-max-crypto-decimals
[one-cent-value]
(let [str-representation (str one-cent-value)
[value]
(let [str-representation (str value)
decimal-part (second (clojure.string/split str-representation #"\."))
exponent (extract-exponent str-representation)
zeroes-count (count (take-while #(= \0 %) decimal-part))
@@ -61,60 +58,29 @@
(inc max-decimals)
max-decimals)))
(defn token-usd-price
[token]
(get-in token [:market-values-per-currency :usd :price]))
(defn one-cent-value
[token-price-in-usd]
(if (pos? token-price-in-usd)
(/ 0.01 token-price-in-usd)
0))
(defn analyze-token-amount-for-price
"For full details: https://github.com/status-im/status-mobile/issues/18225"
[token-price-in-usd token-units]
(if (or (nil? token-units)
(not (money/bignumber? token-units))
(money/equal-to token-units 0))
{:zero-value? true}
(let [cent-value (one-cent-value token-price-in-usd)]
{:usd-cent-value cent-value
:standardized-decimals-count (if (nil? token-price-in-usd)
missing-price-decimals
(calc-max-crypto-decimals cent-value))})))
(defn cut-crypto-decimals-to-fit-usd-cents
[token-units token-price-in-usd]
(let [{:keys [zero-value? usd-cent-value standardized-decimals-count]}
(analyze-token-amount-for-price token-price-in-usd token-units)]
(cond
zero-value? "0"
(< token-units usd-cent-value) "0"
:else (number/remove-trailing-zeroes
(.toFixed token-units standardized-decimals-count)))))
(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)))
(defn get-crypto-decimals-count
[{:keys [market-values-per-currency]}]
(let [price (get-in market-values-per-currency [:usd :price])
one-cent-value (if (pos? price) (/ 0.01 price) 0)]
(calc-max-crypto-decimals one-cent-value)))
(defn get-standard-crypto-format
"For full details: https://github.com/status-im/status-mobile/issues/18225"
[token token-units]
(let [token-price-in-usd (token-usd-price token)
{:keys [zero-value? usd-cent-value standardized-decimals-count]}
(analyze-token-amount-for-price token-price-in-usd token-units)]
(cond
zero-value?
"0"
[{:keys [market-values-per-currency]} token-units]
(cond (or (nil? token-units)
(money/equal-to token-units 0))
"0"
(< token-units usd-cent-value)
(str "<" (number/remove-trailing-zeroes (.toFixed usd-cent-value standardized-decimals-count)))
(nil? (-> market-values-per-currency :usd :price))
(number/remove-trailing-zeroes (.toFixed token-units missing-price-decimals))
:else
(number/remove-trailing-zeroes (.toFixed token-units standardized-decimals-count)))))
:else
(let [price (-> market-values-per-currency :usd :price)
one-cent-value (if (pos? price) (/ 0.01 price) 0)
decimals-count (calc-max-crypto-decimals one-cent-value)]
(if (< token-units one-cent-value)
(str "<" (number/remove-trailing-zeroes (.toFixed one-cent-value decimals-count)))
(number/remove-trailing-zeroes (.toFixed token-units decimals-count))))))
(defn get-market-value
[currency {:keys [market-values-per-currency]}]
@@ -320,6 +286,18 @@
(let [counter (count address)]
(str (subs address 0 6) "\u2026" (subs address (- counter 3) counter)))))
(defn make-limit-label-crypto
[amount currency]
(str amount
" "
(some-> currency
name
string/upper-case)))
(defn make-limit-label-fiat
[amount currency-symbol]
(str currency-symbol amount))
(defn get-account-name-error
[s existing-account-names]
(cond

Some files were not shown because too many files have changed in this diff Show More