Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30efa275c3 | ||
|
|
f708cdcf50 | ||
|
|
3af4384e00 | ||
|
|
a6b19c021f | ||
|
|
a258717e83 | ||
|
|
a8395e51a4 | ||
|
|
db501b5efd | ||
|
|
44732e9736 | ||
|
|
d12c05aab6 | ||
|
|
4134d18cbc | ||
|
|
8600c1d3a5 | ||
|
|
570c62e30e | ||
|
|
549efdb77c | ||
|
|
8807a63989 | ||
|
|
c0be0b7670 | ||
|
|
6e854428f2 | ||
|
|
c81dd8e3e3 | ||
|
|
24f4c4a07e | ||
|
|
98762c74f1 | ||
|
|
f3aeddb53a | ||
|
|
f5fcc9f45e | ||
|
|
9aa9dc1b4c | ||
|
|
61974dae4d | ||
|
|
8b3e639abd | ||
|
|
7c901fa045 | ||
|
|
8a12ad3510 | ||
|
|
c8044cd2f2 | ||
|
|
6872d1a857 | ||
|
|
98d4969ca5 | ||
|
|
5412092ca1 | ||
|
|
a8695116e2 | ||
|
|
76773a4165 | ||
|
|
32fc7b14e8 | ||
|
|
82a8f9f44d | ||
|
|
8df72d0c29 | ||
|
|
794cd57961 | ||
|
|
6bc29088ab |
@@ -35,3 +35,5 @@ LOCAL_PAIRING_ENABLED=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=1
|
||||
DELETE_MESSAGE_FOR_ME_UNDO_TIME_LIMIT=10000
|
||||
DELETE_MESSAGE_UNDO_TIME_LIMIT=10000
|
||||
|
||||
@@ -36,6 +36,12 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Fetch') {
|
||||
steps { script {
|
||||
@@ -52,7 +58,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -54,6 +54,12 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
steps { script {
|
||||
@@ -79,7 +85,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
@@ -51,7 +56,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -128,3 +128,19 @@ Status-mobile uses `shadow-cljs` for hot reloading changes and uses its own [rel
|
||||
|
||||
### Solution
|
||||
Open react native's [In-App Developer Menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) and press "Disable Fast Refresh" or "Disable Hot Reloading"
|
||||
|
||||
# App crashing after running `make run-ios`
|
||||
|
||||
### Cause
|
||||
It's possible that installing XCode from a `.xip` file might cause XCode to act funny
|
||||
Since it's not installed from the App Store, Or you might be missing a Rosetta installation.
|
||||
|
||||
[Reference/Similar issue](https://github.com/expo/expo-cli/issues/3197)
|
||||
|
||||
You might see something like this after running `make run-ios`:
|
||||
```
|
||||
Underlying error (domain=FBSOpenApplicationServiceErrorDomain, code=1):
|
||||
```
|
||||
### Solution
|
||||
Run `softwareupdate --install-rosetta --agree-to-license`
|
||||
to accept XCode's license and install Rosetta.
|
||||
|
||||
+4
-2
@@ -881,7 +881,9 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-blur (4.3.3):
|
||||
- React-Core
|
||||
- react-native-cameraroll (5.10.0):
|
||||
- react-native-cameraroll (7.5.2):
|
||||
- glog
|
||||
- RCT-Folly (= 2022.05.16.00)
|
||||
- React-Core
|
||||
- react-native-config (1.5.0):
|
||||
- react-native-config/App (= 1.5.0)
|
||||
@@ -1475,7 +1477,7 @@ SPEC CHECKSUMS:
|
||||
react-native-biometrics: 352e5a794bfffc46a0c86725ea7dc62deb085bdc
|
||||
react-native-blob-util: 600972b1782380a5a7d5db61a3817ea32349dae9
|
||||
react-native-blur: c6d0a1dc2b4b519f7afe3b14d8151998632b6d18
|
||||
react-native-cameraroll: 4701ae7c3dbcd3f5e9e150ca17f250a276154b35
|
||||
react-native-cameraroll: af8eec1e585d053ff485d98ec837f9a8a11b5745
|
||||
react-native-config: 5330c8258265c1e5fdb8c009d2cabd6badd96727
|
||||
react-native-hole-view: 6935448993bac79f2b5a4ad7e9741094cf810679
|
||||
react-native-image-resizer: 2f1577efa3bc762597681f530c8e8d05ce0ceeb3
|
||||
|
||||
+2
-3
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "1.19.3",
|
||||
"@react-native-camera-roll/camera-roll": "git+https://github.com/status-im/react-native-camera-roll.git#refs/tags/v5.1.1.1",
|
||||
"@react-native-camera-roll/camera-roll": "7.5.2",
|
||||
"@react-native-clipboard/clipboard": "1.13.2",
|
||||
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#refs/tags/v2.0.3-status-v6",
|
||||
"@react-native-community/blur": "git+https://github.com/status-im/react-native-blur.git#refs/tags/v4.3.3-status",
|
||||
@@ -48,7 +48,7 @@
|
||||
"react-native-keychain": "8.1.2",
|
||||
"react-native-linear-gradient": "^2.8.0",
|
||||
"react-native-lottie-splash-screen": "^1.0.1",
|
||||
"react-native-mail": "git+https://github.com/status-im/react-native-mail.git#refs/tags/v6.1.2-status",
|
||||
"react-native-mail": "6.1.1",
|
||||
"react-native-navigation": "7.38.3",
|
||||
"react-native-orientation-locker": "^1.5.0",
|
||||
"react-native-permissions": "3.8.0",
|
||||
@@ -94,7 +94,6 @@
|
||||
"prettier": "^2.8.8",
|
||||
"process": "0.11.10",
|
||||
"react-test-renderer": "18.1.0",
|
||||
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#refs/tags/v2.0.2-status",
|
||||
"shadow-cljs": "2.26.2"
|
||||
},
|
||||
"binary": {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
--- /tmp/tmp-status-mobile-3907e6b2e/tmp.re8kHerusA/CameraRoll.ts 2024-04-16 15:17:12.942432000 +0200
|
||||
+++ ./node_modules/@react-native-camera-roll/camera-roll/src/CameraRoll.ts 2024-04-16 15:17:42.455250986 +0200
|
||||
@@ -239,6 +239,19 @@
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Returns total iOS image count
|
||||
+ */
|
||||
+ static getPhotosCountiOS(): Promise<number> {
|
||||
+ return RNCCameraRoll.getPhotosCountiOS('');
|
||||
+ }
|
||||
+ /**
|
||||
+ * Returns favorites and their count iOS
|
||||
+ */
|
||||
+ static getFavoritesiOS(): Promise<Album> {
|
||||
+ return RNCCameraRoll.getFavoritesiOS('');
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
* Saves the photo or video to the camera roll or photo library, and returns the URI of the newly created asset.
|
||||
*
|
||||
* @deprecated `save(...)` is deprecated - use `saveAsset(...)` instead.
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /tmp/tmp-status-mobile-3907e6b2e/tmp.juxTO1BeCM/NativeCameraRollModule.ts 2024-04-16 15:21:28.379979000 +0200
|
||||
+++ ./node_modules/@react-native-camera-roll/camera-roll/src/NativeCameraRollModule.ts 2024-04-16 15:21:40.490391291 +0200
|
||||
@@ -81,6 +81,8 @@
|
||||
getPhotos(params: Object): Promise<PhotoIdentifiersPage>;
|
||||
getAlbums(params: Object): Promise<Album[]>;
|
||||
deletePhotos(photoUris: Array<string>): Promise<void>;
|
||||
+ getPhotosCountiOS(arg: string): Promise<number>;
|
||||
+ getFavoritesiOS(arg: string): Promise<Album>;
|
||||
getPhotoByInternalID(
|
||||
internalID: string,
|
||||
options: Object,
|
||||
@@ -0,0 +1,56 @@
|
||||
--- /tmp/tmp-status-mobile-3907e6b2e/tmp.O0mkyjqnsy/RNCCameraRoll.mm 2024-04-16 15:26:23.070258000 +0200
|
||||
+++ ./node_modules/@react-native-camera-roll/camera-roll/ios/RNCCameraRoll.mm 2024-04-16 15:26:32.664996066 +0200
|
||||
@@ -955,6 +955,53 @@
|
||||
return [albumTitles copy];
|
||||
}
|
||||
|
||||
+RCT_EXPORT_METHOD(getPhotosCountiOS:(NSString *)blank
|
||||
+ resolve:(RCTPromiseResolveBlock)resolve
|
||||
+ reject:(RCTPromiseRejectBlock)reject)
|
||||
+{
|
||||
+ __block NSInteger intTotalCount=0;
|
||||
+ PHFetchOptions *allPhotosOptions = [PHFetchOptions new];
|
||||
+ allPhotosOptions.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d ",PHAssetMediaTypeImage];
|
||||
+ PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithOptions:allPhotosOptions];
|
||||
+ intTotalCount+=allPhotosResult.count;
|
||||
+
|
||||
+ resolve(@(intTotalCount));
|
||||
+}
|
||||
+
|
||||
+RCT_EXPORT_METHOD(getFavoritesiOS:(NSString *)blank
|
||||
+ resolve:(RCTPromiseResolveBlock)resolve
|
||||
+ reject:(RCTPromiseRejectBlock)reject)
|
||||
+{
|
||||
+ __block NSInteger intTotalCount=0;
|
||||
+ PHFetchOptions *fetchOptions = [PHFetchOptions new];
|
||||
+ NSString *format = @"(favorite == true)";
|
||||
+ fetchOptions.predicate = [NSPredicate predicateWithFormat:format];
|
||||
+ PHFetchResult<PHAsset *> *const assetsFetchResult = [PHAsset fetchAssetsWithOptions:fetchOptions];
|
||||
+ PHAsset *imageAsset = [assetsFetchResult firstObject];
|
||||
+ NSMutableArray * result = [NSMutableArray new];
|
||||
+
|
||||
+ for (PHAsset* asset in assetsFetchResult) {
|
||||
+ NSArray *resources = [PHAssetResource assetResourcesForAsset:asset ];
|
||||
+ if ([resources count] < 1) continue;
|
||||
+ NSString *orgFilename = ((PHAssetResource*)resources[0]).originalFilename;
|
||||
+ NSString *uit = ((PHAssetResource*)resources[0]).uniformTypeIdentifier;
|
||||
+ NSString *mimeType = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(uit), kUTTagClassMIMEType));
|
||||
+ CFStringRef extension = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(uit), kUTTagClassFilenameExtension);
|
||||
+ [result addObject:@{
|
||||
+ @"width": @([asset pixelWidth]),
|
||||
+ @"height": @([asset pixelHeight]),
|
||||
+ @"filename": orgFilename ?: @"",
|
||||
+ @"mimeType": mimeType ?: @"",
|
||||
+ @"id": [asset localIdentifier],
|
||||
+ @"creationDate": [asset creationDate],
|
||||
+ @"uri": [NSString stringWithFormat:@"ph://%@", [asset localIdentifier]],
|
||||
+ @"duration": @([asset duration])
|
||||
+ }];
|
||||
+ }
|
||||
+ [result addObject:@{@"count": @(assetsFetchResult.count)}];
|
||||
+ resolve(result);
|
||||
+}
|
||||
+
|
||||
static void checkPhotoLibraryConfig()
|
||||
{
|
||||
#if RCT_DEV
|
||||
@@ -0,0 +1,15 @@
|
||||
--- /tmp/tmp-status-mobile-6e854428f/tmp.PSruc8WtHx/build.gradle 2024-04-17 11:08:46.857319000 +0200
|
||||
+++ ./node_modules/react-native-mail/android/build.gradle 2024-04-17 11:09:22.935436792 +0200
|
||||
@@ -1,7 +1,11 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
+def safeExtGet(prop, fallback) {
|
||||
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||
+}
|
||||
+
|
||||
android {
|
||||
- compileSdkVersion project.hasProperty('compileSdkVersion') ? project.compileSdkVersion : 23
|
||||
+ compileSdkVersion safeExtGet('compileSdkVersion', 30)
|
||||
buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : "23.0.1"
|
||||
|
||||
defaultConfig {
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 707 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[legacy.status-im.browser.core :as browser]
|
||||
[legacy.status-im.browser.webview-ref :as webview-ref]
|
||||
[legacy.status-im.qr-scanner.core :as qr-scanner]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.connectivity.view :as connectivity]
|
||||
@@ -105,9 +104,7 @@
|
||||
(if empty-tab
|
||||
[react/touchable-highlight
|
||||
{:accessibility-label :universal-qr-scanner
|
||||
:on-press #(re-frame/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:handler ::qr-scanner/on-scan-success}])}
|
||||
:on-press #(re-frame/dispatch [:open-modal :shell-qr-reader])}
|
||||
[icons/icon :main-icons/qr {:color colors/black}]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
(ns legacy.status-im.ui.screens.communities.invite
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.communities.core :as communities]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -49,18 +48,35 @@
|
||||
contacts-selected (reagent/atom #{})
|
||||
{:keys [invite?]} (rf/sub [:get-screen-params])]
|
||||
(fn []
|
||||
(let [contacts-data (rf/sub [:contacts/active])
|
||||
{:keys [permissions
|
||||
can-manage-users?]}
|
||||
(let [theme (quo.theme/use-theme)
|
||||
contacts-data (rf/sub [:contacts/active])
|
||||
{community-id :id
|
||||
:keys [permissions
|
||||
can-manage-users?]}
|
||||
(rf/sub [:communities/edited-community])
|
||||
selected @contacts-selected
|
||||
selected-contacts-count (count selected)
|
||||
contacts (map (fn [{:keys [public-key] :as contact}]
|
||||
(assoc contact :active (contains? selected public-key)))
|
||||
contacts-data)
|
||||
;; no-membership communities can only be shared
|
||||
can-invite? (and can-manage-users?
|
||||
invite?
|
||||
(not= (:access permissions) constants/community-no-membership-access))]
|
||||
(not= (:access permissions) constants/community-no-membership-access))
|
||||
on-press-share-community (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:communities/share-community-confirmation-pressed
|
||||
selected community-id])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:type :positive
|
||||
:theme theme
|
||||
:text (if (= 1 selected-contacts-count)
|
||||
(i18n/label :t/one-user-was-invited)
|
||||
(i18n/label
|
||||
:t/n-users-were-invited
|
||||
{:count selected-contacts-count}))}]))
|
||||
[community-id selected selected-contacts-count theme])]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title (i18n/label (if can-invite?
|
||||
@@ -81,11 +97,8 @@
|
||||
:center
|
||||
[quo/button
|
||||
{:disabled (and (string/blank? @user-pk)
|
||||
(zero? (count selected)))
|
||||
(zero? selected-contacts-count))
|
||||
:accessibility-label :share-community-link
|
||||
:type :secondary
|
||||
:on-press #(debounce/throttle-and-dispatch
|
||||
[::communities/share-community-confirmation-pressed @user-pk
|
||||
selected]
|
||||
3000)}
|
||||
:on-press on-press-share-community}
|
||||
(i18n/label (if can-invite? :t/invite :t/share))]}]]))))
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
:image - collection image
|
||||
:theme - keyword -> :light/:dark"
|
||||
[{:keys [image theme size] :or {size :size-24}}]
|
||||
[{:keys [image theme size on-load-end on-error] :or {size :size-24}}]
|
||||
[fast-image/fast-image
|
||||
{:accessibility-label :collection-avatar
|
||||
:source image
|
||||
:on-load-end on-load-end
|
||||
:on-error on-error
|
||||
:style (style/collection-avatar theme size)}])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
:theme :light/:dark
|
||||
only icon
|
||||
[button {:icon-only? true} :i/close-circle]"
|
||||
[{:keys [on-press on-long-press disabled? type background size icon-left icon-right icon-top
|
||||
customization-color accessibility-label icon-only? container-style inner-style
|
||||
pressed? on-press-in on-press-out allow-multiple-presses?]
|
||||
[{:keys [on-press on-long-press disabled? type background size icon-left icon-left-color icon-right
|
||||
icon-right-color icon-top icon-top-color customization-color accessibility-label icon-only?
|
||||
container-style inner-style pressed? on-press-in on-press-out allow-multiple-presses?]
|
||||
:or {type :primary
|
||||
size 40
|
||||
customization-color (if (= type :primary) :blue nil)}}
|
||||
@@ -94,7 +94,7 @@
|
||||
[quo.icons/icon icon-top
|
||||
{:container-style {:margin-bottom 2
|
||||
:opacity (when disabled? 0.3)}
|
||||
:color icon-color
|
||||
:color (or icon-top-color icon-color)
|
||||
:size icon-size}]])
|
||||
(when icon-left
|
||||
[rn/view
|
||||
@@ -103,7 +103,7 @@
|
||||
:icon-size icon-size
|
||||
:disabled? disabled?})}
|
||||
[quo.icons/icon icon-left
|
||||
{:color icon-color
|
||||
{:color (or icon-left-color icon-color)
|
||||
:size icon-size}]])
|
||||
[rn/view
|
||||
(cond
|
||||
@@ -130,5 +130,5 @@
|
||||
:icon-size icon-size
|
||||
:disabled? disabled?})}
|
||||
[quo.icons/icon icon-right
|
||||
{:color icon-color
|
||||
{:color (or icon-right-color icon-color)
|
||||
:size icon-size}]])]]]))
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
(ns quo.components.community.community-detail-token-gating.component-spec
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Community Detail Token Gating Component"
|
||||
(h/test "render with member permissions"
|
||||
(h/render
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 2
|
||||
:role-text "Member"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "ETH"
|
||||
:sufficient? true
|
||||
:collectible? false
|
||||
:amount 0.8
|
||||
:img-src nil}]
|
||||
[{:symbol "ETH"
|
||||
:sufficient? false
|
||||
:collectible? false
|
||||
:amount 1
|
||||
:img-src nil}
|
||||
{:symbol "STT"
|
||||
:sufficient? false
|
||||
:collectible? false
|
||||
:amount 10
|
||||
:img-src nil}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Member"}))
|
||||
(h/is-truthy (h/get-by-text "0.8 ETH"))
|
||||
(h/is-truthy (h/get-by-text "1 ETH"))
|
||||
(h/is-truthy (h/get-by-text "10 STT")))
|
||||
|
||||
(h/test "render with admin permissions"
|
||||
(h/render
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 1
|
||||
:role-text "Admin"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "ETH"
|
||||
:sufficient? true
|
||||
:collectible? false
|
||||
:amount 2
|
||||
:img-src nil}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Admin"}))
|
||||
(h/is-truthy (h/get-by-text "2 ETH")))
|
||||
|
||||
(h/test "render with token master permissions"
|
||||
(h/render-with-theme-provider
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 5
|
||||
:role-text "Token Master"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "TMANI "
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:img-src {:uri "mock-image"}}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Token Master"}))
|
||||
(h/is-truthy (h/get-by-text "TMANI")))
|
||||
|
||||
(h/test "render with token owner permissions"
|
||||
(h/render-with-theme-provider
|
||||
[quo/community-detail-token-gating
|
||||
{:permissions [{:role 6
|
||||
:role-text "Token Owner"
|
||||
:satisfied? true
|
||||
:tokens [[{:symbol "TOANI"
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:img-src {:uri "mock-image"}}]]}]}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/you-eligible-to-join-as {:role "Token Owner"}))
|
||||
(h/is-truthy (h/get-by-text "TOANI"))))
|
||||
@@ -0,0 +1,20 @@
|
||||
(ns quo.components.community.community-detail-token-gating.style)
|
||||
|
||||
(def container
|
||||
{:padding-horizontal 20
|
||||
:margin-vertical -4})
|
||||
|
||||
(defn token-row
|
||||
[first?]
|
||||
{:flex-direction :row
|
||||
:margin-top (if first? 8 4)
|
||||
:row-gap 10
|
||||
:column-gap 8
|
||||
:flex-wrap :wrap
|
||||
:margin-bottom 16})
|
||||
|
||||
(def divider
|
||||
{:padding-left 0
|
||||
:height 28
|
||||
:padding-top 0
|
||||
:align-items :flex-start})
|
||||
@@ -0,0 +1,74 @@
|
||||
(ns quo.components.community.community-detail-token-gating.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo.components.community.community-detail-token-gating.style :as style]
|
||||
[quo.components.dividers.divider-label.view :as divider-label]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.components.tags.collectible-tag.view :as collectible-tag]
|
||||
[quo.components.tags.token-tag.view :as token-tag]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn- token-view
|
||||
[{:keys [collectible? img-src amount sufficient?] :as token}]
|
||||
(let [token-symbol (:symbol token)]
|
||||
(if collectible?
|
||||
[collectible-tag/view
|
||||
{:collectible-name token-symbol
|
||||
:size :size-24
|
||||
:collectible-img-src img-src
|
||||
:options (when sufficient?
|
||||
:hold)}]
|
||||
[token-tag/view
|
||||
{:token-symbol token-symbol
|
||||
:size :size-24
|
||||
:token-value amount
|
||||
:token-img-src img-src
|
||||
:options (when sufficient? :hold)}])))
|
||||
|
||||
(defn- tokens-row
|
||||
[{:keys [tokens divider? first?]}]
|
||||
[:<>
|
||||
[rn/view
|
||||
{:style (style/token-row first?)}
|
||||
(map-indexed (fn [token-index token]
|
||||
^{:key (str "token-" token-index)}
|
||||
[token-view token])
|
||||
tokens)]
|
||||
(when-not divider?
|
||||
[divider-label/view
|
||||
{:container-style style/divider}
|
||||
[text/text
|
||||
{:size :label
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
(string/lower-case (i18n/label :t/or))]])])
|
||||
|
||||
(defn- role-view
|
||||
[{:keys [role tokens satisfied? role-text]}]
|
||||
(when (seq tokens)
|
||||
^{:key (str "role-" role)}
|
||||
[:<>
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:margin-top 4}}
|
||||
(if satisfied?
|
||||
(i18n/label :t/you-eligible-to-join-as {:role role-text})
|
||||
(i18n/label :t/you-not-eligible-to-join-as {:role role-text}))]
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style {:margin-bottom 8}}
|
||||
(i18n/label (if satisfied? :t/you-hodl :t/you-must-hold))]
|
||||
|
||||
(map-indexed (fn [index tokens-item]
|
||||
^{:key (str role "-tokens-" index)}
|
||||
[tokens-row
|
||||
{:tokens tokens-item
|
||||
:first? (zero? index)
|
||||
:divider? (= index (dec (count tokens)))}])
|
||||
tokens)]))
|
||||
|
||||
(defn view
|
||||
[{:keys [permissions]}]
|
||||
[rn/view {:style style/container}
|
||||
(map role-view permissions)])
|
||||
@@ -102,7 +102,7 @@
|
||||
:right 8})
|
||||
|
||||
(def token-tag-spacing
|
||||
{:margin-top 10
|
||||
{:padding-top 10
|
||||
:margin-right 8})
|
||||
|
||||
(defn token-row
|
||||
@@ -117,11 +117,12 @@
|
||||
(defn token-row-or-text
|
||||
[padding? theme]
|
||||
(merge
|
||||
{:margin-top 4
|
||||
:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40
|
||||
theme)}
|
||||
{:padding-top 4
|
||||
:margin-bottom -2
|
||||
:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40
|
||||
theme)}
|
||||
(when padding?
|
||||
{:padding-left 12})))
|
||||
|
||||
|
||||
@@ -7,8 +7,14 @@
|
||||
:align-items :center})
|
||||
|
||||
(def image
|
||||
{:width 80
|
||||
:height 80})
|
||||
{:width 72
|
||||
:height 72})
|
||||
|
||||
(def image-container
|
||||
{:width 80
|
||||
:height 80
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def text-container
|
||||
{:margin-top 12
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
[rn/view {:style (merge styles/container container-style)}
|
||||
(if placeholder?
|
||||
[rn/view {:style styles/image-placeholder}]
|
||||
[fast-image/fast-image
|
||||
{:style styles/image
|
||||
:source image}])
|
||||
[rn/view {:style styles/image-container}
|
||||
[fast-image/fast-image
|
||||
{:style styles/image
|
||||
:source image}]])
|
||||
[rn/view {:style styles/text-container}
|
||||
[text/text
|
||||
{:style (styles/title blur?)
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
(ns quo.components.profile.collectible-list-item.component-spec
|
||||
(:require
|
||||
[quo.components.profile.collectible-list-item.view :as collectible-list-item]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Profile/ collectible list item tests"
|
||||
(h/describe "type card"
|
||||
(h/test "Renders default and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-called on-press)))
|
||||
|
||||
(h/test "Renders loading and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :loading
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-not-called on-press)
|
||||
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
|
||||
|
||||
(h/test "Renders counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500")))
|
||||
|
||||
(h/test "Renders counter and collectible name"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:collectible-name "Doodle #6822"
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500"))
|
||||
(h/is-truthy (h/get-by-text "Doodle #6822")))
|
||||
|
||||
(h/test "Renders status cant-fetch"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :cant-fetch}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
|
||||
|
||||
(h/test "Renders status unsupported"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :unsupported}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
|
||||
|
||||
(h/test "Renders status unsupported and counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :unsupported
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500"))
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file))))
|
||||
|
||||
(h/describe "type image"
|
||||
(h/test "Renders default and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-called on-press)))
|
||||
|
||||
(h/test "Renders loading and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :loading
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-not-called on-press)
|
||||
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
|
||||
|
||||
(h/test "Renders counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500")))
|
||||
|
||||
(h/test "Renders status cant-fetch"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :cant-fetch}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
|
||||
|
||||
(h/test "Renders status unsupported"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :unsupported}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
|
||||
|
||||
(h/test "Renders status unsupported and counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :unsupported
|
||||
:counter "x500"}])
|
||||
(h/get-by-text "x500")
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
|
||||
@@ -28,9 +28,6 @@
|
||||
:bottom 12
|
||||
:left 12})
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
|
||||
(defn card-view-container
|
||||
[theme]
|
||||
(merge
|
||||
@@ -85,6 +82,17 @@
|
||||
|
||||
(defn loading-image
|
||||
[theme]
|
||||
{:flex 1
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:border-radius container-border-radius
|
||||
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)})
|
||||
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)
|
||||
:z-index 2})
|
||||
|
||||
(defn avatar-container
|
||||
[loaded?]
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:opacity (when-not loaded? 0)})
|
||||
|
||||
@@ -41,17 +41,9 @@
|
||||
:color-index gradient-color-index}])
|
||||
|
||||
(defn- card-details
|
||||
[{:keys [status community? avatar-image-src collectible-name theme]}]
|
||||
[{:keys [community? avatar-image-src collectible-name theme state set-state]}]
|
||||
[rn/view {:style style/card-details-container}
|
||||
|
||||
(cond (= :cant-fetch status)
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
|
||||
(i18n/label :t/unknown)]
|
||||
|
||||
(= :loading status)
|
||||
(cond (not (:avatar-loaded? state))
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[loading-square theme]
|
||||
[loading-message theme]]
|
||||
@@ -67,92 +59,98 @@
|
||||
{:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style style/card-detail-text}
|
||||
collectible-name]]
|
||||
collectible-name]])
|
||||
|
||||
:else
|
||||
[:<>
|
||||
[collection-avatar/view
|
||||
{:size :size-20
|
||||
:image avatar-image-src}]
|
||||
[rn/view {:style {:width 8}}]
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style style/card-detail-text}
|
||||
collectible-name]])])
|
||||
[rn/view
|
||||
{:style (style/avatar-container (:avatar-loaded? state))}
|
||||
[:<>
|
||||
[collection-avatar/view
|
||||
{:size :size-20
|
||||
:on-load-end #(set-state (fn [prev-state] (assoc prev-state :avatar-loaded? true)))
|
||||
:image avatar-image-src}]
|
||||
[rn/view {:style {:width 8}}]]
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style style/card-detail-text}
|
||||
collectible-name]]])
|
||||
|
||||
(defn- card-view
|
||||
[{:keys [avatar-image-src collectible-name community? counter
|
||||
gradient-color-index image-src status]}]
|
||||
[{:keys [avatar-image-src collectible-name community? counter state set-state
|
||||
gradient-color-index image-src supported-file?]}]
|
||||
(let [theme (quo.theme/use-theme-value)]
|
||||
[rn/view {:style (style/card-view-container theme)}
|
||||
[rn/view {:style {:aspect-ratio 1}}
|
||||
(cond
|
||||
(= :loading status)
|
||||
[loading-image
|
||||
{:theme theme
|
||||
:gradient-color-index gradient-color-index}]
|
||||
|
||||
(= status :unsupported)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:label (i18n/label :t/unsupported-file)}]
|
||||
|
||||
(= status :cant-fetch)
|
||||
(:image-error? state)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:label (i18n/label :t/cant-fetch-info)}]
|
||||
|
||||
:else
|
||||
(not supported-file?)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:label (i18n/label :t/unsupported-file)}]
|
||||
|
||||
(not (:image-loaded? state))
|
||||
[loading-image
|
||||
{:theme theme
|
||||
:gradient-color-index gradient-color-index}])
|
||||
(when supported-file?
|
||||
[rn/view {:style {:aspect-ratio 1}}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:source image-src}]])]
|
||||
(when (and (not= status :loading) (not= status :cant-fetch) counter)
|
||||
{:style style/image
|
||||
:on-load-end #(set-state (fn [prev-state] (assoc prev-state :image-loaded? true)))
|
||||
:on-error #(set-state (fn [prev-state] (assoc prev-state :image-error? true)))
|
||||
:source image-src}]])]
|
||||
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
|
||||
[collectible-counter/view
|
||||
{:container-style style/collectible-counter
|
||||
:size :size-24
|
||||
:value counter}])
|
||||
[card-details
|
||||
{:status status
|
||||
{:state state
|
||||
:set-state set-state
|
||||
:community? community?
|
||||
:avatar-image-src avatar-image-src
|
||||
:collectible-name collectible-name
|
||||
:theme theme}]]))
|
||||
|
||||
(defn- image-view
|
||||
[{:keys [avatar-image-src community? counter
|
||||
gradient-color-index image-src status]}]
|
||||
[{:keys [avatar-image-src community? counter state set-state
|
||||
gradient-color-index image-src supported-file?]}]
|
||||
(let [theme (quo.theme/use-theme-value)]
|
||||
[rn/view {:style style/image-view-container}
|
||||
(cond
|
||||
(= :loading status)
|
||||
[loading-image
|
||||
{:theme theme
|
||||
:gradient-color-index gradient-color-index}]
|
||||
|
||||
(= status :unsupported)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:label (i18n/label :t/unsupported-file)}]
|
||||
|
||||
(= status :cant-fetch)
|
||||
(:image-error? state)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:label (i18n/label :t/cant-fetch-info)}]
|
||||
|
||||
:else [rn/view {:style {:aspect-ratio 1}}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:source image-src}]])
|
||||
(when (and (not= status :loading) (not= status :cant-fetch) counter)
|
||||
(not supported-file?)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:label (i18n/label :t/unsupported-file)}]
|
||||
|
||||
(not (:image-loaded? state))
|
||||
[loading-image
|
||||
{:theme theme
|
||||
:gradient-color-index gradient-color-index}])
|
||||
(when supported-file?
|
||||
[rn/view {:style {:aspect-ratio 1}}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:on-load-end #(set-state (fn [prev-state] (assoc prev-state :image-loaded? true)))
|
||||
:on-error #(set-state (fn [prev-state] (assoc prev-state :image-error? true)))
|
||||
:source image-src}]])
|
||||
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
|
||||
[collectible-counter/view
|
||||
{:container-style style/collectible-counter
|
||||
:size :size-24
|
||||
:value counter}])
|
||||
(when (and (not= status :loading) (not= status :cant-fetch) community?)
|
||||
(when (and (:image-loaded? state) (not (:image-error? state)) community?)
|
||||
[preview-list/view
|
||||
{:container-style style/avatar
|
||||
:type :communities
|
||||
@@ -160,15 +158,28 @@
|
||||
[avatar-image-src]])]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [container-style type on-press status]
|
||||
[{:keys [container-style type on-press on-long-press supported-file?]
|
||||
:as props}]
|
||||
[rn/pressable
|
||||
{:on-press (when-not (= status :loading) on-press)
|
||||
:accessibility-label :collectible-list-item
|
||||
:style (merge container-style style/container)}
|
||||
(if (= type :card)
|
||||
[card-view props]
|
||||
[image-view props])])
|
||||
(let [[state set-state] (rn/use-state {:image-loaded? false
|
||||
:image-error? false
|
||||
:avatar-loaded? false})
|
||||
collectible-ready? (or (:image-loaded? state) (not supported-file?))]
|
||||
[rn/pressable
|
||||
{:on-press (when collectible-ready? on-press)
|
||||
:on-long-press (when collectible-ready? on-long-press)
|
||||
:accessibility-label :collectible-list-item
|
||||
:style container-style}
|
||||
(if (= type :card)
|
||||
[card-view
|
||||
(assoc props
|
||||
:state state
|
||||
:set-state set-state
|
||||
:supported-file? supported-file?)]
|
||||
[image-view
|
||||
(assoc props
|
||||
:state state
|
||||
:set-state set-state
|
||||
:supported-file? supported-file?)])]))
|
||||
|
||||
(def ?schema
|
||||
[:=>
|
||||
@@ -177,14 +188,17 @@
|
||||
[:map {:closed true}
|
||||
[:avatar-image-src {:optional true} [:maybe :schema.common/image-source]]
|
||||
[:collectible-name {:optional true} [:maybe string?]]
|
||||
[:supported-file? {:optional true} [:maybe boolean?]]
|
||||
[:native-ID {:optional true} [:maybe [:or string? keyword?]]]
|
||||
[:community? {:optional true} [:maybe boolean?]]
|
||||
[:counter {:optional true} [:maybe string?]]
|
||||
[:counter {:optional true} [:maybe [:or :string :int]]]
|
||||
[:gradient-color-index {:optional true}
|
||||
[:maybe [:enum :gradient-1 :gradient-2 :gradient-3 :gradient-4 :gradient-5]]]
|
||||
[:image-src {:optional true} [:maybe :schema.common/image-source]]
|
||||
[:on-press {:optional true} [:maybe fn?]]
|
||||
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
|
||||
[:type [:enum :card :image]]]]]
|
||||
[:on-long-press {:optional true} [:maybe fn?]]
|
||||
[:type [:enum :card :image]]
|
||||
[:container-style {:optional true} [:maybe :map]]]]]
|
||||
:any])
|
||||
|
||||
(def view (schema/instrument #'view-internal ?schema))
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
(ns quo.components.profile.expanded-collectible.component-spec
|
||||
(:require
|
||||
[quo.components.profile.expanded-collectible.view :as expanded-collectible]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Profile/ expanded collectible "
|
||||
(h/test "renders with counter and has on-press event"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[expanded-collectible/view
|
||||
{:image-src
|
||||
"https://media.istockphoto.com/id/603164912/photo/suburb-asphalt-road-and-sun-flowers.jpg?s=612x612&w=0&k=20&c=qLoQ5QONJduHrQ0kJF3fvoofmGAFcrq6cL84HbzdLQM="
|
||||
:counter "1200"
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :expanded-collectible))
|
||||
(h/was-called on-press)
|
||||
(h/is-truthy (h/get-by-text "1200"))))
|
||||
|
||||
(h/test "renders with status :cant-fetch and has on-press event"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[expanded-collectible/view
|
||||
{:counter "1200"
|
||||
:status :cant-fetch
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :expanded-collectible))
|
||||
(h/was-called on-press)
|
||||
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info))))
|
||||
|
||||
|
||||
(h/test "renders with status :unsupported and has on-press event"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[expanded-collectible/view
|
||||
{:counter "1200"
|
||||
:status :unsupported
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :expanded-collectible))
|
||||
(h/was-called on-press)
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
|
||||
@@ -32,9 +32,10 @@
|
||||
label]])
|
||||
|
||||
(defn view-internal
|
||||
[{:keys [container-style square? status on-press counter image-src] :or {status :default}}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[image-size set-image-size] (rn/use-state {})]
|
||||
[{:keys [container-style square? on-press counter image-src native-ID supported-file?]}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[image-size set-image-size] (rn/use-state {})
|
||||
[image-error? set-image-error] (rn/use-state false)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(promesa/let [[image-width image-height] (rn/image-get-size image-src)]
|
||||
@@ -43,22 +44,29 @@
|
||||
:aspect-ratio (/ image-width image-height)})))
|
||||
[image-src])
|
||||
[rn/pressable
|
||||
{:on-press on-press
|
||||
{:on-press (when (and (not image-error?) supported-file?) on-press)
|
||||
:accessibility-label :expanded-collectible
|
||||
:style (merge container-style style/container)}
|
||||
(case status
|
||||
:unsupported [fallback-view
|
||||
{:label (i18n/label :t/unsupported-file)
|
||||
:counter counter
|
||||
:theme theme}]
|
||||
:cant-fetch [fallback-view
|
||||
{:label (i18n/label :t/cant-fetch-info)
|
||||
:counter counter
|
||||
:theme theme}]
|
||||
(cond
|
||||
(not supported-file?)
|
||||
[fallback-view
|
||||
{:label (i18n/label :t/unsupported-file)
|
||||
:counter counter
|
||||
:theme theme}]
|
||||
|
||||
image-error?
|
||||
[fallback-view
|
||||
{:label (i18n/label :t/cant-fetch-info)
|
||||
:counter counter
|
||||
:theme theme}]
|
||||
|
||||
(and (not image-error?) supported-file?)
|
||||
[rn/view
|
||||
[rn/image
|
||||
{:style (style/image square? (:aspect-ratio image-size))
|
||||
:source image-src}]
|
||||
{:style (style/image square? (:aspect-ratio image-size))
|
||||
:source image-src
|
||||
:native-ID native-ID
|
||||
:on-error #(set-image-error true)}]
|
||||
[counter-view counter]])]))
|
||||
|
||||
(def ?schema
|
||||
@@ -67,10 +75,11 @@
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:image-src {:optional true} [:maybe string?]]
|
||||
[:supported-file? {:optional true} [:maybe boolean?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:native-ID {:optional true} [:maybe [:or string? keyword?]]]
|
||||
[:square? {:optional true} [:maybe boolean?]]
|
||||
[:counter {:optional true} [:maybe string?]]
|
||||
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
|
||||
[:on-press {:optional true} [:maybe fn?]]]]]
|
||||
:any])
|
||||
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
[:blur? {:optional true} [:maybe :boolean]]
|
||||
[:collectible-img-src :schema.common/image-source]
|
||||
[:collectible-name :string]
|
||||
[:collectible-id :string]]]]
|
||||
[:collectible-id {:optional true} [:maybe :string]]]]]
|
||||
:any])
|
||||
|
||||
@@ -41,12 +41,13 @@
|
||||
:weight :medium
|
||||
:style (style/label theme)}
|
||||
collectible-name]
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:margin-left 5
|
||||
:style (style/label theme)}
|
||||
collectible-id]]]
|
||||
(when collectible-id
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:margin-left 5
|
||||
:style (style/label theme)}
|
||||
collectible-id])]]
|
||||
(when options
|
||||
[rn/view {:style (style/options-icon size)}
|
||||
[icons/icon (if (= options :hold) :i/hold :i/add-token)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
(ns quo.components.wallet.network-link.helpers)
|
||||
|
||||
(def ^:private central-figure-width 63)
|
||||
|
||||
(defn calculate-side-lines-path-1x
|
||||
"Calculates the `d` attribute for the side lines based on the SVG width."
|
||||
[width]
|
||||
(let [side-offset (/ (- width central-figure-width) 2)]
|
||||
{:left (str "M0 57 L" side-offset " 57")
|
||||
:right (str "M" (+ side-offset central-figure-width) " 1 L" width " 1")}))
|
||||
|
||||
(defn calculate-transform
|
||||
"Calculates the transform attribute for the central figure based on the SVG width."
|
||||
[width]
|
||||
(let [translate-x (/ (- width central-figure-width) 2)]
|
||||
(str "translate(" translate-x " 0)")))
|
||||
|
||||
(defn calculate-side-lines-path-2x
|
||||
"Calculates the `d` attribute for the side lines based on the SVG width."
|
||||
[width]
|
||||
(let [side-offset (/ (- width central-figure-width) 2)]
|
||||
{:left (str "M0 113 L" side-offset " 113")
|
||||
:right (str "M" (+ side-offset central-figure-width) " 1 L" width " 1")}))
|
||||
@@ -0,0 +1,34 @@
|
||||
(ns quo.components.wallet.network-link.style)
|
||||
|
||||
(def left-circle-container
|
||||
{:position :absolute
|
||||
:left -3})
|
||||
|
||||
(def right-circle-container
|
||||
{:position :absolute
|
||||
:right -3})
|
||||
|
||||
(def bottom-left-circle-container
|
||||
{:position :absolute
|
||||
:bottom -3
|
||||
:left -3})
|
||||
|
||||
(def top-right-circle-container
|
||||
{:position :absolute
|
||||
:top -3
|
||||
:right -3})
|
||||
|
||||
(def link-linear-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:height 10})
|
||||
|
||||
(def link-1x-container
|
||||
{:flex 1
|
||||
:height 58
|
||||
:justify-content :center})
|
||||
|
||||
(def link-2x-container
|
||||
{:flex 1
|
||||
:height 114
|
||||
:justify-content :center})
|
||||
@@ -1,82 +1,151 @@
|
||||
(ns quo.components.wallet.network-link.view
|
||||
(:require
|
||||
[oops.core :refer [oget]]
|
||||
[quo.components.wallet.network-link.helpers :as helpers]
|
||||
[quo.components.wallet.network-link.schema :as component-schema]
|
||||
[quo.components.wallet.network-link.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.svg :as svg]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- circle
|
||||
[fill stroke]
|
||||
[svg/svg
|
||||
{:height "8"
|
||||
:width "8"}
|
||||
[svg/circle
|
||||
{:cx "4"
|
||||
:cy "4"
|
||||
:r "3.5"
|
||||
:fill fill
|
||||
:stroke stroke
|
||||
:strokeWidth "1"}]])
|
||||
|
||||
(defn- line
|
||||
[stroke width]
|
||||
[svg/svg
|
||||
{:height "10"
|
||||
:width "100%"
|
||||
:view-box (str "0 0 " width " 10")}
|
||||
[svg/path
|
||||
{:d (str "M0,5 L" width ",5")
|
||||
:stroke stroke
|
||||
:stroke-width "1"}]])
|
||||
|
||||
(defn link-linear
|
||||
[{:keys [source theme]}]
|
||||
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "10" :fill :none}
|
||||
[svg/path {:stroke (colors/resolve-color source theme) :d "M68 5H5"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]])
|
||||
(let [[container-width
|
||||
set-container-width] (rn/use-state 100)
|
||||
stroke-color (colors/resolve-color source theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
on-layout (rn/use-callback #(set-container-width
|
||||
(oget % :nativeEvent :layout :width)))]
|
||||
[rn/view
|
||||
{:style style/link-linear-container
|
||||
:on-layout on-layout}
|
||||
[line stroke-color container-width]
|
||||
[rn/view {:style style/left-circle-container}
|
||||
[circle fill-color stroke-color]]
|
||||
[rn/view {:style style/right-circle-container}
|
||||
[circle fill-color stroke-color]]]))
|
||||
|
||||
(defn link-1x
|
||||
[{:keys [source destination theme]}]
|
||||
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "66" :fill :none}
|
||||
[svg/path
|
||||
{:stroke "url(#gradient)" :d "M68 5h-9.364c-11.046 0-20 8.954-20 20v16c0 11.046-8.955 20-20 20H5"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color destination theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "61"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient" :x1 "72.271" :x2 "82.385" :y1 "5" :y2 "34.155" :gradientUnits "userSpaceOnUse"}
|
||||
[svg/stop {:stopColor (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stopColor (colors/resolve-color source theme)}]]]])
|
||||
(let [[container-width
|
||||
set-container-width] (rn/use-state 100)
|
||||
stroke-color "url(#gradient)"
|
||||
source-color (colors/resolve-color source theme)
|
||||
destination-color (colors/resolve-color destination theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
view-box (str "0 0 " container-width " 58")
|
||||
side-lines-path (helpers/calculate-side-lines-path-1x container-width)
|
||||
central-transform (helpers/calculate-transform container-width)
|
||||
on-layout (rn/use-callback #(set-container-width
|
||||
(oget % :nativeEvent :layout :width)))]
|
||||
[rn/view
|
||||
{:style style/link-1x-container
|
||||
:on-layout on-layout}
|
||||
[svg/svg
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:height "100%"
|
||||
:width "100%"
|
||||
:view-box view-box
|
||||
:fill :none}
|
||||
[svg/path
|
||||
{:d (:left side-lines-path)
|
||||
:stroke source-color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M63 1L53.6356 1C42.5899 1 33.6356 9.9543 33.6356 21L33.6356 37C33.6356 48.0457 24.6813 57 13.6356 57L2.85889e-05 57"
|
||||
:transform central-transform
|
||||
:stroke stroke-color}]
|
||||
[svg/path
|
||||
{:d (:right side-lines-path)
|
||||
:stroke destination-color}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.271"
|
||||
:x2 "82.385"
|
||||
:y1 "5"
|
||||
:y2 "34.155"
|
||||
:gradient-units "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]]
|
||||
[rn/view {:style style/bottom-left-circle-container}
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/top-right-circle-container}
|
||||
[circle fill-color destination-color]]]))
|
||||
|
||||
(defn link-2x
|
||||
[{:keys [source destination theme]}]
|
||||
[svg/svg
|
||||
{:width "73" :height "122" :viewBox "0 0 73 122" :fill "none" :xmlns "http://www.w3.org/2000/svg"}
|
||||
[svg/path
|
||||
{:d
|
||||
"M67.9999 5L58.6356 5C47.5899 5 38.6356 13.9543 38.6356 25L38.6356 97C38.6356 108.046 29.6813 117 18.6356 117L5.00006 117"
|
||||
:stroke "url(#gradient)"}]
|
||||
[svg/circle
|
||||
{:cx "68"
|
||||
:cy "5"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color destination theme)}]
|
||||
[svg/circle
|
||||
{:cx "5"
|
||||
:cy "117"
|
||||
:r "4"
|
||||
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
:stroke (colors/resolve-color source theme)}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.2711"
|
||||
:y1 "5.00001"
|
||||
:x2 "102.867"
|
||||
:y2 "49.0993"
|
||||
:gradientUnits "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]])
|
||||
(let [[container-width
|
||||
set-container-width] (rn/use-state 100)
|
||||
stroke-color "url(#gradient)"
|
||||
source-color (colors/resolve-color source theme)
|
||||
destination-color (colors/resolve-color destination theme)
|
||||
fill-color (colors/theme-colors colors/white colors/neutral-90 theme)
|
||||
view-box (str "0 0 " container-width " 114")
|
||||
side-lines-path (helpers/calculate-side-lines-path-2x container-width)
|
||||
central-transform (helpers/calculate-transform container-width)
|
||||
on-layout (rn/use-callback #(set-container-width
|
||||
(oget % :nativeEvent :layout :width)))]
|
||||
[rn/view
|
||||
{:style style/link-2x-container
|
||||
:on-layout on-layout}
|
||||
[svg/svg
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:height "100%"
|
||||
:width "100%"
|
||||
:view-box view-box
|
||||
:fill :none}
|
||||
[svg/path
|
||||
{:d (:left side-lines-path)
|
||||
:stroke source-color}]
|
||||
[svg/path
|
||||
{:d
|
||||
"M62.9999 1L53.6356 1C42.5899 1 33.6356 9.9543 33.6356 21L33.6356 93C33.6356 104.046 24.6813 113 13.6356 113L5.71778e-05 113"
|
||||
:transform central-transform
|
||||
:stroke stroke-color}]
|
||||
[svg/path
|
||||
{:d (:right side-lines-path)
|
||||
:stroke destination-color}]
|
||||
[svg/defs
|
||||
[svg/linear-gradient
|
||||
{:id "gradient"
|
||||
:x1 "72.2711"
|
||||
:y1 "5.00001"
|
||||
:x2 "102.867"
|
||||
:y2 "49.0993"
|
||||
:gradient-units "userSpaceOnUse"}
|
||||
[svg/stop {:stop-color (colors/resolve-color destination theme)}]
|
||||
[svg/stop {:offset "1" :stop-color (colors/resolve-color source theme)}]]]]
|
||||
[rn/view {:style style/bottom-left-circle-container}
|
||||
[circle fill-color source-color]]
|
||||
[rn/view {:style style/top-right-circle-container}
|
||||
[circle fill-color destination-color]]]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [shape container-style] :as props}]
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
quo.components.community.channel-action.view
|
||||
quo.components.community.channel-actions.view
|
||||
quo.components.community.community-card-view
|
||||
quo.components.community.community-detail-token-gating.view
|
||||
quo.components.community.community-list-view
|
||||
quo.components.community.community-stat.view
|
||||
quo.components.community.community-view
|
||||
@@ -224,6 +225,7 @@
|
||||
|
||||
;;;; Community
|
||||
(def community-card-view-item quo.components.community.community-card-view/view)
|
||||
(def community-detail-token-gating quo.components.community.community-detail-token-gating.view/view)
|
||||
(def communities-membership-list-item
|
||||
quo.components.community.community-list-view/communities-membership-list-item)
|
||||
(def community-stats-column quo.components.community.community-view/community-stats-column)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
quo.components.calendar.calendar.component-spec
|
||||
quo.components.calendar.calendar.month-picker.component-spec
|
||||
quo.components.colors.color-picker.component-spec
|
||||
quo.components.community.community-detail-token-gating.component-spec
|
||||
quo.components.community.community-stat.component-spec
|
||||
quo.components.counter.collectible-counter.component-spec
|
||||
quo.components.counter.counter.component-spec
|
||||
@@ -64,8 +65,6 @@
|
||||
quo.components.numbered-keyboard.keyboard-key.component-spec
|
||||
quo.components.onboarding.small-option-card.component-spec
|
||||
quo.components.password.tips.component-spec
|
||||
quo.components.profile.collectible-list-item.component-spec
|
||||
quo.components.profile.expanded-collectible.component-spec
|
||||
quo.components.profile.link-card.component-spec
|
||||
quo.components.profile.select-profile.component-spec
|
||||
quo.components.profile.showcase-nav.component-spec
|
||||
|
||||
@@ -226,7 +226,3 @@
|
||||
(defn open-url [link] (.openURL ^js linking link))
|
||||
|
||||
(def set-status-bar-style react-native/StatusBar.setBarStyle)
|
||||
|
||||
(defn sharing
|
||||
[content]
|
||||
(.share (.-Share ^js react-native) (clj->js content)))
|
||||
|
||||
@@ -4,9 +4,5 @@
|
||||
|
||||
(defn open
|
||||
([options]
|
||||
(open options #() #()))
|
||||
([options on-success on-error]
|
||||
(-> ^js react-native-share
|
||||
(.open (clj->js options))
|
||||
(.then on-success)
|
||||
(.catch on-error))))
|
||||
(.open (clj->js options)))))
|
||||
|
||||
@@ -40,13 +40,15 @@
|
||||
params: sequence - A positional sequence of zero or more arguments.
|
||||
|
||||
on-success/on-error: function/vector (optional) - When a function, it will be
|
||||
called with the transformed response as the sole argument. When a vector, it
|
||||
is expected to be a valid re-frame event vector, and the event will be
|
||||
dispatched with the transformed response conj'ed at the end.
|
||||
called with the transformed response and id (request-id) as the argument.
|
||||
When a vector, it is expected to be a valid re-frame event vector, and the event
|
||||
will be dispatched with the transformed response and id conj'ed at the end.
|
||||
|
||||
js-response: boolean - When non-nil, the successful response will not be
|
||||
recursively converted to Clojure data structures. Default: nil.
|
||||
|
||||
id: (optional) - id passed while making the RPC call will be returned in response
|
||||
|
||||
number-of-retries: integer - The maximum number of retries in case of failure.
|
||||
Default: nil.
|
||||
|
||||
@@ -56,14 +58,14 @@
|
||||
Note that on-error is optional, but if not provided, a default implementation
|
||||
will be used.
|
||||
"
|
||||
[{:keys [method params on-success on-error js-response] :as arg}]
|
||||
[{:keys [method params on-success on-error js-response id] :as arg}]
|
||||
(let [params (or params [])
|
||||
on-error (or on-error
|
||||
(on-error-retry call arg)
|
||||
#(log/warn :json-rpc/error method :error % :params params))]
|
||||
(native-module/call-private-rpc
|
||||
(transforms/clj->json {:jsonrpc "2.0"
|
||||
:id 1
|
||||
:id (or id 1)
|
||||
:method method
|
||||
:params params})
|
||||
(fn [raw-response]
|
||||
@@ -79,12 +81,13 @@
|
||||
(rf/dispatch (conj on-error error))
|
||||
(on-error error)))
|
||||
(when on-success
|
||||
(let [result (if js-response
|
||||
(.-result response-js)
|
||||
(transforms/js->clj (.-result response-js)))]
|
||||
(let [result (if js-response
|
||||
(.-result response-js)
|
||||
(transforms/js->clj (.-result response-js)))
|
||||
request-id (.-id response-js)]
|
||||
(if (vector? on-success)
|
||||
(rf/dispatch (conj on-success result))
|
||||
(on-success result)))))))))))
|
||||
(rf/dispatch (conj on-success result request-id))
|
||||
(on-success result request-id)))))))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:json-rpc/call
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[react-native.cameraroll :as cameraroll]
|
||||
[react-native.fs :as fs]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def config
|
||||
@@ -15,10 +14,12 @@
|
||||
(blob/fetch uri
|
||||
config
|
||||
(fn [downloaded-url]
|
||||
(share/open {:url (str (when platform/android? "file://") downloaded-url)
|
||||
:isNewTask true}
|
||||
#(fs/unlink downloaded-url)
|
||||
#(fs/unlink downloaded-url))))))
|
||||
(rf/dispatch [:open-share
|
||||
{:options {:url (str (when platform/android? "file://")
|
||||
downloaded-url)
|
||||
:isNewTask true}
|
||||
:on-success #(fs/unlink downloaded-url)
|
||||
:on-error #(fs/unlink downloaded-url)}])))))
|
||||
|
||||
(rf/reg-fx :effects.lightbox/save-image-to-gallery
|
||||
(fn [[uri on-success]]
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
ens?
|
||||
(assoc-in [:route-params :ens-name] fragment)
|
||||
|
||||
(and (or (= handler :community) (= handler :community-chat)) compressed-key?)
|
||||
(and (= handler :community) compressed-key?)
|
||||
(assoc-in [:route-params :community-id] fragment)
|
||||
|
||||
(and equal-end-of-base64url (= handler :community) (:community-data route-params))
|
||||
@@ -119,6 +119,13 @@
|
||||
(re-find constants/regx-starts-with-uuid (:community-data route-params)))
|
||||
(assoc-in [:route-params :community-channel-id] (:community-data route-params))
|
||||
|
||||
(and fragment
|
||||
(= handler :community-chat)
|
||||
(:community-data route-params)
|
||||
(string? (:community-data route-params))
|
||||
(not (re-find constants/regx-starts-with-uuid (:community-data route-params))))
|
||||
(assoc-in [:route-params :community-encoded-data?] true)
|
||||
|
||||
(and equal-end-of-base64url (= handler :user) (:user-data route-params))
|
||||
(update-in [:route-params :user-data] #(str % equal-end-of-base64url))
|
||||
|
||||
@@ -203,6 +210,10 @@
|
||||
(cb {:type :private-chat
|
||||
:error :invalid-chat-id})))))
|
||||
|
||||
(defn parse-shared-url
|
||||
[uri]
|
||||
(re-frame/dispatch [:shared-urls/parse-shared-url uri]))
|
||||
|
||||
(defn match-community-channel-async
|
||||
[{:keys [community-channel-id community-id]} cb]
|
||||
(if (validators/valid-compressed-key? community-id)
|
||||
@@ -307,9 +318,10 @@
|
||||
(and (= handler :community-chat) (:community-channel-id route-params) (:community-id route-params))
|
||||
(match-community-channel-async route-params cb)
|
||||
|
||||
(and (= handler :community-chat) (:community-id route-params))
|
||||
(cb {:type :community
|
||||
:community-id (:community-id route-params)})
|
||||
(and (= handler :community-chat)
|
||||
(:community-encoded-data? route-params)
|
||||
(:community-id route-params))
|
||||
(parse-shared-url uri)
|
||||
|
||||
;; NOTE: removed in `match-uri`, might need this in the future
|
||||
(= handler :wallet-account)
|
||||
|
||||
@@ -42,12 +42,14 @@
|
||||
[:community-chat
|
||||
{:community-data
|
||||
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
|
||||
:community-encoded-data? true
|
||||
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
|
||||
|
||||
"status-app://cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"
|
||||
[:community-chat
|
||||
{:community-data
|
||||
"G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM="
|
||||
:community-encoded-data? true
|
||||
:community-id "zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11"}]
|
||||
|
||||
"https://status.app/cc/c432709e-fc73-440d-bb67-cb3a0929dfda#zQ3shZL6dXiFCbDyxnXxwQa9v8QFC2q19subFtyxd7kVszMVo"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
(ns status-im.common.shared-urls.data-store
|
||||
(:require
|
||||
[clojure.set :as set]))
|
||||
|
||||
(defn <-rpc
|
||||
[{:keys [community channel contact]}]
|
||||
{:community (set/rename-keys
|
||||
community
|
||||
{:communityId :community-id
|
||||
:displayName :display-name
|
||||
:membersCount :members-count
|
||||
:tagIndices :tag-indices})
|
||||
:channel (set/rename-keys
|
||||
channel
|
||||
{:displayName :display-name
|
||||
:channelUuid :channel-uuid})
|
||||
:contact (set/rename-keys
|
||||
contact
|
||||
{:displayName :display-name
|
||||
:publicKey :public-key})})
|
||||
@@ -0,0 +1,33 @@
|
||||
(ns status-im.common.shared-urls.events
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.shared-urls.data-store :as data-store]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn parse-shared-url-success
|
||||
[url response]
|
||||
(let [parsed-data (data-store/<-rpc response)
|
||||
cb #(rf/dispatch [:universal-links/match-value url %])]
|
||||
(cond
|
||||
(:channel parsed-data)
|
||||
(cb {:type :community-chat
|
||||
:chat-id (str (get-in parsed-data [:community :community-id])
|
||||
(get-in parsed-data [:channel :channel-uuid]))
|
||||
:community-id (get-in parsed-data [:community :community-id])})
|
||||
|
||||
(:community parsed-data)
|
||||
(cb {:type :community :community-id (get-in parsed-data [:community :community-id])}))))
|
||||
|
||||
(defn parse-shared-url
|
||||
[_ [uri]]
|
||||
(let [url (string/replace uri #"status-app:/" "https://status.app")]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_parseSharedURL"
|
||||
:params [url]
|
||||
:on-success #(parse-shared-url-success url %)
|
||||
:on-error (fn [err]
|
||||
(log/error "failed to parse shared url" {:error err :url url}))}]}))
|
||||
|
||||
(re-frame/reg-event-fx :shared-urls/parse-shared-url parse-shared-url)
|
||||
@@ -18,8 +18,8 @@
|
||||
[rn/view
|
||||
[quo/text
|
||||
{:accessibility-label :sync-code-generated
|
||||
:weight :bold
|
||||
:size :heading-1
|
||||
:weight :semi-bold
|
||||
:size :heading-2
|
||||
:style {:margin-bottom 4}}
|
||||
(i18n/label :t/enter-password)]
|
||||
[rn/view
|
||||
|
||||
@@ -116,14 +116,16 @@
|
||||
(log/debug "universal-links: no url")))
|
||||
|
||||
(rf/defn on-handle
|
||||
{:events [::match-value]}
|
||||
[cofx url {:keys [type chat-id] :as data}]
|
||||
{:events [:universal-links/match-value]}
|
||||
[cofx url {:keys [type chat-id community-id] :as data}]
|
||||
(case type
|
||||
:group-chat (handle-group-chat cofx data)
|
||||
:private-chat (handle-private-chat cofx data)
|
||||
:community-requests (handle-community-requests cofx data)
|
||||
:community (communities.events/navigate-to-serialized-community cofx data)
|
||||
:community-chat {:dispatch [:communities/navigate-to-community-chat chat-id :pop-to-root]}
|
||||
:community (communities.events/navigate-to-community-overview cofx [community-id])
|
||||
:community-chat (communities.events/navigate-to-community-chat cofx
|
||||
[chat-id :pop-to-root
|
||||
community-id])
|
||||
:contact (handle-view-profile cofx data)
|
||||
:browser (handle-browse cofx data)
|
||||
:eip681 (handle-eip681 cofx data)
|
||||
@@ -136,7 +138,7 @@
|
||||
{:router/handle-uri {:chain (chain/chain-keyword db)
|
||||
:chats (:chats db)
|
||||
:uri url
|
||||
:cb #(re-frame/dispatch [::match-value url %])}})
|
||||
:cb #(re-frame/dispatch [:universal-links/match-value url %])}})
|
||||
|
||||
(rf/defn store-url-for-later
|
||||
"Store the url in the db to be processed on login"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[react-native.config :as react-native-config]
|
||||
[status-im.constants :as constants]
|
||||
[utils.ens.core :as utils.ens]
|
||||
[utils.ethereum.chain :as chain]))
|
||||
|
||||
@@ -70,6 +71,18 @@
|
||||
; currently not supported in status-go
|
||||
(def enable-remove-profile-picture? false)
|
||||
|
||||
(defn env-variable->int
|
||||
[env-var-name default-value]
|
||||
(js/parseInt (get-config env-var-name default-value)))
|
||||
|
||||
(def delete-message-for-me-undo-time-limit-ms
|
||||
(env-variable->int :DELETE_MESSAGE_FOR_ME_UNDO_TIME_LIMIT
|
||||
constants/delete-message-for-me-undo-time-limit-ms))
|
||||
|
||||
(def delete-message-undo-time-limit-ms
|
||||
(env-variable->int :DELETE_MESSAGE_UNDO_TIME_LIMIT
|
||||
constants/delete-message-undo-time-limit-ms))
|
||||
|
||||
(def verify-transaction-chain-id (js/parseInt (get-config :VERIFY_TRANSACTION_CHAIN_ID "1")))
|
||||
(def verify-transaction-url
|
||||
(if (= :mainnet (chain/chain-id->chain-keyword verify-transaction-chain-id))
|
||||
|
||||
@@ -448,6 +448,8 @@
|
||||
(def ^:const optimism-short-name "opt")
|
||||
(def ^:const arbitrum-short-name "arb1")
|
||||
|
||||
(def ^:const default-multichain-address-prefix "eth:opt:arb1:")
|
||||
|
||||
(def ^:const mainnet-abbreviated-name "Eth.")
|
||||
(def ^:const optimism-abbreviated-name "Opt.")
|
||||
(def ^:const arbitrum-abbreviated-name "Arb1.")
|
||||
@@ -490,3 +492,25 @@
|
||||
(def ^:const status-hostname "status.app")
|
||||
|
||||
(def ^:const community-joined-notification-type "communityJoined")
|
||||
|
||||
(def ^:const wallet-activity-error-code-success 1)
|
||||
(def ^:const wallet-activity-error-code-task-canceled 2)
|
||||
(def ^:const wallet-activity-error-code-failed 3)
|
||||
|
||||
(def ^:const wallet-activity-type-send 0)
|
||||
(def ^:const wallet-activity-type-receive 1)
|
||||
(def ^:const wallet-activity-type-buy 2)
|
||||
(def ^:const wallet-activity-type-swap 3)
|
||||
(def ^:const wallet-activity-type-bridge 4)
|
||||
(def ^:const wallet-activity-type-contract-deployment 5)
|
||||
(def ^:const wallet-activity-type-mint 6)
|
||||
|
||||
(def ^:const wallet-activity-status-failed 0)
|
||||
(def ^:const wallet-activity-status-pending 1)
|
||||
(def ^:const wallet-activity-status-complete 2)
|
||||
(def ^:const wallet-activity-status-finalized 3)
|
||||
|
||||
(def ^:const wallet-activity-token-type-native 0)
|
||||
(def ^:const wallet-activity-token-type-erc-20 1)
|
||||
(def ^:const wallet-activity-token-type-erc-721 2)
|
||||
(def ^:const wallet-activity-token-type-erc-1155 3)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.share :as share]
|
||||
[status-im.common.contact-list-item.view :as contact-list-item]
|
||||
[status-im.common.contact-list.view :as contact-list]
|
||||
[status-im.common.home.actions.view :as actions]
|
||||
@@ -122,7 +121,7 @@
|
||||
[:show-bottom-sheet {:content chat.actions.view/new-chat}])
|
||||
:accessibility-label :new-chat-button}
|
||||
:card-props
|
||||
{:on-press #(share/open {:url profile-link})
|
||||
{:on-press #(rf/dispatch [:open-share {:options {:url profile-link}}])
|
||||
:banner (resources/get-image :invite-friends)
|
||||
:title (i18n/label :t/invite-friends-to-status)
|
||||
:description (i18n/label :t/share-invite-link)}})
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
:margin-bottom (when-not community? 12)})
|
||||
|
||||
(def community-tag-container
|
||||
{:margin-horizontal 20 :margin-top 4 :margin-bottom 12})
|
||||
{:margin-horizontal 20
|
||||
:margin-top 4
|
||||
:margin-bottom 12})
|
||||
|
||||
(def no-pinned-messages-container
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
:margin 12
|
||||
:margin-bottom (when platform/android? 12)})
|
||||
:align-items :center})
|
||||
|
||||
(def list-footer
|
||||
{:height (when platform/android? 12)})
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
(defn pinned-message
|
||||
[{:keys [from quoted-message timestamp-str]}]
|
||||
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])
|
||||
one-to-one-chat? (rf/sub [:current-chat/one-to-one-chat?])
|
||||
one-to-one-chat? (rf/sub [:chats/current-chat-one-to-one?])
|
||||
current-chat-color (rf/sub [:chats/current-chat-color])
|
||||
contact-customization-color (rf/sub [:contacts/contact-customization-color-by-address from])]
|
||||
[quo/system-message
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
[rn/view {:padding-top 4 :width 32}]))
|
||||
|
||||
(defn author
|
||||
[{:keys [response-to
|
||||
[{:keys [content
|
||||
compressed-key
|
||||
last-in-group?
|
||||
pinned-by
|
||||
@@ -61,7 +61,7 @@
|
||||
show-reactions?
|
||||
in-reaction-and-action-menu?
|
||||
show-user-info?]
|
||||
(when (or (and (seq response-to) quoted-message)
|
||||
(when (or (and (seq (:response-to content)) quoted-message)
|
||||
last-in-group?
|
||||
pinned-by
|
||||
show-user-info?
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[react-native.gesture :as gesture]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.contact-list-item.view :as contact-list-item]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.composer.reply.view :as reply]
|
||||
[status-im.contexts.chat.messenger.messages.drawers.style :as style]
|
||||
@@ -140,7 +141,7 @@
|
||||
(rf/dispatch
|
||||
[:hide-bottom-sheet])
|
||||
(rf/dispatch [:chat.ui/delete-message-for-me message-data
|
||||
constants/delete-message-for-me-undo-time-limit-ms]))
|
||||
config/delete-message-for-me-undo-time-limit-ms]))
|
||||
|
||||
:label (i18n/label :t/delete-for-me)
|
||||
:icon :i/delete
|
||||
@@ -155,7 +156,7 @@
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:chat.ui/delete-message message-data
|
||||
constants/delete-message-undo-time-limit-ms]))
|
||||
config/delete-message-undo-time-limit-ms]))
|
||||
:label (i18n/label :t/delete-for-everyone)
|
||||
:icon :i/delete
|
||||
:id :delete-for-all}])))
|
||||
|
||||
@@ -130,6 +130,9 @@
|
||||
[cofx chat-id]
|
||||
(navigation/show-bottom-sheet
|
||||
cofx
|
||||
{:content (fn [] [pinned-messages-menu/view
|
||||
{:chat-id chat-id
|
||||
:disable-message-long-press? (not= :chat (get-in cofx [:db :view-id]))}])}))
|
||||
{:padding-bottom-override 21
|
||||
:content (fn [] [pinned-messages-menu/view
|
||||
{:chat-id chat-id
|
||||
:disable-message-long-press? (not= :chat
|
||||
(get-in cofx
|
||||
[:db :view-id]))}])}))
|
||||
|
||||
@@ -73,19 +73,25 @@
|
||||
|
||||
(defn check-permissions-to-join-for-selection
|
||||
[{:keys [db]} [community-id addresses]]
|
||||
(if (empty? addresses)
|
||||
;; When there are no addresses we can't just check permissions, otherwise
|
||||
;; status-go will consider all possible addresses and the user will see the
|
||||
;; incorrect highest permission role.
|
||||
{:db (update db :communities/permissions-checks-for-selection dissoc community-id)}
|
||||
{:db (assoc-in db [:communities/permissions-checks-for-selection community-id :checking?] true)
|
||||
:fx [[:json-rpc/call
|
||||
[{:method :wakuext_checkPermissionsToJoinCommunity
|
||||
:params [{:communityId community-id :addresses addresses}]
|
||||
:on-success [:communities/check-permissions-to-join-during-selection-success
|
||||
community-id]
|
||||
:on-error [:communities/check-permissions-to-join-during-selection-failure
|
||||
community-id addresses]}]]]}))
|
||||
(let [request-id (rand-int 10000000)]
|
||||
(if (empty? addresses)
|
||||
;; When there are no addresses we can't just check permissions, otherwise
|
||||
;; status-go will consider all possible addresses and the user will see the
|
||||
;; incorrect highest permission role.
|
||||
{:db (update db :communities/permissions-checks-for-selection dissoc community-id)}
|
||||
{:db (update-in db
|
||||
[:communities/permissions-checks-for-selection community-id]
|
||||
assoc
|
||||
:checking? true
|
||||
:latest-request-id request-id)
|
||||
:fx [[:json-rpc/call
|
||||
[{:method :wakuext_checkPermissionsToJoinCommunity
|
||||
:params [{:communityId community-id :addresses addresses}]
|
||||
:id request-id
|
||||
:on-success [:communities/check-permissions-to-join-during-selection-success
|
||||
community-id]
|
||||
:on-error [:communities/check-permissions-to-join-during-selection-failure
|
||||
community-id addresses]}]]]})))
|
||||
|
||||
;; This event should be used to check permissions temporarily because it won't
|
||||
;; mutate the state `:communities/permissions-check` (used by many other
|
||||
@@ -94,12 +100,14 @@
|
||||
check-permissions-to-join-for-selection)
|
||||
|
||||
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection-success
|
||||
(fn [{:keys [db]} [community-id result]]
|
||||
{:db (assoc-in db
|
||||
[:communities/permissions-checks-for-selection community-id]
|
||||
{:checking? false
|
||||
:based-on-client-selection? true
|
||||
:check result})}))
|
||||
(fn [{:keys [db]} [community-id result request-id]]
|
||||
(when (= (get-in db [:communities/permissions-checks-for-selection community-id :latest-request-id])
|
||||
request-id)
|
||||
{:db (assoc-in db
|
||||
[:communities/permissions-checks-for-selection community-id]
|
||||
{:checking? false
|
||||
:based-on-client-selection? true
|
||||
:check result})})))
|
||||
|
||||
(rf/reg-event-fx :communities/check-permissions-to-join-during-selection-failure
|
||||
(fn [_ [community-id addresses error]]
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
(ns status-im.contexts.communities.actions.permissions-sheet.style)
|
||||
|
||||
(def container
|
||||
{:flex 1
|
||||
:padding-horizontal 20})
|
||||
@@ -1,38 +1,12 @@
|
||||
(ns status-im.contexts.communities.actions.permissions-sheet.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[status-im.contexts.communities.actions.permissions-sheet.style :as style]
|
||||
[status-im.contexts.communities.utils :as communities.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- role-text
|
||||
[role]
|
||||
(i18n/label
|
||||
(communities.utils/role->translation-key role
|
||||
:t/token-master)))
|
||||
|
||||
(defn- permission-view
|
||||
[{:keys [tokens role satisfied?]}]
|
||||
(when (seq tokens)
|
||||
^{:key role}
|
||||
[rn/view {:style {:margin-bottom 20}}
|
||||
[quo/text {:weight :medium}
|
||||
(if satisfied?
|
||||
(i18n/label :t/you-eligible-to-join-as {:role (role-text role)})
|
||||
(i18n/label :t/you-not-eligible-to-join-as {:role (role-text role)}))]
|
||||
[quo/text {:size :paragraph-2 :style {:padding-bottom 8}}
|
||||
(if satisfied?
|
||||
(i18n/label :t/you-hodl)
|
||||
(i18n/label :t/you-must-hold))]
|
||||
[quo/token-requirement-list
|
||||
{:tokens tokens
|
||||
:container-style {:padding-horizontal 20}}]]))
|
||||
|
||||
(defn view
|
||||
[id]
|
||||
(let [permissions (rf/sub [:community/token-permissions id])]
|
||||
[gesture/scroll-view {:style style/container}
|
||||
(map permission-view permissions)]))
|
||||
[gesture/scroll-view
|
||||
[quo/community-detail-token-gating {:permissions permissions}]
|
||||
]))
|
||||
|
||||
@@ -149,23 +149,6 @@
|
||||
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
|
||||
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))
|
||||
|
||||
(defn initialize-permission-addresses
|
||||
[{:keys [db]} [community-id]]
|
||||
(when community-id
|
||||
(let [accounts (utils/sorted-non-watch-only-accounts db)
|
||||
addresses (set (map :address accounts))]
|
||||
{:db (update-in db
|
||||
[:communities community-id]
|
||||
assoc
|
||||
:previous-share-all-addresses? true
|
||||
:share-all-addresses? true
|
||||
:previous-permission-addresses addresses
|
||||
:selected-permission-addresses addresses
|
||||
:airdrop-address (:address (first accounts)))})))
|
||||
|
||||
(rf/reg-event-fx :communities/initialize-permission-addresses
|
||||
initialize-permission-addresses)
|
||||
|
||||
(defn update-previous-permission-addresses
|
||||
[{:keys [db]} [community-id]]
|
||||
(when community-id
|
||||
@@ -342,8 +325,8 @@
|
||||
|
||||
(rf/reg-event-fx :chat.ui/spectate-community spectate-community)
|
||||
|
||||
(rf/defn navigate-to-serialized-community
|
||||
[_ {:keys [community-id]}]
|
||||
(defn navigate-to-serialized-community
|
||||
[community-id]
|
||||
{:serialization/deserialize-and-compress-key
|
||||
{:serialized-key community-id
|
||||
:on-success #(rf/dispatch [:communities/navigate-to-community-overview %])
|
||||
@@ -351,27 +334,30 @@
|
||||
:error %
|
||||
:community-id community-id})}})
|
||||
|
||||
(rf/reg-event-fx :communities/navigate-to-community-overview
|
||||
(fn [{:keys [db] :as cofx} [deserialized-key]]
|
||||
(let [current-view-id (:view-id db)]
|
||||
(if (string/starts-with? deserialized-key constants/serialization-key)
|
||||
(navigate-to-serialized-community cofx deserialized-key)
|
||||
(rf/merge
|
||||
cofx
|
||||
{:fx [[:dispatch
|
||||
[:communities/fetch-community
|
||||
{:community-id deserialized-key
|
||||
:update-last-opened-at? true}]]
|
||||
[:dispatch [:navigate-to :community-overview deserialized-key]]
|
||||
(when (get-in db [:communities deserialized-key :joined])
|
||||
[:dispatch
|
||||
[:activity-center.notifications/dismiss-community-overview deserialized-key]])]}
|
||||
(when-not (or (= current-view-id :shell) (= current-view-id :communities-stack))
|
||||
(navigation/pop-to-root :shell-stack)))))))
|
||||
(rf/defn navigate-to-community-overview
|
||||
[{:keys [db] :as cofx} [community-id]]
|
||||
(let [current-view-id (:view-id db)]
|
||||
(if (string/starts-with? community-id constants/serialization-key)
|
||||
(navigate-to-serialized-community community-id)
|
||||
(rf/merge
|
||||
cofx
|
||||
{:fx [[:dispatch
|
||||
[:communities/fetch-community
|
||||
{:community-id community-id
|
||||
:update-last-opened-at? true}]]
|
||||
[:dispatch [:navigate-to :community-overview community-id]]
|
||||
(when (get-in db [:communities community-id :joined])
|
||||
[:dispatch
|
||||
[:activity-center.notifications/dismiss-community-overview community-id]])]}
|
||||
(when-not (or (= current-view-id :shell) (= current-view-id :communities-stack))
|
||||
(navigation/pop-to-root :shell-stack))))))
|
||||
|
||||
(rf/reg-event-fx :communities/navigate-to-community-chat
|
||||
(fn [{:keys [db]} [chat-id pop-to-root?]]
|
||||
(let [{:keys [community-id]} (get-in db [:chats chat-id])]
|
||||
(rf/reg-event-fx :communities/navigate-to-community-overview navigate-to-community-overview)
|
||||
|
||||
(defn navigate-to-community-chat
|
||||
[{:keys [db]} [chat-id pop-to-root? community-id]]
|
||||
(let [community-id (or community-id (get-in db [:chats chat-id :community-id]))]
|
||||
(merge
|
||||
{:fx [(when community-id
|
||||
[:dispatch
|
||||
[:communities/fetch-community
|
||||
@@ -379,7 +365,11 @@
|
||||
:update-last-opened-at? true}]])
|
||||
(if pop-to-root?
|
||||
[:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]]
|
||||
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
|
||||
[:dispatch [:chat/navigate-to-chat chat-id]])]}
|
||||
(when-not (get-in db [:chats chat-id :community-id])
|
||||
{:db (assoc-in db [:chats chat-id :community-id] community-id)}))))
|
||||
|
||||
(rf/reg-event-fx :communities/navigate-to-community-chat navigate-to-community-chat)
|
||||
|
||||
(defn get-revealed-accounts
|
||||
[{:keys [db]} [community-id on-success]]
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
(def community-tag-container
|
||||
{:padding-horizontal screen-horizontal-padding
|
||||
:margin-horizontal (- screen-horizontal-padding)
|
||||
:margin-bottom 20})
|
||||
:margin-bottom 16})
|
||||
|
||||
(def community-content-container
|
||||
{:padding-horizontal screen-horizontal-padding})
|
||||
@@ -64,4 +64,5 @@
|
||||
{:border-radius 16
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80)
|
||||
:border-width 1
|
||||
:padding-top 10})
|
||||
:padding-top 10
|
||||
:margin-bottom 106})
|
||||
|
||||
@@ -38,8 +38,9 @@
|
||||
{:keys [name emoji muted? id mentions-count unread-messages? on-press locked? color] :as chat}]
|
||||
(let [sheet-content [actions/chat-actions
|
||||
(assoc chat
|
||||
:chat-type constants/community-chat-type
|
||||
:chat-id (str community-id id))
|
||||
:community-id community-id
|
||||
:chat-type constants/community-chat-type
|
||||
:chat-id (str community-id id))
|
||||
false]
|
||||
notification (cond
|
||||
muted? :mute
|
||||
@@ -161,7 +162,7 @@
|
||||
(i18n/label :t/you-eligible-to-join-as {:role highest-role-text})
|
||||
(i18n/label :t/you-not-eligible-to-join))]
|
||||
[info-button]]
|
||||
[quo/text {:style {:padding-horizontal 12 :padding-bottom 18} :size :paragraph-2}
|
||||
[quo/text {:style {:padding-horizontal 12 :padding-bottom 6} :size :paragraph-2}
|
||||
(if can-request-access?
|
||||
(i18n/label :t/you-hodl)
|
||||
(i18n/label :t/you-must-hold))]
|
||||
@@ -175,7 +176,7 @@
|
||||
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
|
||||
:accessibility-label :join-community-button
|
||||
:customization-color color
|
||||
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
|
||||
:container-style {:margin-horizontal 12 :margin-top 8 :margin-bottom 12}
|
||||
:disabled? (not can-request-access?)
|
||||
:icon-left (if can-request-access? :i/unlocked :i/locked)}
|
||||
(i18n/label :t/request-to-join)]])))
|
||||
|
||||
@@ -38,23 +38,24 @@
|
||||
:url %}])]
|
||||
{:fx [[:dispatch [:communities/get-community-channel-share-data chat-id on-success]]]})))
|
||||
|
||||
(rf/reg-event-fx :communities/share-community-url-with-data
|
||||
(fn [_ [community-id]]
|
||||
(let [title (i18n/label :t/community-on-status)
|
||||
(rf/reg-event-fx :communities/share-community-channel-url-with-data
|
||||
(fn [_ [chat-id]]
|
||||
(let [title (i18n/label :t/channel-on-status)
|
||||
on-success (fn [url]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content title}
|
||||
:item {:default {:type "url"
|
||||
:content url}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message url
|
||||
:url url
|
||||
:isNewTask true})))]
|
||||
{:fx [[:dispatch [:communities/get-community-share-data community-id on-success]]]})))
|
||||
(rf/dispatch [:open-share
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources
|
||||
[{:placeholderItem {:type :text
|
||||
:content title}
|
||||
:item {:default {:type :url
|
||||
:content url}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message url
|
||||
:url url
|
||||
:isNewTask true})}]))]
|
||||
{:fx [[:dispatch [:communities/get-community-channel-share-data chat-id on-success]]]})))
|
||||
|
||||
(rf/reg-event-fx :communities/get-community-channel-share-data
|
||||
(fn [_ [chat-id on-success]]
|
||||
|
||||
@@ -49,12 +49,13 @@
|
||||
[:screen/onboarding.enter-seed-phrase
|
||||
:screen/onboarding.new-to-status]])}]
|
||||
[rn/view {:style style/space-between-suboptions}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-keycard)
|
||||
:subtitle (i18n/label :t/use-keycard-subtitle)
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(js/alert "TODO: to be implemented")}]]]))
|
||||
(when config/show-not-implemented-features?
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-keycard)
|
||||
:subtitle (i18n/label :t/use-keycard-subtitle)
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(js/alert "TODO: to be implemented")}])]]))
|
||||
|
||||
(defn getting-started-doc
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
(ns status-im.contexts.preview.quo.community.community-detail-token-gating
|
||||
(:require [quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:key :role
|
||||
:type :select
|
||||
:options [{:key :one-role}
|
||||
{:key :two-roles}
|
||||
{:key :three-roles}
|
||||
{:key :four-roles}]}])
|
||||
|
||||
(def roles
|
||||
{:member
|
||||
{:role 2
|
||||
:role-text "Member"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "ETH" :sufficient? true :collectible? false :loading? false :amount 0.8 :img-src nil}]
|
||||
[{:symbol "ETH" :sufficient? false :collectible? false :loading? false :amount 1 :img-src nil}
|
||||
{:symbol "STT" :sufficient? false :collectible? false :loading? false :amount 10 :img-src nil}]]}
|
||||
:admin
|
||||
{:role 1
|
||||
:role-text "Admin"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "ETH" :sufficient? true :collectible? false :loading? false :amount 2 :img-src nil}]]}
|
||||
:token-master
|
||||
{:role 5
|
||||
:role-text "Token Master"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "TMANI"
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:loading? false
|
||||
:amount nil
|
||||
:img-src (resources/mock-images :collectible1)}]]}
|
||||
:token-owner
|
||||
{:role 6
|
||||
:role-text "Token Owner"
|
||||
:satisfied? true
|
||||
:tokens
|
||||
[[{:symbol "TOANI"
|
||||
:sufficient? true
|
||||
:collectible? true
|
||||
:loading? false
|
||||
:amount nil
|
||||
:img-src (resources/mock-images :collectible)}]]}})
|
||||
|
||||
(def permissions
|
||||
{:one-role [(:member roles)]
|
||||
:two-roles [(:admin roles) (:member roles)]
|
||||
:three-roles [(:token-master roles) (:admin roles) (:member roles)]
|
||||
:four-roles [(:token-owner roles) (:token-master roles) (:admin roles) (:member roles)]})
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:role :one-role})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:blur? (:blur? @state)
|
||||
:show-blur-background? true}
|
||||
[quo/community-detail-token-gating {:permissions ((:role @state) permissions)}]])))
|
||||
@@ -39,6 +39,8 @@
|
||||
channel-actions]
|
||||
[status-im.contexts.preview.quo.community.community-card-view :as
|
||||
community-card]
|
||||
[status-im.contexts.preview.quo.community.community-detail-token-gating :as
|
||||
community-detail-token-gating]
|
||||
[status-im.contexts.preview.quo.community.community-membership-list-view
|
||||
:as community-membership-list-view]
|
||||
[status-im.contexts.preview.quo.community.community-stat :as community-stat]
|
||||
@@ -260,6 +262,8 @@
|
||||
:component color/view}]
|
||||
:community [{:name :community-card-view
|
||||
:component community-card/view}
|
||||
{:name :community-detail-token-gating
|
||||
:component community-detail-token-gating/view}
|
||||
{:name :community-membership-list-view
|
||||
:component community-membership-list-view/view}
|
||||
{:name :community-stat
|
||||
|
||||
@@ -15,12 +15,6 @@
|
||||
{:key :image}]}
|
||||
{:key :community?
|
||||
:type :boolean}
|
||||
{:key :status
|
||||
:type :select
|
||||
:options [{:key :loading}
|
||||
{:key :default}
|
||||
{:key :unsupported}
|
||||
{:key :cant-fetch}]}
|
||||
{:key :gradient-color-index
|
||||
:type :select
|
||||
:options [{:key :gradient-1}
|
||||
@@ -39,7 +33,6 @@
|
||||
:collectible-name "Doodle #6822"
|
||||
:gradient-color-index :gradient-1
|
||||
:community? false
|
||||
:status :loading
|
||||
:counter ""})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
@@ -52,5 +45,6 @@
|
||||
:counter (when (seq (:counter @state)) (:counter @state))
|
||||
:gradient-color-index (:gradient-color-index @state)
|
||||
:image-src test-image
|
||||
:supported-file? true
|
||||
:avatar-image-src test-avatar
|
||||
:on-press #(js/alert "Pressed"))]])))
|
||||
|
||||
@@ -14,12 +14,6 @@
|
||||
:type :boolean}
|
||||
{:key :counter
|
||||
:type :text}
|
||||
{:key :status
|
||||
:type :select
|
||||
:options [{:key :loading}
|
||||
{:key :default}
|
||||
{:key :unsupported}
|
||||
{:key :cant-fetch}]}
|
||||
{:type :select
|
||||
:key :image-type
|
||||
:options [{:key :vertical}
|
||||
@@ -29,7 +23,6 @@
|
||||
[]
|
||||
(let [state (reagent/atom {:square? false
|
||||
:counter ""
|
||||
:status :default
|
||||
:image-type :horizontal})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
@@ -39,8 +32,9 @@
|
||||
:margin-horizontal 35}}
|
||||
[quo/expanded-collectible
|
||||
(assoc (dissoc @state :image-type)
|
||||
:image-src (if (= :vertical (:image-type @state))
|
||||
vertical-image
|
||||
horizontal-image)
|
||||
:counter (when (seq (:counter @state)) (:counter @state))
|
||||
:on-press #(js/alert "Pressed"))]])))
|
||||
:image-src (if (= :vertical (:image-type @state))
|
||||
vertical-image
|
||||
horizontal-image)
|
||||
:counter (when (seq (:counter @state)) (:counter @state))
|
||||
:supported-file? true
|
||||
:on-press #(js/alert "Pressed"))]])))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.contexts.preview.quo.wallet.network-link
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
@@ -23,17 +24,21 @@
|
||||
:options networks}
|
||||
{:key :destination
|
||||
:type :select
|
||||
:options networks}])
|
||||
:options networks}
|
||||
{:key :width
|
||||
:type :number}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:shape :linear
|
||||
:source :ethereum
|
||||
:destination :optimism})]
|
||||
:destination :optimism
|
||||
:width 63})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:component-container-style {:padding-top 40
|
||||
:align-items :center}}
|
||||
[quo/network-link @state]])))
|
||||
[rn/view {:style {:width (max (:width @state) 63)}}
|
||||
[quo/network-link @state]]])))
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
(fn []
|
||||
(rf/dispatch [:universal-links/generate-profile-url
|
||||
{:public-key public-key
|
||||
:on-success #(rn/sharing {:message %})}]))
|
||||
:on-success #(rf/dispatch [:open-share
|
||||
{:options {:message %}}])}]))
|
||||
[public-key])
|
||||
on-remove-contact (rn/use-callback
|
||||
(fn []
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im.contexts.profile.contact.share.view
|
||||
(:require [legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[quo.core :as quo]
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
@@ -19,7 +18,8 @@
|
||||
abbreviated-url (rn/use-memo (fn []
|
||||
(address/get-abbreviated-profile-url universal-profile-url))
|
||||
[universal-profile-url])
|
||||
on-share-press (rn/use-callback #(list-selection/open-share {:message universal-profile-url})
|
||||
on-share-press (rn/use-callback #(rf/dispatch [:open-share
|
||||
{:options {:message universal-profile-url}}])
|
||||
[universal-profile-url])
|
||||
on-copy-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:share/copy-text-and-show-toast
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
(when config/show-not-implemented-features?
|
||||
{:title (i18n/label :t/dapps)
|
||||
:on-press not-implemented/alert
|
||||
:image-props :i/placeholder
|
||||
:image-props :i/dapps
|
||||
:image :icon
|
||||
:blur? true
|
||||
:action :arrow})
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.contexts.profile.settings.header.view :as settings.header]
|
||||
[status-im.contexts.profile.settings.list-items :as settings.items]
|
||||
[status-im.contexts.profile.settings.style :as style]
|
||||
@@ -19,7 +18,7 @@
|
||||
[rf/delay-render
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:container-style {:padding-bottom 0}
|
||||
:container-style {:padding-bottom 12}
|
||||
:blur? true
|
||||
:data data}]])
|
||||
|
||||
@@ -62,7 +61,10 @@
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:right-side [{:icon-name :i/qr-code
|
||||
:on-press #(debounce/throttle-and-dispatch [:open-modal :share-shell] 1000)}
|
||||
{:icon-name :i/share :on-press not-implemented/alert}]}]]
|
||||
{:icon-name :i/share
|
||||
:on-press #(rf/dispatch [:open-share
|
||||
{:options {:message (:universal-profile-url
|
||||
profile)}}])}]}]]
|
||||
[rn/flat-list
|
||||
{:key :list
|
||||
:header [settings.header/view {:scroll-y scroll-y}]
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
|
||||
(defn floating-button
|
||||
[shared-values]
|
||||
[quo/floating-shell-button
|
||||
{:jump-to {:on-press #(animation/close-home-stack true)
|
||||
:label (i18n/label :t/jump-to)
|
||||
:customization-color (rf/sub [:profile/customization-color])}}
|
||||
{:position :absolute
|
||||
:bottom (utils/bottom-tabs-container-height)}
|
||||
(:home-stack-opacity shared-values)])
|
||||
(let [current-screen-id (rf/sub [:view-id])]
|
||||
(when-not (= current-screen-id :settings)
|
||||
[quo/floating-shell-button
|
||||
{:jump-to {:on-press #(animation/close-home-stack true)
|
||||
:label (i18n/label :t/jump-to)
|
||||
:customization-color (rf/sub [:profile/customization-color])}}
|
||||
{:position :absolute
|
||||
:bottom (utils/bottom-tabs-container-height)}
|
||||
(:home-stack-opacity shared-values)])))
|
||||
|
||||
(defn f-shell-stack
|
||||
[]
|
||||
|
||||
@@ -71,13 +71,10 @@
|
||||
(defn on-qr-code-scanned
|
||||
[scanned-text]
|
||||
(cond
|
||||
(text-for-url-path? scanned-text router/community-with-data-path)
|
||||
;; TODO: https://github.com/status-im/status-mobile/issues/18743
|
||||
nil
|
||||
|
||||
(text-for-url-path? scanned-text router/channel-path)
|
||||
;; TODO: https://github.com/status-im/status-mobile/issues/18743
|
||||
nil
|
||||
(or
|
||||
(text-for-url-path? scanned-text router/community-with-data-path)
|
||||
(text-for-url-path? scanned-text router/channel-path))
|
||||
(debounce/debounce-and-dispatch [:universal-links/handle-url scanned-text] 300)
|
||||
|
||||
(text-for-url-path? scanned-text router/user-with-data-path)
|
||||
(let [address (extract-id scanned-text)]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.contexts.shell.share.profile.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
@@ -30,7 +29,7 @@
|
||||
:width (- window-width (* style/screen-padding 2))
|
||||
:qr-data universal-profile-url
|
||||
:qr-data-label-shown abbreviated-url
|
||||
:on-share-press #(list-selection/open-share {:message universal-profile-url})
|
||||
:on-share-press #(rf/dispatch [:open-share {:options {:message universal-profile-url}}])
|
||||
:on-text-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}])
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.shell.share.style :as style]
|
||||
@@ -20,18 +19,18 @@
|
||||
|
||||
(defn- share-action
|
||||
[address share-title]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})))
|
||||
(rf/dispatch [:open-share
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type :text
|
||||
:content address}
|
||||
:item {:default {:type :text
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})}]))
|
||||
|
||||
(defn- open-preferences
|
||||
[selected-networks account]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.share :as share]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.account.share-address.style :as style]
|
||||
@@ -18,18 +17,18 @@
|
||||
|
||||
(defn- share-action
|
||||
[address share-title]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})))
|
||||
(rf/dispatch [:open-share
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type :text
|
||||
:content address}
|
||||
:item {:default {:type :text
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})}]))
|
||||
|
||||
(defn- open-preferences
|
||||
[selected-networks]
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
|
||||
(defn view
|
||||
[{:keys [selected-tab]}]
|
||||
(let [collectible-list (rf/sub [:wallet/current-viewing-account-collectibles-in-selected-networks])]
|
||||
(let [collectible-list (rf/sub
|
||||
[:wallet/current-viewing-account-collectibles-in-selected-networks])
|
||||
current-account-address (rf/sub [:wallet/current-viewing-account-address])]
|
||||
[rn/view {:style {:flex 1}}
|
||||
(case selected-tab
|
||||
:assets [assets/view]
|
||||
:collectibles [collectibles/view
|
||||
{:collectibles collectible-list
|
||||
:current-account-address current-account-address
|
||||
:on-end-reached #(rf/dispatch
|
||||
[:wallet/request-collectibles-for-current-viewing-account])
|
||||
:on-collectible-press (fn [{:keys [id]}]
|
||||
@@ -30,7 +33,7 @@
|
||||
[options-drawer/view
|
||||
{:name (:name collectible-details)
|
||||
:image (:uri preview-url)}])}]))}]
|
||||
:activity [activity/view]
|
||||
:activity [activity/view {:activities []}]
|
||||
:permissions [empty-tab/view
|
||||
{:title (i18n/label :t/no-permissions)
|
||||
:description (i18n/label :t/no-collectibles-description)
|
||||
|
||||
@@ -6,20 +6,10 @@
|
||||
[status-im.contexts.wallet.account.style :as style]
|
||||
[status-im.contexts.wallet.account.tabs.view :as tabs]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
[status-im.contexts.wallet.common.temp :as temp]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn buy-drawer
|
||||
[]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/buy-tokens)}]
|
||||
[rn/flat-list
|
||||
{:data temp/buy-tokens-list
|
||||
:style {:padding-horizontal 8
|
||||
:padding-bottom 8}
|
||||
:render-fn quo/settings-item}]])
|
||||
|
||||
(def first-tab-id :assets)
|
||||
|
||||
(defn tabs-data
|
||||
@@ -55,7 +45,7 @@
|
||||
:flow-id :wallet-flow}]))
|
||||
:receive-action #(rf/dispatch [:open-modal :screen/wallet.share-address {:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-drawer}])
|
||||
{:content buy-token/view}])
|
||||
:bridge-action #(rf/dispatch [:wallet/start-bridge])}])
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
|
||||
+1
-3
@@ -25,9 +25,7 @@
|
||||
(fn []
|
||||
[rn/view {:style style/container}
|
||||
[create-or-edit-account/view
|
||||
{:page-nav-right-side [{:icon-name :i/info
|
||||
:on-press #(js/alert "Get info (to be implemented)")}]
|
||||
:placeholder placeholder
|
||||
{:placeholder placeholder
|
||||
:account-name @account-name
|
||||
:account-emoji @account-emoji
|
||||
:account-color @account-color
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
:accessibility-label :import-using-phrase
|
||||
:label (i18n/label :t/import-using-phrase)
|
||||
:add-divider? true}
|
||||
{:icon :i/keycard-card
|
||||
:accessibility-label :import-from-keycard
|
||||
:label (i18n/label :t/import-from-keycard)}
|
||||
{:icon :i/key
|
||||
:accessibility-label :import-private-key
|
||||
:label (i18n/label :t/import-private-key)}]]])
|
||||
|
||||
@@ -46,19 +46,18 @@
|
||||
{:title (i18n/label :t/derivation-path)
|
||||
:image :icon
|
||||
:image-props :i/derivated-path
|
||||
:action :button
|
||||
:action-props {:on-press #(if (ff/enabled? :ff/wallet.edit-derivation-path)
|
||||
(rf/dispatch [:standard-auth/authorize
|
||||
{:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/continue)}])
|
||||
(js/alert "Coming soon!"))
|
||||
:action (if (ff/enabled? ::ff/wallet.edit-derivation-path) :button :none)
|
||||
:action-props {:on-press #(rf/dispatch [:standard-auth/authorize
|
||||
{:on-auth-success on-auth-success
|
||||
:auth-button-label (i18n/label :t/continue)}])
|
||||
|
||||
:button-text (i18n/label :t/edit)
|
||||
:icon-left :i/face-id
|
||||
:alignment :flex-start}
|
||||
:description :text
|
||||
:description-props {:text formatted-path}}]))
|
||||
|
||||
(defn- f-view
|
||||
(defn- view-internal
|
||||
[_]
|
||||
(let [top (safe-area/get-top)
|
||||
bottom (safe-area/get-bottom)
|
||||
@@ -180,8 +179,4 @@
|
||||
:derivation-path derivation-path
|
||||
:customization-color customization-color})}]]))))
|
||||
|
||||
(defn- view-internal
|
||||
[]
|
||||
[:f> f-view])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
[account-switcher/view
|
||||
{:on-press #(rf/dispatch [:navigate-back])
|
||||
:icon-name :i/arrow-left
|
||||
:accessibility-label :top-bar}]
|
||||
:accessibility-label :top-bar
|
||||
:switcher-type :select-account}]
|
||||
[quo/page-top {:title bridge-to-title}]
|
||||
[rn/view style/content-container
|
||||
[bridge-token-component (assoc mainnet :network-name :t/mainnet) account-token]]
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
:button-one-label (i18n/label :t/confirm-bridge)
|
||||
:button-one-props {:icon-left :i/bridge}
|
||||
:on-navigate-back (fn []
|
||||
(rf/dispatch [:wallet/clean-disabled-from-networks])
|
||||
(rf/dispatch [:navigate-back]))}]])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
[rn/view {:style {:flex 1}}
|
||||
[account-switcher/view
|
||||
{:on-press #(rf/dispatch [:navigate-back])
|
||||
:accessibility-label :top-bar}]
|
||||
:accessibility-label :top-bar
|
||||
:switcher-type :select-account}]
|
||||
[quo/page-top {:title (i18n/label :t/bridge)}]
|
||||
[quo/input
|
||||
{:container-style style/input-container
|
||||
|
||||
@@ -7,3 +7,33 @@
|
||||
first
|
||||
:balance
|
||||
js/parseInt))
|
||||
|
||||
(def ^:const supported-collectible-types
|
||||
#{"image/jpeg"
|
||||
"image/gif"
|
||||
"image/bmp"
|
||||
"image/png"
|
||||
"image/webp"})
|
||||
|
||||
(defn supported-file?
|
||||
[collectible-type]
|
||||
(if (supported-collectible-types collectible-type)
|
||||
true
|
||||
(do
|
||||
(println "unsupoorted collectible file type" collectible-type)
|
||||
false)))
|
||||
|
||||
(defn total-owned-collectible
|
||||
([ownership]
|
||||
(total-owned-collectible ownership false))
|
||||
([ownership address]
|
||||
(reduce (fn [acc item]
|
||||
(if (or (not address) (= (:address item) address))
|
||||
(+ acc (js/parseInt (:balance item)))
|
||||
acc))
|
||||
0
|
||||
ownership)))
|
||||
|
||||
(defn collectible-owned-counter
|
||||
[total]
|
||||
(when (> total 1) (str "x" total)))
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
(ns status-im.contexts.wallet.collectible.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.svg :as svg]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.scroll-page.view :as scroll-page]
|
||||
[status-im.contexts.wallet.collectible.options.view :as options-drawer]
|
||||
[status-im.contexts.wallet.collectible.style :as style]
|
||||
[status-im.contexts.wallet.collectible.tabs.view :as tabs]
|
||||
[status-im.contexts.wallet.collectible.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -36,10 +37,13 @@
|
||||
:icon-left :i/send}
|
||||
(i18n/label :t/send)]
|
||||
[quo/button
|
||||
{:container-style style/opensea-button
|
||||
:type :outline
|
||||
:size 40
|
||||
:icon-left :i/opensea}
|
||||
{:container-style style/opensea-button
|
||||
:type :outline
|
||||
:size 40
|
||||
:icon-left :i/opensea
|
||||
:icon-left-color (colors/theme-colors colors/neutral-100 colors/neutral-40)
|
||||
:icon-right :i/external
|
||||
:icon-right-color (colors/theme-colors colors/neutral-50 colors/neutral-40)}
|
||||
(i18n/label :t/opensea)]])
|
||||
|
||||
(def tabs-data
|
||||
@@ -57,6 +61,7 @@
|
||||
(fn []
|
||||
(let [collectible (rf/sub [:wallet/last-collectible-details])
|
||||
animation-shared-element-id (rf/sub [:animation-shared-element-id])
|
||||
wallet-address (rf/sub [:wallet/current-viewing-account-address])
|
||||
{:keys [id
|
||||
preview-url
|
||||
collection-data
|
||||
@@ -76,7 +81,9 @@
|
||||
:image-height 300
|
||||
:id token-id
|
||||
:header collectible-name
|
||||
:description collection-name}]
|
||||
:description collection-name}
|
||||
total-owned (utils/total-owned-collectible (:ownership collectible)
|
||||
wallet-address)]
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/clear-last-collectible-details]))
|
||||
[scroll-page/scroll-page
|
||||
{:navigate-back? true
|
||||
@@ -93,10 +100,13 @@
|
||||
:theme theme}])}]
|
||||
:picture preview-uri}}
|
||||
[rn/view {:style style/container}
|
||||
[rn/view {:style style/preview-container}
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
[quo/expanded-collectible
|
||||
{:image-src preview-uri
|
||||
:container-style style/preview-container
|
||||
:counter (utils/collectible-owned-counter total-owned)
|
||||
:native-ID (when (= animation-shared-element-id token-id) :shared-element)
|
||||
:supported-file? (utils/supported-file? (:animation-media-type collectible-data))
|
||||
:on-press (fn []
|
||||
(if svg?
|
||||
(js/alert "Can't visualize SVG images in lightbox")
|
||||
(rf/dispatch
|
||||
@@ -109,17 +119,7 @@
|
||||
(fn []
|
||||
[options-drawer/view
|
||||
{:name collectible-name
|
||||
:image preview-uri}])}])}])))}
|
||||
(if svg?
|
||||
[rn/view
|
||||
{:style (assoc style/preview :overflow :hidden)
|
||||
:native-ID (when (= animation-shared-element-id token-id)
|
||||
:shared-element)}
|
||||
[svg/svg-uri (assoc style/preview :uri preview-uri)]]
|
||||
[rn/image
|
||||
{:source preview-uri
|
||||
:style style/preview
|
||||
:native-ID (when (= animation-shared-element-id token-id) :shared-element)}])]]
|
||||
:image preview-uri}])}])}])))}]
|
||||
[header collectible-name collection-name collection-image]
|
||||
[cta-buttons]
|
||||
[quo/tabs
|
||||
|
||||
@@ -16,16 +16,15 @@
|
||||
item)]])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [theme]}]
|
||||
(let [activity-list []]
|
||||
(if (empty? activity-list)
|
||||
[empty-tab/view
|
||||
{:title (i18n/label :t/no-activity)
|
||||
:description (i18n/label :t/empty-tab-description)
|
||||
:image (resources/get-themed-image :no-activity theme)}]
|
||||
[rn/flat-list
|
||||
{:data activity-list
|
||||
:style {:flex 1}
|
||||
:render-fn activity-item}])))
|
||||
[{:keys [theme activity-list]}]
|
||||
(if (empty? activity-list)
|
||||
[empty-tab/view
|
||||
{:title (i18n/label :t/no-activity)
|
||||
:description (i18n/label :t/empty-tab-description)
|
||||
:image (resources/get-themed-image :no-activity theme)}]
|
||||
[rn/flat-list
|
||||
{:data activity-list
|
||||
:style {:flex 1}
|
||||
:render-fn activity-item}]))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -4,11 +4,32 @@
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.wallet.collectible.utils :as utils]
|
||||
[status-im.contexts.wallet.common.empty-tab.view :as empty-tab]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn- render-fn
|
||||
[{:keys [preview-url collection-data ownership collectible-data] :as collectible} index address
|
||||
on-press on-long-press]
|
||||
(let [total-owned (utils/total-owned-collectible ownership address)]
|
||||
[quo/collectible-list-item
|
||||
{:type :card
|
||||
:image-src (:uri preview-url)
|
||||
:avatar-image-src (:image-url collection-data)
|
||||
:collectible-name (:name collection-data)
|
||||
:supported-file? (utils/supported-file? (:animation-media-type collectible-data))
|
||||
:gradient-color-index (keyword (str "gradient-" (inc (mod index 5))))
|
||||
:counter (utils/collectible-owned-counter total-owned)
|
||||
:container-style {:padding 8
|
||||
:width "50%"}
|
||||
:on-press #(when on-press
|
||||
(on-press collectible))
|
||||
:on-long-press #(when on-long-press
|
||||
(on-long-press collectible))}]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [theme collectibles filtered? on-collectible-press on-collectible-long-press on-end-reached]}]
|
||||
[{:keys [theme collectibles filtered? on-collectible-press on-end-reached current-account-address
|
||||
on-collectible-long-press]}]
|
||||
(let [no-results-match-query? (and filtered? (empty? collectibles))]
|
||||
(cond
|
||||
no-results-match-query?
|
||||
@@ -28,16 +49,15 @@
|
||||
[rn/flat-list
|
||||
{:data collectibles
|
||||
:style {:flex 1}
|
||||
:content-container-style {:align-items :center}
|
||||
:content-container-style {:margin-horizontal 12}
|
||||
:window-size 11
|
||||
:num-columns 2
|
||||
:render-fn (fn [{:keys [preview-url] :as collectible}]
|
||||
[quo/collectible
|
||||
{:images [preview-url]
|
||||
:on-press #(when on-collectible-press
|
||||
(on-collectible-press collectible))
|
||||
:on-long-press #(when on-collectible-long-press
|
||||
(on-collectible-long-press collectible))}])
|
||||
:render-fn (fn [item index]
|
||||
(render-fn item
|
||||
index
|
||||
current-account-address
|
||||
on-collectible-press
|
||||
on-collectible-long-press))
|
||||
:on-end-reached on-end-reached
|
||||
:on-end-reached-threshold 4}])))
|
||||
|
||||
|
||||
@@ -1,52 +1,80 @@
|
||||
(ns status-im.contexts.wallet.common.token-value.view
|
||||
(:require [quo.core :as quo]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- action-buy
|
||||
[]
|
||||
{:icon :i/buy
|
||||
:accessibility-label :buy
|
||||
:label (i18n/label :t/buy)
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:right-icon :i/external})
|
||||
|
||||
(defn- action-send
|
||||
[token-data]
|
||||
{:icon :i/send
|
||||
:accessibility-label :send
|
||||
:label (i18n/label :t/send)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/send-select-token
|
||||
{:token token-data
|
||||
:start-flow? true}]))})
|
||||
|
||||
(defn- action-receive
|
||||
[]
|
||||
{:icon :i/receive
|
||||
:accessibility-label :receive
|
||||
:label (i18n/label :t/receive)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/wallet.share-address {:status :receive}])})
|
||||
|
||||
(defn- action-bridge
|
||||
[]
|
||||
{:icon :i/bridge
|
||||
:accessibility-label :bridge
|
||||
:label (i18n/label :t/bridge)
|
||||
:on-press #(js/alert "to be implemented")})
|
||||
|
||||
(defn- action-manage-tokens
|
||||
[watch-only?]
|
||||
{:icon :i/settings
|
||||
:accessibility-label :settings
|
||||
:label (i18n/label :t/manage-tokens)
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:add-divider? (not watch-only?)})
|
||||
|
||||
(defn- action-hide
|
||||
[]
|
||||
{:icon :i/hide
|
||||
:accessibility-label :hide
|
||||
:label (i18n/label :t/hide)
|
||||
:on-press #(js/alert "to be implemented")})
|
||||
|
||||
(defn token-value-drawer
|
||||
[token]
|
||||
[token watch-only?]
|
||||
(let [token-data (first (rf/sub [:wallet/current-viewing-account-tokens-filtered (:token token)]))]
|
||||
[:<>
|
||||
[quo/action-drawer
|
||||
[[{:icon :i/buy
|
||||
:accessibility-label :buy
|
||||
:label (i18n/label :t/buy)
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:right-icon :i/external}
|
||||
{:icon :i/send
|
||||
:accessibility-label :send
|
||||
:label (i18n/label :t/send)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:wallet/send-select-token
|
||||
{:token token-data
|
||||
:start-flow? true}]))}
|
||||
{:icon :i/receive
|
||||
:accessibility-label :receive
|
||||
:label (i18n/label :t/receive)
|
||||
:on-press #(js/alert "to be implemented")}
|
||||
{:icon :i/bridge
|
||||
:accessibility-label :bridge
|
||||
:label (i18n/label :t/bridge)
|
||||
:on-press #(js/alert "to be implemented")}
|
||||
{:icon :i/settings
|
||||
:accessibility-label :settings
|
||||
:label (i18n/label :t/manage-tokens)
|
||||
:on-press #(js/alert "to be implemented")
|
||||
:add-divider? true}
|
||||
{:icon :i/hide
|
||||
:accessibility-label :hide
|
||||
:label (i18n/label :t/hide)
|
||||
:on-press #(js/alert "to be implemented")}]]]]))
|
||||
[quo/action-drawer
|
||||
[(cond->> [(when (ff/enabled? ::ff/wallet.assets-modal-manage-tokens)
|
||||
(action-manage-tokens watch-only?))
|
||||
(when (ff/enabled? ::ff/wallet.assets-modal-hide)
|
||||
(action-hide))]
|
||||
(not watch-only?) (concat [(action-buy)
|
||||
(action-send token-data)
|
||||
(action-receive)
|
||||
(action-bridge)]))]]))
|
||||
|
||||
(defn view
|
||||
[item _ _ {:keys [watch-only?]}]
|
||||
[quo/token-value
|
||||
(cond-> item
|
||||
(not watch-only?)
|
||||
(or (not watch-only?) (ff/enabled? ::ff/wallet.long-press-watch-only-asset))
|
||||
(assoc :on-long-press
|
||||
#(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn [] [token-value-drawer item])
|
||||
{:content (fn [] [token-value-drawer item watch-only?])
|
||||
:selected-item (fn [] [quo/token-value item])}])))])
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
(ns status-im.contexts.wallet.common.utils.networks
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]))
|
||||
|
||||
(defn resolve-receiver-networks
|
||||
[{:keys [prefix testnet-enabled? goerli-enabled?]}]
|
||||
(let [prefix (if (string/blank? prefix)
|
||||
constants/default-multichain-address-prefix
|
||||
prefix)
|
||||
prefix-seq (string/split prefix #":")]
|
||||
(->> prefix-seq
|
||||
(remove string/blank?)
|
||||
(mapv
|
||||
#(utils/network->chain-id
|
||||
{:network %
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})))))
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.wallet.common.utils.send
|
||||
(:require [utils.money :as money]))
|
||||
(:require [clojure.string :as string]
|
||||
[utils.money :as money]))
|
||||
|
||||
(defn calculate-gas-fee
|
||||
[data]
|
||||
@@ -20,3 +21,17 @@
|
||||
(defn calculate-full-route-gas-fee
|
||||
[route]
|
||||
(reduce money/add (map calculate-gas-fee route)))
|
||||
|
||||
(defn find-affordable-networks
|
||||
[{:keys [balances-per-chain input-value selected-networks disabled-chain-ids]}]
|
||||
(let [input-value (if (string/blank? input-value) 0 input-value)]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_
|
||||
{:keys [balance chain-id]
|
||||
:or {balance 0}}]]
|
||||
(and
|
||||
(money/greater-than-or-equals (money/bignumber balance)
|
||||
(money/bignumber input-value))
|
||||
(some #(= % chain-id) selected-networks)
|
||||
(not-any? #(= % chain-id) disabled-chain-ids))))
|
||||
(map first))))
|
||||
|
||||
@@ -20,3 +20,44 @@
|
||||
expected-eip1559-disabled-result (money/bignumber 0.000760406)]
|
||||
(is (money/equal-to (utils/calculate-gas-fee data-eip1559-disabled)
|
||||
expected-eip1559-disabled-result))))))
|
||||
|
||||
(deftest test-find-affordable-networks
|
||||
(testing "All networks affordable and selected, none disabled"
|
||||
(let [balances-per-chain {"1" {:balance "50.0" :chain-id "1"}
|
||||
"2" {:balance "40.0" :chain-id "2"}}
|
||||
input-value 20
|
||||
selected-networks ["1" "2"]
|
||||
disabled-chain-ids []
|
||||
expected ["1" "2"]]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected)))))
|
||||
|
||||
(testing "No networks affordable"
|
||||
(let [balances-per-chain {"1" {:balance "5.0" :chain-id "1"}
|
||||
"2" {:balance "1.0" :chain-id "2"}}
|
||||
input-value 10
|
||||
selected-networks ["1" "2"]
|
||||
disabled-chain-ids []
|
||||
expected []]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected)))))
|
||||
|
||||
(testing "Selected networks subset, with some disabled"
|
||||
(let [balances-per-chain {"1" {:balance "100.0" :chain-id "1"}
|
||||
"2" {:balance "50.0" :chain-id "2"}
|
||||
"3" {:balance "20.0" :chain-id "3"}}
|
||||
input-value 15
|
||||
selected-networks ["1" "2" "3"]
|
||||
disabled-chain-ids ["2"]
|
||||
expected ["1" "3"]]
|
||||
(is (= (set (utils/find-affordable-networks {:balances-per-chain balances-per-chain
|
||||
:input-value input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-chain-ids}))
|
||||
(set expected))))))
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.share :as share]))
|
||||
|
||||
(rf/reg-fx :effects.share/open
|
||||
(fn [content]
|
||||
(share/open content)))
|
||||
[re-frame.core :as rf]))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet/create-account-from-mnemonic
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.wallet.events
|
||||
(:require
|
||||
[camel-snake-kebab.extras :as cske]
|
||||
[clojure.string :as string]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[react-native.platform :as platform]
|
||||
@@ -10,6 +11,7 @@
|
||||
[status-im.contexts.wallet.item-types :as item-types]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.collection]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.number]
|
||||
@@ -63,6 +65,7 @@
|
||||
(utils.collection/index-by :address (data-store/rpc->accounts wallet-accounts)))
|
||||
:fx [[:dispatch [:wallet/get-wallet-token]]
|
||||
[:dispatch [:wallet/request-collectibles-for-all-accounts {:new-request? true}]]
|
||||
[:dispatch [:wallet/check-recent-history]]
|
||||
(when new-account?
|
||||
[:dispatch [:wallet/navigate-to-new-account navigate-to-account]])]})))
|
||||
|
||||
@@ -148,7 +151,7 @@
|
||||
(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 (accounts address)
|
||||
(if (contains? accounts address)
|
||||
(update accounts address assoc :tokens tokens-data)
|
||||
accounts))
|
||||
stored-accounts
|
||||
@@ -392,6 +395,20 @@
|
||||
{:error %
|
||||
:event :wallet/start-wallet})}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/check-recent-history
|
||||
(fn [{:keys [db]}]
|
||||
(let [addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
(map :address))
|
||||
chain-ids (chain/chain-ids db)]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_checkRecentHistoryForChainIDs"
|
||||
:params [chain-ids addresses]
|
||||
:on-error #(log/info "failed to check recent history"
|
||||
{:error %
|
||||
:event :wallet/check-recent-history})}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/initialize
|
||||
(fn []
|
||||
{:fx [[:dispatch [:wallet/start-wallet]]
|
||||
@@ -402,16 +419,16 @@
|
||||
(rf/reg-event-fx :wallet/share-account
|
||||
(fn [_ [{:keys [content title]}]]
|
||||
{:fx [[:effects.share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources
|
||||
[{:placeholderItem {:type "text"
|
||||
:content content}
|
||||
:item {:default {:type "text"
|
||||
:content content}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message content})]]}))
|
||||
{:options (if platform/ios?
|
||||
{:activityItemSources
|
||||
[{:placeholderItem {:type :text
|
||||
:content content}
|
||||
:item {:default {:type :text
|
||||
:content content}}
|
||||
:linkMetadata {:title title}}]}
|
||||
{:title title
|
||||
:subject title
|
||||
:message content})}]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/blockchain-status-changed
|
||||
@@ -477,3 +494,45 @@
|
||||
{:db (update-in db [:wallet :ui :network-filter :selected-networks] update-fn network-name)})))
|
||||
|
||||
(rf/reg-event-fx :wallet/update-selected-networks update-selected-networks)
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/fetch-activities
|
||||
(fn [{:keys [db]}]
|
||||
(let [addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
(map :address))
|
||||
chain-ids (chain/chain-ids db)
|
||||
request-id 0
|
||||
filters {:period {:startTimestamp 0
|
||||
:endTimestamp 0}
|
||||
:types []
|
||||
:statuses []
|
||||
:counterpartyAddresses []
|
||||
:assets []
|
||||
:collectibles []
|
||||
:filterOutAssets false
|
||||
:filterOutCollectibles false}
|
||||
offset 0
|
||||
limit 20
|
||||
request-params [request-id
|
||||
addresses
|
||||
chain-ids
|
||||
filters
|
||||
offset
|
||||
limit]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{;; This method is deprecated and will be replaced by
|
||||
;; "wallet_startActivityFilterSession"
|
||||
:method "wallet_filterActivityAsync"
|
||||
:params request-params
|
||||
:on-error #(log/info "failed to fetch activities"
|
||||
{:error %
|
||||
:event :wallet/fetch-activities})}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/activity-filtering-done
|
||||
(fn [{:keys [db]} [{:keys [message]}]]
|
||||
(let [{:keys [activities]} (transforms/json->clj message)
|
||||
activities (cske/transform-keys transforms/->kebab-case-keyword activities)
|
||||
sorted-activities (sort :timestamp activities)]
|
||||
{:db (assoc-in db [:wallet :activities] sorted-activities)})))
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
|
||||
(defn home-container
|
||||
[]
|
||||
{:margin-top (safe-area/get-top)
|
||||
{:margin-top (+ (safe-area/get-top) 8)
|
||||
:flex 1})
|
||||
|
||||
@@ -34,4 +34,4 @@
|
||||
:on-end-reached request-collectibles
|
||||
:on-collectible-press (fn [{:keys [id]}]
|
||||
(rf/dispatch [:wallet/get-collectible-details id]))}]
|
||||
[activity/view])]))
|
||||
[activity/view {:activities []}])]))
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[status-im.contexts.wallet.home.style :as style]
|
||||
[status-im.contexts.wallet.home.tabs.view :as tabs]
|
||||
[status-im.contexts.wallet.sheets.network-filter.view :as network-filter]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -76,5 +77,9 @@
|
||||
:size 32
|
||||
:default-active selected-tab
|
||||
:data tabs-data
|
||||
:on-change #(set-selected-tab %)}]
|
||||
:on-change (fn [tab]
|
||||
(when (and (ff/enabled? ::ff/wallet.activities)
|
||||
(= :activity tab))
|
||||
(rf/dispatch [:wallet/fetch-activities]))
|
||||
(set-selected-tab tab))}]
|
||||
[tabs/view {:selected-tab selected-tab}]]))
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[native-module.core :as native-module]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
@@ -24,45 +25,71 @@
|
||||
(rf/reg-event-fx :wallet/suggested-routes-success
|
||||
(fn [{:keys [db]} [suggested-routes timestamp]]
|
||||
(when (= (get-in db [:wallet :ui :send :suggested-routes-call-timestamp]) timestamp)
|
||||
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword suggested-routes)
|
||||
chosen-route (:best suggested-routes-data)]
|
||||
(let [suggested-routes-data (cske/transform-keys transforms/->kebab-case-keyword
|
||||
suggested-routes)
|
||||
chosen-route (:best suggested-routes-data)
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
token-display-name (get-in db [:wallet :ui :send :token-display-name])
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? false})
|
||||
from-network-values-for-ui (send-utils/network-values-for-ui from-network-amounts-by-chain)
|
||||
to-network-amounts-by-chain (send-utils/network-amounts-by-chain {:route chosen-route
|
||||
:token-decimals
|
||||
token-decimals
|
||||
:native-token?
|
||||
native-token?
|
||||
:to? true})
|
||||
to-network-values-for-ui (send-utils/network-values-for-ui to-network-amounts-by-chain)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] suggested-routes-data)
|
||||
(assoc-in [:wallet :ui :send :route] chosen-route)
|
||||
(assoc-in [:wallet :ui :send :from-values-by-chain] from-network-values-for-ui)
|
||||
(assoc-in [:wallet :ui :send :to-values-by-chain] to-network-values-for-ui)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-error
|
||||
(fn [{:keys [db]} [_error]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes :route)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-suggested-routes
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :suggested-routes)
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send] dissoc :loading-suggested-routes?))}))
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
dissoc
|
||||
:suggested-routes
|
||||
:route
|
||||
:from-values-by-chain
|
||||
:to-values-by-chain
|
||||
:loading-suggested-routes?
|
||||
:suggested-routes-call-timestamp)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-address
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :recipient :to-address)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-disabled-from-networks
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :disabled-from-chain-ids)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/select-send-address
|
||||
(fn [{:keys [db]} [{:keys [address recipient stack-id start-flow?]}]]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)
|
||||
testnet-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
goerli-enabled? (get-in db [:profile/profile :is-goerli-enabled?])
|
||||
prefix-seq (string/split prefix #":")
|
||||
selected-networks (->> prefix-seq
|
||||
(remove string/blank?)
|
||||
(mapv
|
||||
#(utils/network->chain-id
|
||||
{:network %
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})))]
|
||||
selected-networks (network-utils/resolve-receiver-networks
|
||||
{:prefix prefix
|
||||
:testnet-enabled? testnet-enabled?
|
||||
:goerli-enabled? goerli-enabled?})]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] to-address)
|
||||
@@ -84,7 +111,8 @@
|
||||
(fn [{:keys [db]} [{:keys [token stack-id start-flow?]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :collectible)
|
||||
(assoc-in [:wallet :ui :send :token] token))
|
||||
(assoc-in [:wallet :ui :send :token] token)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] (:symbol token)))
|
||||
:fx [[:dispatch [:wallet/clean-suggested-routes]]
|
||||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
@@ -95,13 +123,15 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/edit-token-to-send
|
||||
(fn [{:keys [db]} [token]]
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :token] token)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] token))
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:wallet/clean-suggested-routes]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-selected-token
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :token :tx-type)}))
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :token :token-display-name :tx-type)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-selected-collectible
|
||||
(fn [{:keys [db]}]
|
||||
@@ -110,18 +140,30 @@
|
||||
[:wallet :ui :send]
|
||||
dissoc
|
||||
:collectible
|
||||
:token-display-name
|
||||
:amount
|
||||
(when (= transaction-type :collecible) :tx-type))})))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id amount]}]]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]}))
|
||||
(let [collection-data (:collection-data collectible)
|
||||
collectible-data (:collectible-data collectible)
|
||||
collectible-id (get-in collectible [:id :token-id])
|
||||
token-display-name (cond
|
||||
(and collectible
|
||||
(not (string/blank? (:name collectible-data))))
|
||||
(:name collectible-data)
|
||||
|
||||
collectible
|
||||
(str (:name collection-data) " #" collectible-id))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :token)
|
||||
(assoc-in [:wallet :ui :send :collectible] collectible)
|
||||
(assoc-in [:wallet :ui :send :token-display-name] token-display-name)
|
||||
(assoc-in [:wallet :ui :send :tx-type] :collectible)
|
||||
(assoc-in [:wallet :ui :send :amount] amount))
|
||||
:fx [[:dispatch [:wallet/get-suggested-routes {:amount amount}]]
|
||||
[:navigate-to-within-stack [:screen/wallet.transaction-confirmation stack-id]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/select-collectibles-amount
|
||||
(fn [{:keys [db]} [{:keys [collectible stack-id]}]]
|
||||
@@ -140,6 +182,12 @@
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-flow}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/disable-from-networks
|
||||
(fn [{:keys [db]} [chain-ids]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :disabled-from-chain-ids] chain-ids)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] true))}))
|
||||
|
||||
(rf/reg-event-fx :wallet/get-suggested-routes
|
||||
(fn [{:keys [db now]} [{:keys [amount]}]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
@@ -147,6 +195,7 @@
|
||||
transaction-type (get-in db [:wallet :ui :send :tx-type])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
disabled-from-chain-ids (or (get-in db [:wallet :ui :send :disabled-from-chain-ids]) [])
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks ((if test-networks-enabled? :test :prod)
|
||||
(get-in db [:wallet :networks]))
|
||||
@@ -163,7 +212,7 @@
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in (send-utils/amount-in-hex amount (if token token-decimal 0))
|
||||
from-address wallet-address
|
||||
disabled-from-chain-ids []
|
||||
disabled-from-chain-ids disabled-from-chain-ids
|
||||
disabled-to-chain-ids (if (= transaction-type :bridge)
|
||||
(filter #(not= % bridge-to-chain-id) network-chain-ids)
|
||||
[])
|
||||
@@ -218,6 +267,7 @@
|
||||
{:fx [[:dispatch [:wallet/clean-scanned-address]]
|
||||
[:dispatch [:wallet/clean-local-suggestions]]
|
||||
[:dispatch [:wallet/clean-send-address]]
|
||||
[:dispatch [:wallet/clean-disabled-from-networks]]
|
||||
[:dispatch [:wallet/select-address-tab nil]]
|
||||
[:dispatch [:dismiss-modal :screen/wallet.transaction-progress]]]}))
|
||||
|
||||
|
||||
@@ -5,60 +5,75 @@
|
||||
[status-im.contexts.wallet.send.input-amount.view :as input-amount]
|
||||
[test-helpers.component :as h]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(set! rf/dispatch #())
|
||||
(set! debounce/debounce-and-dispatch #())
|
||||
|
||||
(def sub-mocks
|
||||
{:profile/profile {:currency :usd}
|
||||
:wallet/selected-network-details [{:source 525
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]
|
||||
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
|
||||
:emoji "💎"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:watch-only? false
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :purple
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:network-preferences-names #{:mainnet :arbitrum
|
||||
:optimism}
|
||||
:position 1
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false}
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route [{:from {:chainid 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:to {:chain-id 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:gas-amount "23487"
|
||||
:gas-fees {:base-fee "32.325296406"
|
||||
:max-priority-fee-per-gas "0.011000001"
|
||||
:eip1559-enabled true}}]
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}
|
||||
:wallet/wallet-send-selected-networks []
|
||||
:view-id :screen/wallet.send-input-amount
|
||||
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
|
||||
:profile/currency-symbol "$"
|
||||
:wallet/token-by-symbol {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}})
|
||||
{:profile/profile {:currency :usd}
|
||||
:wallet/selected-network-details [{:source 525
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:chain-id 1
|
||||
:related-chain-id 5}]
|
||||
:wallet/current-viewing-account {:path "m/44'/60'/0'/0/1"
|
||||
:emoji "💎"
|
||||
:key-uid "0x2f5ea39"
|
||||
:address "0x1"
|
||||
:wallet false
|
||||
:name "Account One"
|
||||
:type :generated
|
||||
:watch-only? false
|
||||
:chat false
|
||||
:test-preferred-chain-ids #{5 420 421613}
|
||||
:color :purple
|
||||
:hidden false
|
||||
:prod-preferred-chain-ids #{1 10 42161}
|
||||
:network-preferences-names #{:mainnet :arbitrum
|
||||
:optimism}
|
||||
:position 1
|
||||
:clock 1698945829328
|
||||
:created-at 1698928839000
|
||||
:operable "fully"
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
:removed false}
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:networks [{:source 879
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:abbreviated-name "Eth."
|
||||
:chain-id 1
|
||||
:related-chain-id 1
|
||||
:layer 1}]}
|
||||
:wallet/current-viewing-account-tokens-filtered {:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route [{:from {:chainid 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:to {:chain-id 1
|
||||
:native-currency-symbol "ETH"}
|
||||
:gas-amount "23487"
|
||||
:gas-fees {:base-fee "32.325296406"
|
||||
:max-priority-fee-per-gas "0.011000001"
|
||||
:eip1559-enabled true}}]
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}
|
||||
:wallet/wallet-send-selected-networks [1]
|
||||
:view-id :screen/wallet.send-input-amount
|
||||
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
|
||||
:profile/currency-symbol "$"
|
||||
:wallet/token-by-symbol {:symbol :eth
|
||||
:total-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-disabled-from-chain-ids []
|
||||
:wallet/wallet-send-from-values-by-chain {1 (money/bignumber "250")}
|
||||
:wallet/wallet-send-to-values-by-chain {1 (money/bignumber "250")}})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
||||
@@ -190,8 +190,9 @@
|
||||
(reset-input-error num-value current-limit-amount input-error)
|
||||
(reagent/flush))))
|
||||
on-navigate-back on-navigate-back
|
||||
fetch-routes (fn [input-num-value current-limit-amount]
|
||||
(let [nav-current-screen-id (rf/sub [:view-id])]
|
||||
fetch-routes (fn [input-num-value current-limit-amount bounce-duration-ms]
|
||||
(let [nav-current-screen-id (rf/sub [:view-id])
|
||||
input-num-value (or input-num-value 0)]
|
||||
; this check is to prevent effect being triggered when screen is
|
||||
; loaded but not being shown to the user (deep in the navigation
|
||||
; stack) and avoid undesired behaviors
|
||||
@@ -201,7 +202,7 @@
|
||||
(> input-num-value current-limit-amount))
|
||||
(debounce/debounce-and-dispatch
|
||||
[:wallet/get-suggested-routes {:amount @input-value}]
|
||||
2000)
|
||||
bounce-duration-ms)
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])))))
|
||||
handle-on-confirm (fn []
|
||||
(rf/dispatch [:wallet/send-select-amount
|
||||
@@ -215,65 +216,92 @@
|
||||
(reset! input-selection selection)
|
||||
(reagent/flush))]
|
||||
(fn []
|
||||
(let [{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-balance :total-balance
|
||||
token-symbol :symbol
|
||||
token-networks :networks
|
||||
:as token} (rf/sub [:wallet/wallet-send-token])
|
||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||
loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
best-routes (when suggested-routes (or (:best suggested-routes) []))
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
to-address (rf/sub [:wallet/wallet-send-to-address])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or default-crypto-decimals
|
||||
(utils/get-crypto-decimals-count token))
|
||||
crypto-limit (or default-limit-crypto
|
||||
(utils/get-standard-crypto-format token token-balance))
|
||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||
limit-label (make-limit-label {:amount (current-limit)
|
||||
:currency current-currency})
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (current-limit)))
|
||||
amount-text (str @input-value " " token-symbol)
|
||||
native-currency-symbol (when-not confirm-disabled?
|
||||
(get-in route [:from :native-currency-symbol]))
|
||||
native-token (when native-currency-symbol
|
||||
(rf/sub [:wallet/token-by-symbol native-currency-symbol]))
|
||||
fee-in-native-token (when-not confirm-disabled?
|
||||
(send-utils/calculate-full-route-gas-fee route))
|
||||
fee-in-crypto-formatted (when fee-in-native-token
|
||||
(utils/get-standard-crypto-format native-token
|
||||
fee-in-native-token))
|
||||
fee-in-fiat (when-not confirm-disabled?
|
||||
(utils/calculate-token-fiat-value
|
||||
{:currency fiat-currency
|
||||
:balance fee-in-native-token
|
||||
:token native-token}))
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
fee-formatted (when fee-in-fiat
|
||||
(utils/get-standard-fiat-format fee-in-crypto-formatted
|
||||
currency-symbol
|
||||
fee-in-fiat))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet clear-input!])}])]
|
||||
(let [{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-symbol :symbol
|
||||
token-networks :networks} (rf/sub [:wallet/wallet-send-token])
|
||||
{token-balance :total-balance
|
||||
token-balances-per-chain :balances-per-chain
|
||||
:as
|
||||
token} (rf/sub
|
||||
[:wallet/current-viewing-account-tokens-filtered
|
||||
(str token-symbol)])
|
||||
conversion-rate (-> token :market-values-per-currency :usd :price)
|
||||
loading-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
best-routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
to-address (rf/sub [:wallet/wallet-send-to-address])
|
||||
disabled-from-chain-ids (rf/sub
|
||||
[:wallet/wallet-send-disabled-from-chain-ids])
|
||||
from-values-by-chain (rf/sub [:wallet/wallet-send-from-values-by-chain])
|
||||
to-values-by-chain (rf/sub [:wallet/wallet-send-to-values-by-chain])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or default-crypto-decimals
|
||||
(utils/get-crypto-decimals-count token))
|
||||
crypto-limit (or default-limit-crypto
|
||||
(utils/get-standard-crypto-format
|
||||
token
|
||||
token-balance))
|
||||
fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit #(if @crypto-currency? crypto-limit fiat-limit)
|
||||
current-currency (if @crypto-currency? token-symbol fiat-currency)
|
||||
limit-label (make-limit-label {:amount (current-limit)
|
||||
:currency current-currency})
|
||||
input-num-value (parse-double @input-value)
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (current-limit)))
|
||||
amount-text (str @input-value " " token-symbol)
|
||||
native-currency-symbol (when-not confirm-disabled?
|
||||
(get-in route [:from :native-currency-symbol]))
|
||||
native-token (when native-currency-symbol
|
||||
(rf/sub [:wallet/token-by-symbol
|
||||
native-currency-symbol]))
|
||||
fee-in-native-token (when-not confirm-disabled?
|
||||
(send-utils/calculate-full-route-gas-fee route))
|
||||
fee-in-crypto-formatted (when fee-in-native-token
|
||||
(utils/get-standard-crypto-format
|
||||
native-token
|
||||
fee-in-native-token))
|
||||
fee-in-fiat (when-not confirm-disabled?
|
||||
(utils/calculate-token-fiat-value
|
||||
{:currency fiat-currency
|
||||
:balance fee-in-native-token
|
||||
:token native-token}))
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
fee-formatted (when fee-in-fiat
|
||||
(utils/get-standard-fiat-format
|
||||
fee-in-crypto-formatted
|
||||
currency-symbol
|
||||
fee-in-fiat))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
affordable-networks (send-utils/find-affordable-networks
|
||||
{:balances-per-chain token-balances-per-chain
|
||||
:input-value @input-value
|
||||
:selected-networks selected-networks
|
||||
:disabled-chain-ids disabled-from-chain-ids})]
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||
#(.remove app-keyboard-listener))))
|
||||
(rn/use-effect
|
||||
#(fetch-routes input-num-value (current-limit))
|
||||
#(when (> (count affordable-networks) 0)
|
||||
(fetch-routes input-num-value (current-limit) 2000))
|
||||
[@input-value])
|
||||
(rn/use-effect
|
||||
#(when (> (count affordable-networks) 0)
|
||||
(fetch-routes input-num-value (current-limit) 0))
|
||||
[disabled-from-chain-ids])
|
||||
[rn/view
|
||||
{:style style/screen
|
||||
:accessibility-label (str "container" (when @input-error "-error"))}
|
||||
@@ -303,11 +331,28 @@
|
||||
:limit-crypto crypto-limit})
|
||||
:on-token-press show-select-asset-sheet}]
|
||||
[routes/view
|
||||
{:amount amount-text
|
||||
:routes best-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes #(fetch-routes % (current-limit))}]
|
||||
{:from-values-by-chain from-values-by-chain
|
||||
:to-values-by-chain to-values-by-chain
|
||||
:affordable-networks affordable-networks
|
||||
:routes best-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes #(fetch-routes % (current-limit) 2000)
|
||||
:disabled-from-networks disabled-from-chain-ids
|
||||
:on-press-from-network (fn [chain-id _]
|
||||
(let [disabled-chain-ids (if (contains? (set
|
||||
disabled-from-chain-ids)
|
||||
chain-id)
|
||||
(vec (remove #(= % chain-id)
|
||||
disabled-from-chain-ids))
|
||||
(conj disabled-from-chain-ids
|
||||
chain-id))
|
||||
re-enabling-chain? (< (count disabled-chain-ids)
|
||||
(count disabled-from-chain-ids))]
|
||||
(when (or re-enabling-chain?
|
||||
(> (count affordable-networks) 1))
|
||||
(rf/dispatch [:wallet/disable-from-networks
|
||||
disabled-chain-ids]))))}]
|
||||
(when (or loading-routes? (seq route))
|
||||
[estimated-fees
|
||||
{:loading-suggested-routes? loading-routes?
|
||||
|
||||
@@ -12,20 +12,23 @@
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(def routes-inner-container
|
||||
{:margin-top 8
|
||||
(defn routes-inner-container
|
||||
[first-item?]
|
||||
{:margin-top (if first-item? 7.5 11)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between})
|
||||
|
||||
(defn section-label
|
||||
[margin-left]
|
||||
{:flex 0.5
|
||||
:margin-left margin-left})
|
||||
(def section-label-right
|
||||
{:width 135})
|
||||
|
||||
(def section-label-left
|
||||
{:width 136})
|
||||
|
||||
(def network-link
|
||||
{:right 6
|
||||
:z-index 1})
|
||||
{:margin-horizontal -1.5
|
||||
:z-index 1
|
||||
:flex 1})
|
||||
|
||||
(def empty-container
|
||||
{:flex-grow 1
|
||||
@@ -33,9 +36,8 @@
|
||||
:justify-content :center})
|
||||
|
||||
(def add-network
|
||||
{:margin-top 8
|
||||
:align-self :flex-end
|
||||
:right 12})
|
||||
{:margin-top 11
|
||||
:align-self :flex-end})
|
||||
|
||||
(defn warning-container
|
||||
[color theme]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user