Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f6b42c844 | ||
|
|
c53bbc74e1 |
@@ -14,25 +14,14 @@ This step will take a while the first time as it will download all dependencies.
|
||||
|
||||
There are three steps necessary to start development, in this case for Android:
|
||||
|
||||
1. `make run-clojure` - Compiles Clojure into JavaScript, watches for changes on cljs files, and hot-reloads code in the app.
|
||||
2. `make run-metro` - Starts metro bundler and watches JavaScript code.
|
||||
3. `make run-android` or `make run-ios` - Builds the Android/iOS app and starts it on the device.
|
||||
1. `make run-clojure` - Compiles Clojure into JavaScript, watches for changes on cljs files, and hot-reloads code in the app
|
||||
2. `make run-metro` - Starts metro bundler and watches JavaScript code
|
||||
3. `make run-android` - Builds the Android app and starts it on the device
|
||||
|
||||
The first two will continue watching for changes and keep re-building the app. They need to be ready first.
|
||||
The last one will exit once the app is up and ready.
|
||||
|
||||
## Simulators and Devices
|
||||
### Android
|
||||
|
||||
You need to have an emulator like [AVD](https://developer.android.com/studio/run/emulator), or [Genymotion](#genymotion-virtualization), or a real device running and visible to [adb](https://developer.android.com/studio/command-line/adb), before you run `make run-android`.
|
||||
|
||||
### iOS
|
||||
|
||||
You can specify the simulator type by adding the `SIMULATOR` flag:
|
||||
```sh
|
||||
make run-ios SIMULATOR="iPhone 11 Pro"
|
||||
```
|
||||
Some manual steps are necesary for [developing on a physical iOS Device](#physical-ios-device).
|
||||
You need to have your emulator or real devices running and visible to adb, before you run `make run-android`.
|
||||
|
||||
# Build release
|
||||
|
||||
@@ -82,17 +71,3 @@ Steps:
|
||||
2. [Setup Git to use your GPG key](https://help.github.com/en/github/authenticating-to-github/telling-git-about-your-signing-key)
|
||||
3. [Setup Git to sign commits](https://help.github.com/en/github/authenticating-to-github/signing-commits)
|
||||
4. [Setup GitHub to validate commits](https://help.github.com/en/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account)
|
||||
|
||||
## Physical iOS Device
|
||||
|
||||
To use a physical iPhone your device UDID must be added to provisioning profiles and your Apple account invited as Developer to Status team.
|
||||
|
||||
1. [Get your UDID of your iPhone.](https://www.extentia.com/post/finding-the-udid-of-an-ios-device)
|
||||
2. Request from someone with access like @cammellos or @jakubgs to
|
||||
- Add the UDID to development devices on Apple Developer Portal.
|
||||
- Invite your Apple account to be Developer in Status team.
|
||||
3. Run a build in XCode using the project from `status-mobile/ios` directory.
|
||||
- You might see error: `Select a development team in the Signing & Capabilities editor`
|
||||
- Select `STATUS HOLDINGS PTE. LTD.` as the development team and rebuild again.
|
||||
|
||||
Once build finishes Status should start on your iPhone with its logs in terminal running `make run-metro`.
|
||||
|
||||
@@ -238,7 +238,7 @@ PODS:
|
||||
- React
|
||||
- react-native-status (1.0.0):
|
||||
- React
|
||||
- react-native-status-keycard (2.5.38):
|
||||
- react-native-status-keycard (2.5.37):
|
||||
- Keycard
|
||||
- React
|
||||
- react-native-webview (11.16.0):
|
||||
@@ -640,7 +640,7 @@ SPEC CHECKSUMS:
|
||||
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
||||
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 36ce0530c6d2c3a5a4326885ef4069564887a1db
|
||||
glog: 64a900d72fb14cd1b2cdf3b717a5555ceb889d49
|
||||
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
|
||||
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
|
||||
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
|
||||
@@ -671,7 +671,7 @@ SPEC CHECKSUMS:
|
||||
react-native-shake: de052eaa3eadc4a326b8ddd7ac80c06e8d84528c
|
||||
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
|
||||
react-native-status: 21f75d492fd311dc111303da38a7a2b23a8a8466
|
||||
react-native-status-keycard: f60ca57d789aad6875c64ece81ab06ef0609e0d3
|
||||
react-native-status-keycard: 961d01ca190889ddf220206822fd752f8f4f3f7a
|
||||
react-native-webview: 28a8636d97ee641f2ee8f20492d7a6c269c1d703
|
||||
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
|
||||
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
|
||||
|
||||
@@ -172,15 +172,12 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
|
||||
|
||||
NSURL *networkDir = [rootUrl URLByAppendingPathComponent:networkDirPath];
|
||||
NSURL *originalGethLogsFile = [networkDir URLByAppendingPathComponent:@"geth.log"];
|
||||
NSURL *gethLogsFile = [logsFolderName URLByAppendingPathComponent:@"mainnet_geth.log"];
|
||||
NSURL *gethLogsFile = [logsFolderName URLByAppendingPathComponent:@"geth.log"];
|
||||
|
||||
NSURL *goerliNetworkDir = [rootUrl URLByAppendingPathComponent:goerliNetworkDirPath];
|
||||
NSURL *goerliGethLogsFile = [goerliNetworkDir URLByAppendingPathComponent:@"geth.log"];
|
||||
NSURL *goerliLogsFile = [logsFolderName URLByAppendingPathComponent:@"goerli_geth.log"];
|
||||
|
||||
NSURL *mainGethLogsFile = [rootUrl URLByAppendingPathComponent:@"geth.log"];
|
||||
NSURL *mainLogsFile = [logsFolderName URLByAppendingPathComponent:@"geth.log"];
|
||||
|
||||
[dbJson writeToFile:dbFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
[jsLogs writeToFile:jsLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
@@ -188,7 +185,6 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
|
||||
//[gethLogs writeToFile:gethLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
[fileManager copyItemAtPath:originalGethLogsFile.path toPath:gethLogsFile.path error:nil];
|
||||
[fileManager copyItemAtPath:goerliGethLogsFile.path toPath:goerliLogsFile.path error:nil];
|
||||
[fileManager copyItemAtPath:mainGethLogsFile.path toPath:mainLogsFile.path error:nil];
|
||||
|
||||
[SSZipArchive createZipFileAtPath:zipFile.path withContentsOfDirectory:logsFolderName.path];
|
||||
[fileManager removeItemAtPath:logsFolderName.path error:nil];
|
||||
@@ -426,10 +422,12 @@ RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
|
||||
NSString *relativeDataDir = [configJSON objectForKey:@"DataDir"];
|
||||
NSString *absDataDir = [rootUrl.path stringByAppendingString:relativeDataDir];
|
||||
NSURL *absDataDirUrl = [NSURL fileURLWithPath:absDataDir];
|
||||
NSURL *dataDirUrl = [NSURL fileURLWithPath:relativeDataDir];
|
||||
NSURL *logUrl = [dataDirUrl URLByAppendingPathComponent:@"geth.log"];
|
||||
NSString *keystoreDir = [@"/keystore/" stringByAppendingString:keyUID];
|
||||
[configJSON setValue:keystoreDir forKey:@"KeyStoreDir"];
|
||||
[configJSON setValue:@"" forKey:@"LogDir"];
|
||||
[configJSON setValue:@"geth.log" forKey:@"LogFile"];
|
||||
[configJSON setValue:logUrl.path forKey:@"LogFile"];
|
||||
|
||||
NSString *resultingConfig = [configJSON bv_jsonStringWithPrettyPrint:NO];
|
||||
NSLog(@"node config %@", resultingConfig);
|
||||
@@ -439,7 +437,7 @@ RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
|
||||
withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
NSLog(@"logUrlPath %@ rootDir %@", @"geth.log", rootUrl.path);
|
||||
NSLog(@"logUrlPath %@ rootDir %@", logUrl.path, rootUrl.path);
|
||||
NSURL *absLogUrl = [absDataDirUrl URLByAppendingPathComponent:@"geth.log"];
|
||||
if(![fileManager fileExistsAtPath:absLogUrl.path]) {
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
|
||||
@@ -27,11 +27,13 @@
|
||||
"@walletconnect/client": "^2.0.0-beta.23",
|
||||
"@walletconnect/client-legacy": "npm:@walletconnect/client@^1.7.1",
|
||||
"bignumber.js": "git+https://github.com/status-im/bignumber.js.git#refs/tags/v4.0.2-status",
|
||||
"buffer": "^5.4.2",
|
||||
"chance": "^1.1.0",
|
||||
"create-react-class": "^15.6.2",
|
||||
"emojilib": "^2.4.0",
|
||||
"eth-phishing-detect": "^1.2.0",
|
||||
"eth-phishing-detect": "^1.1.13",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"hi-base32": "^0.5.0",
|
||||
"i18n-js": "^3.3.0",
|
||||
"node-libs-react-native": "^1.2.1",
|
||||
"qrcode": "^1.4.1",
|
||||
@@ -71,6 +73,7 @@
|
||||
"react-native-touch-id": "^4.4.1",
|
||||
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",
|
||||
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#refs/tags/v0.4.3",
|
||||
"tdigest": "^0.1.1",
|
||||
"web3-utils": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
|
Before Width: | Height: | Size: 321 B |
|
Before Width: | Height: | Size: 373 B |
|
Before Width: | Height: | Size: 307 B |
|
Before Width: | Height: | Size: 387 B |
|
Before Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 673 B |
|
Before Width: | Height: | Size: 681 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 667 B |
|
Before Width: | Height: | Size: 940 B |
|
Before Width: | Height: | Size: 371 B |
|
Before Width: | Height: | Size: 509 B |
|
Before Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 892 B |
|
Before Width: | Height: | Size: 327 B |
|
Before Width: | Height: | Size: 440 B |
|
Before Width: | Height: | Size: 249 B |
|
Before Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
@@ -248,8 +248,6 @@
|
||||
|
||||
(def react-native-gradien #js {:default #js {}})
|
||||
|
||||
(def masked-view #js {:default #js {}})
|
||||
|
||||
(def react-native-permissions #js {:default #js {}})
|
||||
|
||||
(def push-notification-ios #js {:default #js {:abandonPermissions identity}})
|
||||
@@ -310,7 +308,6 @@
|
||||
"react-native-device-info" react-native-device-info
|
||||
"react-native-push-notification" react-native-push-notification
|
||||
"react-native-linear-gradient" react-native-gradien
|
||||
"@react-native-community/masked-view" masked-view
|
||||
"react-native-blob-util" react-native-blob-util
|
||||
"react-native-navigation" react-native-navigation
|
||||
"@react-native-community/push-notification-ios" push-notification-ios
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
:small 20})
|
||||
|
||||
(defn icon-avatar
|
||||
[{:keys [size icon color opacity]
|
||||
:or {opacity 20}}]
|
||||
[{:keys [size icon color]}]
|
||||
(let [component-size (size sizes)
|
||||
circle-color (colors/custom-color color 50 opacity)
|
||||
circle-color (colors/custom-color color 50 20)
|
||||
icon-color (colors/custom-color-by-theme color 50 60)
|
||||
icon-size (case size
|
||||
:big 20
|
||||
@@ -26,4 +25,4 @@
|
||||
:align-items :center}}
|
||||
[icons/icon icon {:container-style {:width icon-size
|
||||
:height icon-size}
|
||||
:color icon-color}]]))
|
||||
:color icon-color}]]))
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.icon :as icons]
|
||||
[clojure.string :refer [upper-case split blank?]]
|
||||
[quo.theme :refer [dark?]]))
|
||||
[quo.theme :refer [dark?]]
|
||||
[status-im.ui.components.react :as react]))
|
||||
|
||||
(def sizes {:big {:outer 80
|
||||
:inner 72
|
||||
@@ -97,46 +98,47 @@
|
||||
status-indicator?
|
||||
profile-picture
|
||||
full-name]
|
||||
:or {full-name "empty name"
|
||||
status-indicator? true
|
||||
online? true
|
||||
size :big
|
||||
ring? true}}]
|
||||
(let [initials (if full-name
|
||||
(reduce str (map first (split full-name " ")))
|
||||
"")
|
||||
:or {full-name "empty name"
|
||||
status-indicator? true
|
||||
online? true
|
||||
size :big
|
||||
ring? true}}]
|
||||
(let [initials (if full-name
|
||||
(reduce str (map first (split full-name " ")))
|
||||
"")
|
||||
first-initial-letter (if full-name
|
||||
(or (first full-name) "")
|
||||
"")
|
||||
identicon? (contains? identicon-sizes size)
|
||||
small? (contains? small-sizes size)
|
||||
outer-dimensions (get-in sizes [size :outer])
|
||||
inner-dimensions (get-in sizes [size (if ring?
|
||||
:inner
|
||||
:outer)])
|
||||
font-size (get-in sizes [size :font-size])
|
||||
icon-text (if-not (or (blank? first-initial-letter)
|
||||
(blank? initials))
|
||||
(if small?
|
||||
first-initial-letter
|
||||
initials)
|
||||
"")]
|
||||
[rn/view {:style {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
identicon? (contains? identicon-sizes size)
|
||||
small? (contains? small-sizes size)
|
||||
using-profile-picture? (-> profile-picture
|
||||
blank?
|
||||
false?)
|
||||
outer-dimensions (get-in sizes [size :outer])
|
||||
inner-dimensions (get-in sizes [size (if ring?
|
||||
:inner
|
||||
:outer)])
|
||||
font-size (get-in sizes [size :font-size])
|
||||
icon-text (if-not (or (blank? first-initial-letter)
|
||||
(blank? initials))
|
||||
(if small?
|
||||
first-initial-letter
|
||||
initials)
|
||||
"")]
|
||||
[rn/view {:style {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:border-radius outer-dimensions}}
|
||||
(when (and ring? identicon?)
|
||||
[icons/icon :main-icons/identicon-ring {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:size outer-dimensions
|
||||
[icons/icon :main-icons/identicon-ring {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:size outer-dimensions
|
||||
:no-color true}])
|
||||
(if profile-picture
|
||||
;; display image
|
||||
[rn/image {:style (container-styling inner-dimensions outer-dimensions)
|
||||
:source profile-picture}]
|
||||
;; else display initials
|
||||
(if using-profile-picture?
|
||||
[react/image {:style (container-styling inner-dimensions outer-dimensions)
|
||||
:source {:uri profile-picture}}]
|
||||
[container inner-dimensions outer-dimensions
|
||||
[text/text {:weight :semi-bold
|
||||
:size font-size
|
||||
:style {:color colors/white-opa-70}}
|
||||
:size font-size
|
||||
:style {:color colors/white-opa-70}}
|
||||
(upper-case icon-text)]])
|
||||
[dot-indicator size status-indicator? online? ring? (dark?)]]))
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
(ns quo2.components.buttons.dynamic-button
|
||||
(:require [quo.react-native :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.markdown.text :as text]))
|
||||
|
||||
(defn- in?
|
||||
"true if collection contains element"
|
||||
[collection element]
|
||||
(some #(= element %) collection))
|
||||
|
||||
(defn- get-button-color [type pressed? customization-color]
|
||||
(if (in? '(:jump-to :mention) type)
|
||||
(if pressed?
|
||||
(colors/custom-color-by-theme customization-color 60 50)
|
||||
(colors/custom-color-by-theme customization-color 50 60))
|
||||
(if pressed?
|
||||
(colors/theme-colors colors/neutral-80-opa-80 colors/white-opa-80)
|
||||
(colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70))))
|
||||
|
||||
(defn- get-icon-and-text-color [type]
|
||||
(if (in? '(:jump-to :mention) type)
|
||||
colors/white
|
||||
(colors/theme-colors colors/white colors/neutral-100)))
|
||||
|
||||
(defn- icon-view [type]
|
||||
[icon/icon
|
||||
(case type
|
||||
:jump-to :main-icons2/jump-to
|
||||
:mention :main-icons2/mention
|
||||
:notification-down :main-icons2/arrow-down
|
||||
:notification-up :main-icons2/arrow-up
|
||||
:search-with-label :main-icons2/search
|
||||
:search :main-icons2/search
|
||||
:bottom :main-icons2/arrow-down)
|
||||
{:size 12
|
||||
:color (get-icon-and-text-color type)
|
||||
:container-style {:margin-top 6
|
||||
:margin-bottom 6
|
||||
:margin-left (case type
|
||||
:jump-to 0
|
||||
:mention 8
|
||||
:notification-down 2
|
||||
:notification-up 2
|
||||
:search-with-label 8
|
||||
:search 6
|
||||
:bottom 6)
|
||||
:margin-right (case type
|
||||
:jump-to 8
|
||||
:mention 2
|
||||
:notification-down 8
|
||||
:notification-up 8
|
||||
:search-with-label 4
|
||||
:search 6
|
||||
:bottom 6)}}])
|
||||
|
||||
(defn dynamic-button
|
||||
"[:dynamic-button opts]
|
||||
opts
|
||||
{:type :jump-to/:mention/:notification-down/:notification-up/:search/:search-with-label/:bottom
|
||||
:on-press fn
|
||||
:count mentions or notifications count
|
||||
:customization-color customize jump-to and mention button color}"
|
||||
[_]
|
||||
(let [pressed? (reagent/atom false)]
|
||||
(fn [{:keys [type on-press count customization-color]
|
||||
:or {customization-color :primary}}]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press-in #(reset! pressed? true)
|
||||
:on-press-out #(reset! pressed? false)
|
||||
:on-press on-press}
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:height 24
|
||||
:border-radius 12
|
||||
:background-color (get-button-color type @pressed? customization-color)}}
|
||||
(when (in? '(:mention :search :search-with-label :bottom) type)
|
||||
[icon-view type])
|
||||
(when (in? '(:jump-to :mention :notification-down :notification-up :search-with-label) type)
|
||||
[text/text {:weight :medium
|
||||
:size :paragraph-2
|
||||
:style {:color (get-icon-and-text-color type)
|
||||
:margin-top 2.5
|
||||
:margin-bottom 3.5
|
||||
:margin-left (case type
|
||||
:jump-to 8
|
||||
:mention 0
|
||||
:notification-down 8
|
||||
:notification-up 8
|
||||
:search-with-label 0)
|
||||
:margin-right (case type
|
||||
:jump-to 0
|
||||
:mention 8
|
||||
:notification-down 0
|
||||
:notification-up 0
|
||||
:search-with-label 8)}}
|
||||
(case type
|
||||
:jump-to (i18n/label :t/jump-to)
|
||||
:search-with-label (i18n/label :t/back)
|
||||
(:mention :notification-down :notification-up) (str count))])
|
||||
(when (in? '(:jump-to :notification-down :notification-up) type)
|
||||
[icon-view type])]])))
|
||||
@@ -1,162 +0,0 @@
|
||||
(ns quo2.components.messages.system-message
|
||||
(:require [status-im.i18n.i18n :as i18n]
|
||||
[quo.react-native :as rn]
|
||||
[status-im.utils.core :as utils]
|
||||
[quo.theme :as theme]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.reanimated :as ra]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.avatars.icon-avatar :as icon-avatar]))
|
||||
|
||||
(def themes-landed {:pinned colors/primary-50-opa-5
|
||||
:added colors/primary-50-opa-5
|
||||
:deleted colors/danger-50-opa-5})
|
||||
|
||||
(def themes
|
||||
{:light {:text colors/neutral-100
|
||||
:time colors/neutral-50
|
||||
:bg {:default colors/white
|
||||
:pressed colors/neutral-5
|
||||
:landed themes-landed}}
|
||||
:dark {:text colors/white
|
||||
:time colors/neutral-40
|
||||
:bg {:default colors/neutral-90
|
||||
:pressed colors/neutral-80
|
||||
:landed themes-landed}}})
|
||||
|
||||
(defn get-color [& keys]
|
||||
(reduce (fn [acc k] (get acc k (reduced acc)))
|
||||
((theme/get-theme) themes) (vec keys)))
|
||||
|
||||
(defn sm-timestamp [timestamp-str]
|
||||
[rn/view {:margin-left 6}
|
||||
[text/text {:size :label
|
||||
:style {:color (get-color :time)
|
||||
:text-transform :none}}
|
||||
timestamp-str]])
|
||||
|
||||
(defn sm-icon [{:keys [icon color opacity]}]
|
||||
[rn/view {:align-items :center
|
||||
:margin-right 8}
|
||||
[icon-avatar/icon-avatar {:size :medium
|
||||
:icon icon
|
||||
:color color
|
||||
:opacity opacity}]])
|
||||
|
||||
(defn sm-user-avatar [image]
|
||||
[rn/view {:margin-right 4}
|
||||
[user-avatar/user-avatar {:status-indicator? false
|
||||
:online? false
|
||||
:size :xxxs
|
||||
:profile-picture image
|
||||
:ring? false}]])
|
||||
|
||||
(defmulti sm-render :type)
|
||||
|
||||
(defmethod sm-render :deleted [{:keys [state action timestamp-str]}]
|
||||
[rn/view {:align-items :center
|
||||
:justify-content :space-between
|
||||
:flex 1
|
||||
:flex-direction :row}
|
||||
[rn/view {:align-items :center
|
||||
:flex-direction :row}
|
||||
[sm-icon {:icon :main-icons/delete16
|
||||
:color :danger
|
||||
:opacity (if (= state :landed) 0 5)}]
|
||||
[text/text {:size :paragraph-2
|
||||
:style {:color (get-color :text)
|
||||
:margin-right 5}}
|
||||
(i18n/label (if action :message-deleted-for-you :message-deleted))]
|
||||
(when (nil? action) [sm-timestamp timestamp-str])]
|
||||
(when action [button/button {:size 24
|
||||
:before :main-icons/timeout
|
||||
:type :grey} (i18n/label :undo)])])
|
||||
|
||||
(defmethod sm-render :added [{:keys [state mentions timestamp-str]}]
|
||||
[rn/view {:align-items :center
|
||||
:flex-direction :row}
|
||||
[sm-icon {:icon :main-icons/add-user16
|
||||
:color :primary
|
||||
:opacity (if (= state :landed) 0 5)}]
|
||||
[sm-user-avatar (:image (first mentions))]
|
||||
[text/text {:weight :semi-bold
|
||||
:size :paragraph-2}
|
||||
(:name (first mentions))]
|
||||
[text/text {:size :paragraph-2
|
||||
:style {:color (get-color :text)
|
||||
:margin-left 3
|
||||
:margin-right 3}}
|
||||
(i18n/label :added)]
|
||||
[sm-user-avatar (:image (second mentions))]
|
||||
[text/text {:weight :semi-bold
|
||||
:size :paragraph-2}
|
||||
(:name (second mentions))]
|
||||
[sm-timestamp timestamp-str]])
|
||||
|
||||
(defmethod sm-render :pinned [{:keys [state pinned-by content timestamp-str]}]
|
||||
[rn/view {:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center}
|
||||
[sm-icon {:icon :main-icons/pin16
|
||||
:color :primary
|
||||
:opacity (if (= state :landed) 0 5)}]
|
||||
[rn/view {:flex-direction :column
|
||||
:flex 1}
|
||||
[rn/view {:align-items :baseline
|
||||
:flex-direction :row}
|
||||
[text/text {:size :paragraph-2
|
||||
:weight :semi-bold
|
||||
:style {:color (get-color :text)}}
|
||||
(utils/truncate-str pinned-by 18)]
|
||||
[rn/view {:margin-left 4
|
||||
:margin-right 2}
|
||||
[text/text {:size :paragraph-2
|
||||
:style {:color (get-color :text)}}
|
||||
(i18n/label :pinned-a-message)]]
|
||||
[sm-timestamp timestamp-str]]
|
||||
[rn/view {:flex-direction :row}
|
||||
[rn/view {:flex-direction :row
|
||||
:margin-right 4}
|
||||
[sm-user-avatar (:image (:mentions content))]
|
||||
[text/text {:weight :semi-bold
|
||||
:size :label}
|
||||
(:name (:mentions content))]]
|
||||
(when (seq (:text content))
|
||||
[rn/view {:margin-right 20
|
||||
:flex-direction :row
|
||||
:flex 1}
|
||||
[text/text {:size :label
|
||||
:style {:color (get-color :text)}
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail}
|
||||
(:text content)]])
|
||||
[rn/view {:justify-content :flex-end
|
||||
:flex-direction :row
|
||||
:min-width 10}
|
||||
(when (seq (:info content))
|
||||
[text/text {:size :label
|
||||
:style {:color (get-color :time)}}
|
||||
(utils/truncate-str (:info content) 24)])]]]])
|
||||
|
||||
(defn system-message [{:keys [type] :as message}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [sv-color (ra/use-shared-value (get-color :bg :landed type))]
|
||||
(ra/animate-shared-value-with-delay
|
||||
sv-color (get-color :bg :default type) 0 :linear 1000)
|
||||
[ra/touchable-opacity
|
||||
{:on-press #(ra/set-shared-value
|
||||
sv-color (get-color :bg :pressed type))
|
||||
:style (ra/apply-animations-to-style
|
||||
{:background-color sv-color}
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:padding-vertical 9
|
||||
:padding-horizontal 11
|
||||
:width 359
|
||||
:height 52
|
||||
:background-color sv-color})}
|
||||
[sm-render message]]))])
|
||||
@@ -1,175 +0,0 @@
|
||||
(ns quo2.components.navigation.page-nav
|
||||
(:require [quo.react-native :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.icon :as icons]
|
||||
[status-im.utils.dimensions :as dimensions]
|
||||
[clojure.string :as string]
|
||||
[quo2.components.markdown.text :as text]))
|
||||
|
||||
(def ^:private centrify-style
|
||||
{:display :flex
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(def ^:private align-left (assoc centrify-style :align-items :flex-start))
|
||||
|
||||
(def ^:private icon-styles (assoc centrify-style :width 32 :height 32 :border-radius 10))
|
||||
|
||||
(defn- big? [size] (= size :big))
|
||||
|
||||
(defn- icon-props [color size]
|
||||
(merge {:size 20
|
||||
:container-style {:width (if (big? size)
|
||||
20
|
||||
16)
|
||||
:height (if (big? size)
|
||||
20
|
||||
16)}}
|
||||
(if-not (string/blank? color)
|
||||
{:color color}
|
||||
{:no-color true})))
|
||||
|
||||
(defn- mid-section-comp
|
||||
[{:keys [mid-section-description-user-icon horizontal-description? text-secondary-color align-mid? text-color mid-section-icon mid-section-main-text mid-section-type mid-section-description]}]
|
||||
[rn/view {:style (assoc
|
||||
centrify-style
|
||||
:flex-direction :row
|
||||
:margin-horizontal 2)}
|
||||
(when (or (and (not horizontal-description?)
|
||||
align-mid?
|
||||
(not= :text-with-description mid-section-type))
|
||||
(and mid-section-description-user-icon
|
||||
(not mid-section-icon)))
|
||||
[rn/image {:source {:uri mid-section-description-user-icon}
|
||||
:style {:width 32
|
||||
:height 32
|
||||
:border-radius 32
|
||||
:margin-right 8}}])
|
||||
[rn/view {:style {:flex-direction (if horizontal-description?
|
||||
:row
|
||||
:column)}}
|
||||
[text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:color text-color
|
||||
:line-height 21}}
|
||||
mid-section-main-text]
|
||||
(when mid-section-description
|
||||
[text/text {:size :paragraph-2
|
||||
:weight :medium
|
||||
:style (cond-> {:padding-right 4
|
||||
:color text-secondary-color
|
||||
:line-height 18}
|
||||
horizontal-description? (assoc :margin-left 4 :margin-top 2))}
|
||||
mid-section-description])]])
|
||||
|
||||
(defn- mid-section
|
||||
[{:keys [horizontal-description? one-icon-align-left? mid-section-type left-align? mid-section-main-text mid-section-right-icon mid-section-main-text-icon-color mid-section-left-icon] :as mid-section-props}]
|
||||
(let [text-color (if (colors/dark?) colors/neutral-5 colors/neutral-95)
|
||||
text-secondary-color (if (colors/dark?) colors/neutral-40 colors/neutral-50)
|
||||
mid-section-comp-instance [mid-section-comp (assoc mid-section-props :text-secondary-color text-secondary-color)]]
|
||||
[rn/view {:style (merge
|
||||
(if left-align?
|
||||
align-left
|
||||
centrify-style)
|
||||
{:flex 1
|
||||
:margin-left 4
|
||||
:text-align-vertical :center})}
|
||||
(case mid-section-type
|
||||
:text-only [text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:color text-color}}
|
||||
mid-section-main-text]
|
||||
:text-with-two-icons [rn/view {:style (assoc centrify-style :flex-direction :row)}
|
||||
[icons/icon mid-section-left-icon
|
||||
(icon-props mid-section-main-text-icon-color :big)]
|
||||
[text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:padding-horizontal 4
|
||||
:color text-color}}
|
||||
mid-section-main-text]
|
||||
|
||||
[icons/icon mid-section-right-icon
|
||||
(icon-props mid-section-main-text-icon-color :big)]]
|
||||
:text-with-one-icon [rn/view {:style {:flex-direction :row}}
|
||||
(if one-icon-align-left?
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
(when horizontal-description?
|
||||
[icons/icon mid-section-left-icon
|
||||
(icon-props mid-section-main-text-icon-color :big)])
|
||||
mid-section-comp-instance]
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
mid-section-comp-instance
|
||||
(when horizontal-description?
|
||||
[icons/icon mid-section-left-icon
|
||||
(icon-props mid-section-main-text-icon-color :big)])])]
|
||||
:text-with-description mid-section-comp-instance)]))
|
||||
|
||||
(defn- right-section-icon
|
||||
[{:keys [background-color icon icon-color push-to-the-left?] :or {push-to-the-left? false}}]
|
||||
[rn/view {:style (assoc
|
||||
icon-styles
|
||||
:background-color background-color
|
||||
:width 32
|
||||
:height 32
|
||||
:margin-right (if push-to-the-left? 8 0))}
|
||||
[icons/icon icon (icon-props icon-color :big)]])
|
||||
|
||||
(defn page-nav
|
||||
[{:keys [one-icon-align-left? horizontal-description? align-mid? page-nav-color page-nav-background-uri mid-section-type mid-section-icon mid-section-main-text mid-section-left-icon mid-section-right-icon mid-section-description mid-section-description-color mid-section-description-icon mid-section-description-user-icon mid-section-main-text-icon-color left-section-icon left-section-icon-color left-section-icon-background-color right-section-icons]}]
|
||||
(let [{:keys [height width]} (dimensions/window)
|
||||
put-middle-section-on-left? (or align-mid?
|
||||
(> (count right-section-icons) 1))
|
||||
mid-section-props {:mid-section-type mid-section-type
|
||||
:horizontal-description? horizontal-description?
|
||||
:mid-section-main-text mid-section-main-text
|
||||
:one-icon-align-left? one-icon-align-left?
|
||||
:mid-section-right-icon mid-section-right-icon
|
||||
:mid-section-icon mid-section-icon
|
||||
:mid-section-main-text-icon-color mid-section-main-text-icon-color
|
||||
:mid-section-left-icon mid-section-left-icon}]
|
||||
[rn/view {:style (cond->
|
||||
{:display :flex
|
||||
:flex-direction :row
|
||||
:width width
|
||||
:height (* 0.0497 height)
|
||||
;; iPhone 11 Pro's height in Figma divided by Component height 56/1125
|
||||
:align-items :center
|
||||
:padding-horizontal 20
|
||||
:justify-content :space-between}
|
||||
page-nav-background-uri (assoc :background-color page-nav-color)
|
||||
page-nav-color (assoc :background page-nav-background-uri))}
|
||||
[rn/view {:style {:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center}}
|
||||
[rn/view {:style (merge
|
||||
icon-styles
|
||||
{:background-color left-section-icon-background-color
|
||||
:width 32
|
||||
:height 32}
|
||||
(when put-middle-section-on-left? {:margin-right 5}))}
|
||||
[icons/icon left-section-icon (icon-props left-section-icon-color :big)]]
|
||||
(when put-middle-section-on-left?
|
||||
[mid-section (assoc mid-section-props
|
||||
:left-align? true
|
||||
:mid-section-description mid-section-description
|
||||
:mid-section-description-color mid-section-description-color
|
||||
:mid-section-description-icon mid-section-description-icon
|
||||
:align-mid? align-mid?
|
||||
:mid-section-description-user-icon mid-section-description-user-icon)])]
|
||||
(when-not put-middle-section-on-left?
|
||||
[mid-section mid-section-props])
|
||||
[rn/view {:style (assoc
|
||||
centrify-style
|
||||
:flex-direction :row
|
||||
:flex 1
|
||||
:justify-content :flex-end)}
|
||||
(let [last-icon-index (- (count right-section-icons) 1)]
|
||||
(map-indexed (fn [index {:keys [icon background-color icon-color]}]
|
||||
^{:key index}
|
||||
[right-section-icon {:icon icon
|
||||
:background-color background-color
|
||||
:icon-color icon-color
|
||||
:push-to-the-left? (if (= index last-icon-index) false true)}])
|
||||
right-section-icons))]]))
|
||||
@@ -1,142 +1,21 @@
|
||||
(ns quo2.components.tabs.tabs
|
||||
(:require [oops.core :refer [oget]]
|
||||
(:require [reagent.core :as reagent]
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.tabs.tab :as tab]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.utils.core :as utils]
|
||||
[status-im.utils.number :as number-utils]))
|
||||
|
||||
(def default-tab-size 32)
|
||||
[quo2.components.tabs.tab :as tab]))
|
||||
|
||||
(defn tabs [{:keys [default-active on-change]}]
|
||||
(let [active-tab-id (reagent/atom default-active)]
|
||||
(fn [{:keys [data size] :or {size default-tab-size}}]
|
||||
(fn [{:keys [data size] :or {size 32}}]
|
||||
(let [active-id @active-tab-id]
|
||||
[rn/view {:flex-direction :row}
|
||||
(for [{:keys [label id]} data]
|
||||
^{:key id}
|
||||
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
|
||||
[rn/view {:margin-right (if (= size 32) 12 8)}
|
||||
[tab/tab
|
||||
{:id id
|
||||
:size size
|
||||
:active (= id active-id)
|
||||
:on-press (fn [^js press-event id]
|
||||
(reset! active-tab-id id)
|
||||
(when on-change
|
||||
(on-change press-event id)))}
|
||||
label]])]))))
|
||||
|
||||
(defn- calculate-fade-end-percentage
|
||||
[{:keys [offset-x content-width layout-width max-fade-percentage]}]
|
||||
(let [fade-percentage (max max-fade-percentage
|
||||
(/ (+ layout-width offset-x)
|
||||
content-width))]
|
||||
;; Truncate to avoid unnecessary rendering.
|
||||
(if (> fade-percentage 0.99)
|
||||
0.99
|
||||
(number-utils/naive-round fade-percentage 2))))
|
||||
|
||||
(defn scrollable-tabs
|
||||
"Just like the component `tabs`, displays horizontally scrollable tabs with
|
||||
extra options to control if/how the end of the scroll view fades.
|
||||
|
||||
Tabs are rendered using ReactNative's FlatList, which offers the convenient
|
||||
`scrollToIndex` method. FlatList accepts VirtualizedList and ScrollView props,
|
||||
and so does this component.
|
||||
|
||||
Usage:
|
||||
[tabs/scrollable-tabs
|
||||
{:scroll-on-press? true
|
||||
:fade-end? true
|
||||
:on-change #(...)
|
||||
:default-active :tab-a
|
||||
:data [{:id :tab-a :label \"Tab A\"}
|
||||
{:id :tab-b :label \"Tab B\"}]}]]
|
||||
|
||||
Opts:
|
||||
- `size` number
|
||||
- `scroll-on-press?` When non-nil, clicking on a tab centers it the middle
|
||||
(with animation enabled).
|
||||
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
|
||||
- `fade-end-percentage` Percentage where fading starts relative to the total
|
||||
layout width of the `flat-list` data."
|
||||
[{:keys [default-active fade-end-percentage]
|
||||
:or {fade-end-percentage 0.8}}]
|
||||
(let [active-tab-id (reagent/atom default-active)
|
||||
fading (reagent/atom {:fade-end-percentage fade-end-percentage})
|
||||
flat-list-ref (atom nil)]
|
||||
(fn [{:keys [data
|
||||
fade-end-percentage
|
||||
fade-end?
|
||||
on-change
|
||||
on-scroll
|
||||
scroll-event-throttle
|
||||
scroll-on-press?
|
||||
size]
|
||||
:or {fade-end-percentage fade-end-percentage
|
||||
fade-end? false
|
||||
scroll-event-throttle 64
|
||||
scroll-on-press? false
|
||||
size default-tab-size}
|
||||
:as props}]
|
||||
(let [maybe-mask-wrapper (if fade-end?
|
||||
[react/masked-view
|
||||
{:mask-element (reagent/as-element
|
||||
[react/linear-gradient {:colors [:black :transparent]
|
||||
:locations [(get @fading :fade-end-percentage) 1]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 1 :y 0}
|
||||
:pointer-events :none
|
||||
:style {:width "100%"
|
||||
:height "100%"}}])}]
|
||||
[:<>])]
|
||||
(conj maybe-mask-wrapper
|
||||
[rn/flat-list
|
||||
(merge (dissoc props
|
||||
:default-active
|
||||
:fade-end-percentage
|
||||
:fade-end?
|
||||
:on-change
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
(when scroll-on-press?
|
||||
{:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)})
|
||||
{:ref #(reset! flat-list-ref %)
|
||||
:extra-data (str @active-tab-id)
|
||||
:horizontal true
|
||||
:scroll-event-throttle scroll-event-throttle
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:data data
|
||||
:key-fn (comp str :id)
|
||||
:on-scroll (fn [^js e]
|
||||
(when fade-end?
|
||||
(let [offset-x (oget e "nativeEvent.contentOffset.x")
|
||||
content-width (oget e "nativeEvent.contentSize.width")
|
||||
layout-width (oget e "nativeEvent.layoutMeasurement.width")
|
||||
new-percentage (calculate-fade-end-percentage {:offset-x offset-x
|
||||
:content-width content-width
|
||||
:layout-width layout-width
|
||||
:max-fade-percentage fade-end-percentage})]
|
||||
;; Avoid unnecessary re-rendering.
|
||||
(when (not= new-percentage (get @fading :fade-end-percentage))
|
||||
(swap! fading assoc :fade-end-percentage new-percentage))))
|
||||
(when on-scroll
|
||||
(on-scroll e)))
|
||||
:render-fn (fn [{:keys [id label]} index]
|
||||
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)
|
||||
:padding-right (when (= index (dec (count data)))
|
||||
(get-in props [:style :padding-left]))}}
|
||||
[tab/tab {:id id
|
||||
:size size
|
||||
:active (= id @active-tab-id)
|
||||
:on-press (fn [id]
|
||||
(reset! active-tab-id id)
|
||||
(when scroll-on-press?
|
||||
(.scrollToIndex @flat-list-ref
|
||||
#js {:animated true
|
||||
:index index
|
||||
:viewPosition 0.5}))
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
label]])})])))))
|
||||
{:id id
|
||||
:size size
|
||||
:active (= id active-id)
|
||||
:on-press #(do (reset! active-tab-id %)
|
||||
(when on-change
|
||||
(on-change %)))}
|
||||
label]])]))))
|
||||
@@ -119,7 +119,6 @@
|
||||
|
||||
;;;; Customization
|
||||
|
||||
;; Colors for customizing profiles and communities themes
|
||||
(def customization
|
||||
{:primary {50 primary-50 ;; User can also use primary color as customisation color
|
||||
60 primary-60}
|
||||
@@ -146,11 +145,6 @@
|
||||
:beige {50 "#CAAE93"
|
||||
60 "#AA927C"}})
|
||||
|
||||
(def colors-map (merge {:danger {50 danger-50
|
||||
60 danger-60}
|
||||
:success {50 success-50
|
||||
60 success-60}} customization))
|
||||
|
||||
(def custom-color
|
||||
"(custom-color color suffix opacity)
|
||||
color :primary/:purple/...
|
||||
@@ -161,7 +155,7 @@
|
||||
([color suffix]
|
||||
(custom-color color suffix nil))
|
||||
([color suffix opacity]
|
||||
(let [base-color (get-in colors-map [(keyword color) suffix])]
|
||||
(let [base-color (get-in customization [(keyword color) suffix])]
|
||||
(if opacity (alpha base-color (/ opacity 100)) base-color))))))
|
||||
|
||||
(defn custom-color-by-theme
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
:type :select
|
||||
:options [{:key :main-icons/placeholder20
|
||||
:value "Placeholder"}
|
||||
{:key :main-icons/wallet
|
||||
{:key :main-icons/walelt
|
||||
:value "Wallet"}
|
||||
{:key :main-icons/play
|
||||
:value "Play"}]}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo.previews.preview :as preview]
|
||||
[quo2.components.avatars.user-avatar :as quo2]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.react-native.resources :as resources]))
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def descriptor [{:label "Size:"
|
||||
:key :size
|
||||
@@ -33,15 +32,9 @@
|
||||
{:label "Full name separated by space"
|
||||
:key :full-name
|
||||
:type :text}
|
||||
{:label "Profile Picture"
|
||||
:key :profile-picture
|
||||
:type :select
|
||||
:options [{:value "None"
|
||||
:key nil}
|
||||
{:value "Alicia Keys"
|
||||
:key (resources/get-mock-image :user-picture-female2)}
|
||||
{:value "pedro.eth"
|
||||
:key (resources/get-mock-image :user-picture-male4)}]}])
|
||||
{:label "Profile Picture URL"
|
||||
:key :profile-picture
|
||||
:type :text}])
|
||||
|
||||
(defn cool-preview []
|
||||
(let [state (reagent/atom {:full-name "A Y"
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
(ns quo2.screens.buttons.dynamic-button
|
||||
(:require [quo.react-native :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[quo.previews.preview :as preview]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.buttons.dynamic-button :as quo2]))
|
||||
|
||||
(def descriptor [{:label "Type:"
|
||||
:key :type
|
||||
:type :select
|
||||
:options [{:key :jump-to
|
||||
:value "Jump To"}
|
||||
{:key :mention
|
||||
:value "Mention"}
|
||||
{:key :notification-down
|
||||
:value "Notification Down"}
|
||||
{:key :notification-up
|
||||
:value "Notification Up"}
|
||||
{:key :search
|
||||
:value "Search"}
|
||||
{:key :search-with-label
|
||||
:value "Search With Label"}
|
||||
{:key :bottom
|
||||
:value "Bottom"}]}
|
||||
{:label "Count"
|
||||
:key :count
|
||||
:type :text}])
|
||||
|
||||
(defn cool-preview []
|
||||
(let [state (reagent/atom {:count 5 :type :jump-to})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:padding-vertical 60
|
||||
:align-items :center}
|
||||
[quo2/dynamic-button @state]]]])))
|
||||
|
||||
(defn preview-dynamic-button []
|
||||
[rn/view {:background-color (colors/theme-colors colors/white colors/neutral-90)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -13,7 +13,6 @@
|
||||
[quo2.screens.avatars.user-avatar :as user-avatar]
|
||||
[quo2.screens.avatars.wallet-user-avatar :as wallet-user-avatar]
|
||||
[quo2.screens.buttons.button :as button]
|
||||
[quo2.screens.buttons.dynamic-button :as dynamic-button]
|
||||
[quo2.screens.counter.counter :as counter]
|
||||
[quo2.screens.community.community-card-view :as community-card]
|
||||
[quo2.screens.dividers.divider-label :as divider-label]
|
||||
@@ -26,7 +25,6 @@
|
||||
[quo2.screens.list-items.channel :as channel]
|
||||
[quo2.screens.markdown.text :as text]
|
||||
[quo2.screens.messages.gap :as messages-gap]
|
||||
[quo2.screens.messages.system-message :as system-message]
|
||||
[quo2.screens.notifications.activity-logs :as activity-logs]
|
||||
[quo2.screens.reactions.react :as react]
|
||||
[quo2.screens.selectors.disclaimer :as disclaimer]
|
||||
@@ -45,7 +43,6 @@
|
||||
[quo2.screens.wallet.token-overview :as token-overview]
|
||||
[quo2.screens.wallet.network-breakdown :as network-breakdown]
|
||||
[quo2.screens.wallet.network-amount :as network-amount]
|
||||
[quo2.screens.navigation.page-nav :as page-nav]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(def screens-categories
|
||||
@@ -66,10 +63,7 @@
|
||||
:component channel-avatar/preview-channel-avatar}]
|
||||
:buttons [{:name :button
|
||||
:insets {:top false}
|
||||
:component button/preview-button}
|
||||
{:name :dynamic-button
|
||||
:insets {:top false}
|
||||
:component dynamic-button/preview-dynamic-button}]
|
||||
:component button/preview-button}]
|
||||
:community [{:name :community-cards
|
||||
:insets {:top false}
|
||||
:component community-card/preview-community-card}]
|
||||
@@ -102,19 +96,13 @@
|
||||
:component text/preview-text}]
|
||||
:messages [{:name :gap
|
||||
:insets {:top false}
|
||||
:component messages-gap/preview-messages-gap}
|
||||
{:name :system-messages
|
||||
:insets {:top false}
|
||||
:component system-message/preview-system-message}]
|
||||
:component messages-gap/preview-messages-gap}]
|
||||
:navigation [{:name :bottom-nav-tab
|
||||
:insets {:top false}
|
||||
:component bottom-nav-tab/preview-bottom-nav-tab}
|
||||
{:name :top-nav
|
||||
:insets {:top false}
|
||||
:component top-nav/preview-top-nav}
|
||||
{:name :page-nav
|
||||
:insets {:top false}
|
||||
:component page-nav/preview-page-nav}]
|
||||
:component top-nav/preview-top-nav}]
|
||||
:notifications [{:name :activity-logs
|
||||
:insets {:top false}
|
||||
:component activity-logs/preview-activity-logs}]
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
(ns quo2.screens.messages.system-message
|
||||
(:require [reagent.core :as reagent]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[quo.react-native :as rn]
|
||||
[quo.previews.preview :as preview]
|
||||
[quo2.components.messages.system-message :as system-message]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(def descriptor [{:label "Message Type"
|
||||
:key :type
|
||||
:type :select
|
||||
:options [{:value "Message pinned"
|
||||
:key :pinned}
|
||||
{:value "User added"
|
||||
:key :added}
|
||||
{:value "Message deleted"
|
||||
:key :deleted}]}
|
||||
{:label "Action"
|
||||
:key :action
|
||||
:type :select
|
||||
:options [{:value "none"
|
||||
:key nil}
|
||||
{:value "Undo"
|
||||
:key :undo}]}
|
||||
{:label "Pinned By"
|
||||
:key :pinned-by
|
||||
:type :text}
|
||||
{:label "Content Text"
|
||||
:key :content-text
|
||||
:type :text}
|
||||
{:label "Content Info"
|
||||
:key :content-info
|
||||
:type :text}
|
||||
{:label "Timestamp"
|
||||
:key :timestamp-str
|
||||
:type :text}])
|
||||
|
||||
(defn finalize-state [state]
|
||||
(merge @state
|
||||
{:mentions [{:name "Alicia Keys"
|
||||
:image (resources/get-mock-image :user-picture-female2)}
|
||||
{:name "pedro.eth"
|
||||
:image (resources/get-mock-image :user-picture-male4)}]
|
||||
:content {:text (:content-text @state)
|
||||
:info (:content-info @state)
|
||||
:mentions {:name "Alisher"
|
||||
:image (resources/get-mock-image :user-picture-male5)}}}))
|
||||
(defn preview []
|
||||
(let [state (reagent/atom {:type :deleted
|
||||
:pinned-by "Steve"
|
||||
:content-text "Hello! This is an example of a pinned message!"
|
||||
:content-info "3 photos"
|
||||
:timestamp-str "09:41"})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:padding-vertical 60
|
||||
:align-items :center}
|
||||
[system-message/system-message (finalize-state state)]]]])))
|
||||
|
||||
(defn preview-system-message []
|
||||
[rn/view {:background-color (colors/theme-colors colors/white colors/neutral-90)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:header [preview]
|
||||
:key-fn str
|
||||
:keyboardShouldPersistTaps :always}]])
|
||||
@@ -1,106 +0,0 @@
|
||||
(ns quo2.screens.navigation.page-nav
|
||||
(:require [quo.previews.preview :as preview]
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.navigation.page-nav :as quo2]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def ^:private descriptor
|
||||
[{:label "Page nav variation"
|
||||
:key :selected-variation
|
||||
:type :select
|
||||
:options [{:key :text-only?
|
||||
:value "Text only"}
|
||||
{:key :align-left?
|
||||
:value "Align Left"}
|
||||
{:key :align-left-top-down-text?
|
||||
:value "Align left top down text?"}
|
||||
{:key :align-left-with-icon?
|
||||
:value "Align Left with icon ?"}
|
||||
{:key :one-icon-align-left?
|
||||
:value "One icon on the left ?"}
|
||||
{:key :one-icon-align-right?
|
||||
:value "One icon on the right ?"}
|
||||
{:key :two-icons?
|
||||
:value "Two icons ?"}
|
||||
{:key :user-icon?
|
||||
:value "User icon ?"}
|
||||
{:key :empty?
|
||||
:value "Empty ?"}]}
|
||||
{:label "Number of right icons"
|
||||
:key :number-of-right-icons
|
||||
:type :select
|
||||
:options [{:key 1
|
||||
:value 1}
|
||||
{:key 2
|
||||
:value 2}
|
||||
{:key 3
|
||||
:value 3}]}])
|
||||
|
||||
(def ^:private selected-variation (reagent/atom {:selected-variation :text-only?
|
||||
:number-of-right-icons 1}))
|
||||
|
||||
(defn- cool-preview []
|
||||
(let [right-icon {:background-color (if (colors/dark?)
|
||||
colors/neutral-80
|
||||
colors/neutral-20)
|
||||
:icon :main-icons/placeholder
|
||||
:icon-color nil}
|
||||
base-props {:horizontal-description? true
|
||||
:one-icon-align-left? true
|
||||
:align-mid? false
|
||||
:page-nav-color :transparent
|
||||
:page-nav-background-uri ""
|
||||
:mid-section-type :text-with-description
|
||||
:mid-section-icon :main-icons/placeholder
|
||||
:mid-section-main-text "Status"
|
||||
:mid-section-left-icon :main-icons/placeholder
|
||||
:mid-section-right-icon :main-icons/placeholder
|
||||
:mid-section-description "SNT"
|
||||
:mid-section-description-color "black"
|
||||
:mid-section-description-icon :main-icons/placeholder
|
||||
:mid-section-description-user-icon "https://i.picsum.photos/id/810/200/300.jpg?hmac=HgwlXd-OaLOAqhGyCiZDUb_75EgUI4u0GtS7nfgxd8s"
|
||||
:left-section-icon :main-icons/unlocked
|
||||
:left-section-icon-background-color (if (colors/dark?)
|
||||
colors/neutral-80
|
||||
colors/neutral-20)}
|
||||
create-variation #(merge %1 %2)
|
||||
variations {:text-only? base-props
|
||||
:align-left? (create-variation base-props {:align-mid? true})
|
||||
:one-icon-align-left? (create-variation base-props {:one-icon-align-left? true
|
||||
:mid-section-type :text-with-one-icon})
|
||||
:one-icon-align-right? (create-variation base-props {:one-icon-align-left? false
|
||||
:mid-section-type :text-with-one-icon})
|
||||
:two-icons? (create-variation base-props {:mid-section-type :text-with-two-icons})
|
||||
:user-icon? (create-variation base-props {:align-mid? true
|
||||
:horizontal-description? false
|
||||
:mid-section-type :text-with-one-icon})
|
||||
:empty? (create-variation base-props {:mid-section-main-text ""
|
||||
:mid-section-description ""})
|
||||
:align-left-with-icon? (create-variation base-props {:align-mid? true
|
||||
:mid-section-type :text-with-one-icon})
|
||||
:align-left-top-down-text? (create-variation base-props {:align-mid? true
|
||||
:horizontal-description? false
|
||||
:mid-section-type :text-with-description})}
|
||||
state (reagent/atom (-> (get variations (:selected-variation @selected-variation))
|
||||
(assoc :right-section-icons (repeat (:number-of-right-icons @selected-variation) right-icon))))]
|
||||
(fn []
|
||||
[rn/view {:margin-bottom 50
|
||||
:padding 16}
|
||||
[rn/view {:flex 1}
|
||||
[preview/customizer selected-variation descriptor]]
|
||||
[rn/view {:padding-vertical 30
|
||||
:flex-direction :row
|
||||
:justify-content :center}
|
||||
[quo2/page-nav @state]]])))
|
||||
|
||||
(def ^:private trackable-cool-preview (reagent/track cool-preview selected-variation))
|
||||
|
||||
(defn preview-page-nav []
|
||||
[rn/view {:background-color (colors/theme-colors colors/white
|
||||
colors/neutral-90)
|
||||
:flex 1}
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [@trackable-cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -14,7 +14,8 @@
|
||||
[rn/view {:padding-vertical 60
|
||||
:align-items :center}
|
||||
[quo2/disclaimer
|
||||
{:container-style {:margin-bottom 40}
|
||||
{:checked? @checked?
|
||||
:container-style {:margin-bottom 40}
|
||||
:on-change #(swap! checked? not)}
|
||||
"I agree with the community rules"]
|
||||
[button/button
|
||||
|
||||
@@ -1,658 +1,97 @@
|
||||
(ns status-im.activity-center.core
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.data-store.activities :as data-store.activities]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.datetime :as utils.datetime]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
;;;; Notification reconciliation
|
||||
|
||||
(def response-notifications
|
||||
[{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f",
|
||||
:name "0x047c65",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f20",
|
||||
:timestamp 1665167287000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAeElEQVR4nOzR0QnCMBhGURV3cR53cQx3cR6naRfoQ6EtXH7OeQwh5PI9bkMIqRFSI6RGSI2QGiE1QmqE1AipEVIzJuS59+L3/1u2zj+v9/2Mjxx9f8wiQmqE1AipEVIjpEZIjZAaIVxkzCJCaoTUCKkRUrMGAAD////ICGUlBQ5nAAAAAElFTkSuQmCC",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665167287000,
|
||||
:alias "Darkseagreen Colorless Honeybee",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f",
|
||||
:id
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f20",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x04892d0884fb44a940853ba988ce14b4c7c18351ea617bf29a5ceaa9eca03a8e1770f66282d9af9f5644578f8fcb8f4ff8fd926d8b389db4384ec91492aee8406d",
|
||||
:name "0x04892d",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x04892d0884fb44a940853ba988ce14b4c7c18351ea617bf29a5ceaa9eca03a8e1770f66282d9af9f5644578f8fcb8f4ff8fd926d8b389db4384ec91492aee8406d",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x04892d0884fb44a940853ba988ce14b4c7c18351ea617bf29a5ceaa9eca03a8e1770f66282d9af9f5644578f8fcb8f4ff8fd926d8b389db4384ec91492aee8406d20",
|
||||
:timestamp 1665100538000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiElEQVR4nOzWUQmAYAwHcRW7GMwKxrCCwUyjBRSUMTj+3O/Rh0+Owdg0hDCExhAaQ2gMoYkJmbse3o/zevq+rcvY8b+YiRhCYwjN5w3SvYWq78dMxBAaQ2i8tWgMoTGExhAaQ2gMoSnfPW831V/VGyxmIobQGKImMRMxhMYQGkNoDKG5AwAA//9P5BRl2i6T5QAAAABJRU5ErkJggg==",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665100538000,
|
||||
:alias "Amused Neighboring Senegalpython",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x04892d0884fb44a940853ba988ce14b4c7c18351ea617bf29a5ceaa9eca03a8e1770f66282d9af9f5644578f8fcb8f4ff8fd926d8b389db4384ec91492aee8406d",
|
||||
:id
|
||||
"0x04892d0884fb44a940853ba988ce14b4c7c18351ea617bf29a5ceaa9eca03a8e1770f66282d9af9f5644578f8fcb8f4ff8fd926d8b389db4384ec91492aee8406d20",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x04d7b7648d9ef3cacdb64755d2fed9a70e4eb1e287e5f59c58cb3eda2485bdc0d0fb0f88f87dcd568637f2213205defee3fbd864bfe279bf87e43301a32647b88f",
|
||||
:name "0x04d7b7",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x04d7b7648d9ef3cacdb64755d2fed9a70e4eb1e287e5f59c58cb3eda2485bdc0d0fb0f88f87dcd568637f2213205defee3fbd864bfe279bf87e43301a32647b88f",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x04d7b7648d9ef3cacdb64755d2fed9a70e4eb1e287e5f59c58cb3eda2485bdc0d0fb0f88f87dcd568637f2213205defee3fbd864bfe279bf87e43301a32647b88f20",
|
||||
:timestamp 1665097520000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAgUlEQVR4nOzWwQmAMBAFURV7sRI7sgw7shKr0XtASMCF4TPvHALDXv4yhTCExhAaQ2gMoYkJWXsfnvf1jHx8bPtc+U8r5iKG0BhCYwiNITSG0HRvrS+jm+qvDdaKuYghNIaoSMxFDKExhMYQGkNoDKExhMYQGkNoDKExhOYNAAD//0iXEGcISwhOAAAAAElFTkSuQmCC",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 3,
|
||||
:whisperTimestamp 1665097520000,
|
||||
:alias "Honeydew Golden Amazondolphin",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x04d7b7648d9ef3cacdb64755d2fed9a70e4eb1e287e5f59c58cb3eda2485bdc0d0fb0f88f87dcd568637f2213205defee3fbd864bfe279bf87e43301a32647b88f",
|
||||
:id
|
||||
"0x04d7b7648d9ef3cacdb64755d2fed9a70e4eb1e287e5f59c58cb3eda2485bdc0d0fb0f88f87dcd568637f2213205defee3fbd864bfe279bf87e43301a32647b88f20",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x040185b964f42f2f11a07bb3275478605cf9f5a2f79af8a15d30baeaa9fe47e19d636d6461b797cfd2edf57a51e7be912c81e60698758bf145eaa611ae30f921df",
|
||||
:name "0x040185",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x040185b964f42f2f11a07bb3275478605cf9f5a2f79af8a15d30baeaa9fe47e19d636d6461b797cfd2edf57a51e7be912c81e60698758bf145eaa611ae30f921df",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x040185b964f42f2f11a07bb3275478605cf9f5a2f79af8a15d30baeaa9fe47e19d636d6461b797cfd2edf57a51e7be912c81e60698758bf145eaa611ae30f921df20",
|
||||
:timestamp 1665097287000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAfklEQVR4nOzYsQmAMABEURV3sXI7x3A7K6fRBSyEcPA5/istIp+DFFmmEobQGEJjCI0hNDUha+rg876er+/Hts+J/9UsYgiNITS/b5D0LTR6fs0ihtAYQmMIjSE0hiikZhFDaAyh8V2LxhAaQxRSs4ghNIbQGEJjCM0bAAD//5fvEGQwrcNWAAAAAElFTkSuQmCC",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665097287000,
|
||||
:alias "Quizzical Private Anteater",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x040185b964f42f2f11a07bb3275478605cf9f5a2f79af8a15d30baeaa9fe47e19d636d6461b797cfd2edf57a51e7be912c81e60698758bf145eaa611ae30f921df",
|
||||
:id
|
||||
"0x040185b964f42f2f11a07bb3275478605cf9f5a2f79af8a15d30baeaa9fe47e19d636d6461b797cfd2edf57a51e7be912c81e60698758bf145eaa611ae30f921df20",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x046bf5a02fd3a28f82f656bbfbfcaf9bec021b3617c3dc043dc8353f4f6f009ac53df5eba2a2ae63b6f77413a1ad9a054f5c4509ce68b4bf0e688186ab95d2fca7",
|
||||
:name "0x046bf5",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x046bf5a02fd3a28f82f656bbfbfcaf9bec021b3617c3dc043dc8353f4f6f009ac53df5eba2a2ae63b6f77413a1ad9a054f5c4509ce68b4bf0e688186ab95d2fca7",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x046bf5a02fd3a28f82f656bbfbfcaf9bec021b3617c3dc043dc8353f4f6f009ac53df5eba2a2ae63b6f77413a1ad9a054f5c4509ce68b4bf0e688186ab95d2fca720",
|
||||
:timestamp 1665089696000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAgklEQVR4nOzWQQpAYABEYeQu9s7mGM5m7zTsZaE09Zret5R+vab+TEMJQ2gMoTGExhCampA5dfB+Htfb821Zx8T3ahYxhMYQms+3VvoW+nt+zSKG0BiikJpFDKExhCb2r5V+/6lmEUNoDFFIzSKG0BhCYwiNITSG0BhCYwjNHQAA///zHxhnUGfT1gAAAABJRU5ErkJggg==",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665089696000,
|
||||
:alias "Growling Marvelous Parrot",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x046bf5a02fd3a28f82f656bbfbfcaf9bec021b3617c3dc043dc8353f4f6f009ac53df5eba2a2ae63b6f77413a1ad9a054f5c4509ce68b4bf0e688186ab95d2fca7",
|
||||
:id
|
||||
"0x046bf5a02fd3a28f82f656bbfbfcaf9bec021b3617c3dc043dc8353f4f6f009ac53df5eba2a2ae63b6f77413a1ad9a054f5c4509ce68b4bf0e688186ab95d2fca720",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x044a2e346d30266b1b0a05def37b91a1578ab5e420c6971da1bde04d125c40b40a3ea1fe9519398b3fb354986096700f5887b67bb82a93f6e3dd151edc633b8f67",
|
||||
:name "0x044a2e",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x044a2e346d30266b1b0a05def37b91a1578ab5e420c6971da1bde04d125c40b40a3ea1fe9519398b3fb354986096700f5887b67bb82a93f6e3dd151edc633b8f67",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x044a2e346d30266b1b0a05def37b91a1578ab5e420c6971da1bde04d125c40b40a3ea1fe9519398b3fb354986096700f5887b67bb82a93f6e3dd151edc633b8f6720",
|
||||
:timestamp 1665075842000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAiUlEQVR4nOzWwQmEQBAF0V0xF2Pzbhjejc1oNIKRkR6h+NS7KxYNH6dfCENoDKExhMYQGkNoDKExhCYmZK6+4Dj3a8SHrMv2rzwfcxFDaAyhKS3Fk9aaVdepJeYihtAYQtO9IKP+qd7qXbmYixhCY4g+EnMRQ2gMoTGExhAaQ2gMoTGE5g4AAP//09cMY3Qm6ZsAAAAASUVORK5CYII=",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665075842000,
|
||||
:alias "Stable Sniveling Baldeagle",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x044a2e346d30266b1b0a05def37b91a1578ab5e420c6971da1bde04d125c40b40a3ea1fe9519398b3fb354986096700f5887b67bb82a93f6e3dd151edc633b8f67",
|
||||
:id
|
||||
"0x044a2e346d30266b1b0a05def37b91a1578ab5e420c6971da1bde04d125c40b40a3ea1fe9519398b3fb354986096700f5887b67bb82a93f6e3dd151edc633b8f6720",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x043e742bfa6dcd0c93689727ad02ac9e9d418f2a03a783b40d72bc8f0b3144707022ef84ae59a787977275c27ac9421ab094b8fb3908bb80f729f483eff38d84fc",
|
||||
:name "0x043e74",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x043e742bfa6dcd0c93689727ad02ac9e9d418f2a03a783b40d72bc8f0b3144707022ef84ae59a787977275c27ac9421ab094b8fb3908bb80f729f483eff38d84fc",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x043e742bfa6dcd0c93689727ad02ac9e9d418f2a03a783b40d72bc8f0b3144707022ef84ae59a787977275c27ac9421ab094b8fb3908bb80f729f483eff38d84fc20",
|
||||
:timestamp 1665075615000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAkklEQVR4nOzWwQnDMBAF0SSkl3SQylJGKksHqca+GwvWyGuGz7yzDho+CD1uIQyhMYTGEBpDaGJCntWD399/6b3Kvs/7da+ci1nEEBpD1CRmEUNoDKGZ/muN/kLd57diFjGExhCa8qt1VPW1OUvMIobQGEIz/bJc/acaiVnEEBpD1CRmEUNoDKExhMYQmjUAAP//o5AZOL4SLM8AAAAASUVORK5CYII=",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665075615000,
|
||||
:alias "Trusty Nautical Zethusspinipes",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x043e742bfa6dcd0c93689727ad02ac9e9d418f2a03a783b40d72bc8f0b3144707022ef84ae59a787977275c27ac9421ab094b8fb3908bb80f729f483eff38d84fc",
|
||||
:id
|
||||
"0x043e742bfa6dcd0c93689727ad02ac9e9d418f2a03a783b40d72bc8f0b3144707022ef84ae59a787977275c27ac9421ab094b8fb3908bb80f729f483eff38d84fc20",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x0435b461849c0af696b2f71ad95e9c57053722a2390c833b304b4284b00466f52f940004d45f0fee149cf6ed65b8ff856921d40059344a01e68b2fa9dae82e4900",
|
||||
:name "0x0435b4",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x0435b461849c0af696b2f71ad95e9c57053722a2390c833b304b4284b00466f52f940004d45f0fee149cf6ed65b8ff856921d40059344a01e68b2fa9dae82e4900",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x0435b461849c0af696b2f71ad95e9c57053722a2390c833b304b4284b00466f52f940004d45f0fee149cf6ed65b8ff856921d40059344a01e68b2fa9dae82e490020",
|
||||
:timestamp 1665074686000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAgUlEQVR4nOzWsQmAMBgFYRV3cTwbx7BxPKfRPigYJOR43FdKEI7X/NMQwhAaQ2gMoTGEJiZk/vrw2M/r6fu6LWOP96WYRQyhMUSNxCxiCI0hNL9vrTe1N1Xtf0oxixhCYwiNITSG0BiiRmIWMYTGEBpDaAyhMYTGEBpDaO4AAAD//5TbFGUr+nc/AAAAAElFTkSuQmCC",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 3,
|
||||
:whisperTimestamp 1665074686000,
|
||||
:alias "Remote Vapid Honeyeater",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x0435b461849c0af696b2f71ad95e9c57053722a2390c833b304b4284b00466f52f940004d45f0fee149cf6ed65b8ff856921d40059344a01e68b2fa9dae82e4900",
|
||||
:id
|
||||
"0x0435b461849c0af696b2f71ad95e9c57053722a2390c833b304b4284b00466f52f940004d45f0fee149cf6ed65b8ff856921d40059344a01e68b2fa9dae82e490020",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x04f18135a0d5e904d5a877c24ad286d227b1a91ee583d61f16ba71de801d9d92df330696c5788b0810999c4710271584ec84eac223bc5f7f9eaf483b0ed2bd2093",
|
||||
:name "0x04f181",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x04f18135a0d5e904d5a877c24ad286d227b1a91ee583d61f16ba71de801d9d92df330696c5788b0810999c4710271584ec84eac223bc5f7f9eaf483b0ed2bd2093",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x04f18135a0d5e904d5a877c24ad286d227b1a91ee583d61f16ba71de801d9d92df330696c5788b0810999c4710271584ec84eac223bc5f7f9eaf483b0ed2bd209320",
|
||||
:timestamp 1665073831000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAkElEQVR4nOzY0QmAMAwGYRV3cQI3cww3cwKn0QUUAm3h+LnvUYpwBELpMoUwhMYQGkNoDKGJCVlbf3Cd9/P1fT+2ucf5qpiJGEJjCE15U/xtm9Gq2yxmIobQGELTfNfqdadq3YoxEzGExhAaQ2gMoTGEZti7Vq/zVTETMYTGEA0SMxFDaAyhMYTGEJo3AAD//6aKGsYhz2MYAAAAAElFTkSuQmCC",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665073831000,
|
||||
:alias "Nippy Idolized Armyworm",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x04f18135a0d5e904d5a877c24ad286d227b1a91ee583d61f16ba71de801d9d92df330696c5788b0810999c4710271584ec84eac223bc5f7f9eaf483b0ed2bd2093",
|
||||
:id
|
||||
"0x04f18135a0d5e904d5a877c24ad286d227b1a91ee583d61f16ba71de801d9d92df330696c5788b0810999c4710271584ec84eac223bc5f7f9eaf483b0ed2bd209320",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}
|
||||
{:replyMessage nil,
|
||||
:read true,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x04b5aed12d7de0f72a7e3494b7d3ab20b316a9fde5732a3eb1d0f41a957900f764d725a3e725152c37bb615ab2251349ef84e92a145333d8ece9a598cae75681e7",
|
||||
:name "0x04b5ae",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x04b5aed12d7de0f72a7e3494b7d3ab20b316a9fde5732a3eb1d0f41a957900f764d725a3e725152c37bb615ab2251349ef84e92a145333d8ece9a598cae75681e7",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x04b5aed12d7de0f72a7e3494b7d3ab20b316a9fde5732a3eb1d0f41a957900f764d725a3e725152c37bb615ab2251349ef84e92a145333d8ece9a598cae75681e720",
|
||||
:timestamp 1665064413000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAm0lEQVR4nOzXsQnDMBBA0SRkl7QZLmNkOLeexm5cCcmcsIQ/x3+lUfM5OM6vRxKG0BhCYwiNITRpQt7Rh/912Wrff5/v8473pTQTMYTGEJrQRjjT2ja9otupJc1EDKExhGbardXLW+tgCI0hNOGt1TLqT/CqNBMxhMYQmiF3Us3s26yUZiKG0BiiSdJMxBAaQ2gMoTGEZg8AAP//9ecjm0YKWeEAAAAASUVORK5CYII=",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665064413000,
|
||||
:alias "Scary Quickwitted Wrasse",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x04b5aed12d7de0f72a7e3494b7d3ab20b316a9fde5732a3eb1d0f41a957900f764d725a3e725152c37bb615ab2251349ef84e92a145333d8ece9a598cae75681e7",
|
||||
:id
|
||||
"0x04b5aed12d7de0f72a7e3494b7d3ab20b316a9fde5732a3eb1d0f41a957900f764d725a3e725152c37bb615ab2251349ef84e92a145333d8ece9a598cae75681e720",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}])
|
||||
|
||||
(def response-unread-notifications
|
||||
[{:replyMessage nil,
|
||||
:read false,
|
||||
:dismissed false,
|
||||
:chatId
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f",
|
||||
:name "0x047c65",
|
||||
:accepted false,
|
||||
:type 5,
|
||||
:author
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f",
|
||||
:lastMessage nil,
|
||||
:id
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f20",
|
||||
:timestamp 1665167287000,
|
||||
:message
|
||||
{:messageType 0,
|
||||
:identicon
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAeElEQVR4nOzR0QnCMBhGURV3cR53cQx3cR6naRfoQ6EtXH7OeQwh5PI9bkMIqRFSI6RGSI2QGiE1QmqE1AipEVIzJuS59+L3/1u2zj+v9/2Mjxx9f8wiQmqE1AipEVIjpEZIjZAaIVxkzCJCaoTUCKkRUrMGAAD////ICGUlBQ5nAAAAAElFTkSuQmCC",
|
||||
:replace "",
|
||||
:chatId "",
|
||||
:displayName "",
|
||||
:lineCount 0,
|
||||
:contactRequestState 2,
|
||||
:whisperTimestamp 1665167287000,
|
||||
:alias "Darkseagreen Colorless Honeybee",
|
||||
:seen true,
|
||||
:gapParameters {},
|
||||
:from
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f",
|
||||
:id
|
||||
"0x047c654a4b35e4c3605c0eacf68364dd43140616e4d96ae362c4bf7c5ae3f1a3c03ad5935ae1face369bf96edda4ec02459b33964f1a7781036824f1e528c21b2f20",
|
||||
:parsedText
|
||||
[{:type "paragraph",
|
||||
:children [{:literal "Please add me to your contacts"}]}],
|
||||
:contentType 11,
|
||||
:clock 0,
|
||||
:localChatId "",
|
||||
:timestamp 0,
|
||||
:ensName "",
|
||||
:quotedMessage nil,
|
||||
:rtl false,
|
||||
:responseTo "",
|
||||
:text "Please add me to your contacts"}}])
|
||||
|
||||
(defn- update-notifications
|
||||
"Insert `new-notifications` in `db-notifications`.
|
||||
|
||||
Although correct, this is a naive implementation for reconciling notifications
|
||||
because for every notification in `new-notifications`, linear scans will be
|
||||
performed to remove it and sorting will be performed for every new insertion.
|
||||
If the number of existing notifications cached in the app db becomes
|
||||
~excessively~ big, this implementation will probably need to be revisited."
|
||||
[db-notifications new-notifications]
|
||||
(reduce (fn [acc {:keys [id type read] :as notification}]
|
||||
(let [filter-status (if read :read :unread)]
|
||||
(cond-> (-> acc
|
||||
(update-in [type :read :data]
|
||||
(fn [data]
|
||||
(remove #(= id (:id %)) data)))
|
||||
(update-in [type :unread :data]
|
||||
(fn [data]
|
||||
(remove #(= id (:id %)) data))))
|
||||
(not (or (:dismissed notification) (:accepted notification)))
|
||||
(update-in [type filter-status :data]
|
||||
(fn [data]
|
||||
(->> notification
|
||||
(conj data)
|
||||
(sort-by (juxt :timestamp :id))
|
||||
reverse))))))
|
||||
db-notifications
|
||||
new-notifications))
|
||||
[old new]
|
||||
(let [ids-to-be-removed (->> new
|
||||
(filter #(or (:dismissed %) (:accepted %)))
|
||||
(map :id))
|
||||
grouped-new (apply dissoc (group-by :id new) ids-to-be-removed)
|
||||
grouped-old (apply dissoc (group-by :id old) ids-to-be-removed)]
|
||||
(->> (merge grouped-old grouped-new)
|
||||
vals
|
||||
(map first))))
|
||||
|
||||
(fx/defn notifications-reconcile
|
||||
{:events [:activity-center.notifications/reconcile]}
|
||||
[{:keys [db]} new-notifications]
|
||||
(when (seq new-notifications)
|
||||
{:db (update-in db [:activity-center :notifications]
|
||||
update-notifications new-notifications)}))
|
||||
(let [{read-new true
|
||||
unread-new false} (group-by :read new-notifications)
|
||||
read-old (get-in db [:activity-center :notifications-read :data])
|
||||
unread-old (get-in db [:activity-center :notifications-unread :data])]
|
||||
{:db (-> db
|
||||
(assoc-in [:activity-center :notifications-read :data]
|
||||
(update-notifications read-old read-new))
|
||||
(assoc-in [:activity-center :notifications-unread :data]
|
||||
(update-notifications unread-old unread-new)))}))
|
||||
|
||||
;;;; Notifications fetching and pagination
|
||||
|
||||
(def defaults
|
||||
{:filter-status :unread
|
||||
:filter-type constants/activity-center-notification-type-no-type
|
||||
:notifications-per-page 10})
|
||||
(def notifications-per-page
|
||||
20)
|
||||
|
||||
(def start-or-end-cursor
|
||||
"")
|
||||
|
||||
(defn- valid-cursor?
|
||||
[cursor]
|
||||
(and (some? cursor)
|
||||
(not= cursor start-or-end-cursor)))
|
||||
|
||||
(defn- filter-status->rpc-method
|
||||
[filter-status]
|
||||
(if (= filter-status :read)
|
||||
(defn notifications-group->rpc-method
|
||||
[notifications-group]
|
||||
(if (= notifications-group :notifications-read)
|
||||
"wakuext_readActivityCenterNotifications"
|
||||
"wakuext_unreadActivityCenterNotifications"))
|
||||
|
||||
(defn notifications-read-status->group
|
||||
[status-filter]
|
||||
(if (= status-filter :read)
|
||||
:notifications-read
|
||||
:notifications-unread))
|
||||
|
||||
(fx/defn notifications-fetch
|
||||
[{:keys [db]} {:keys [cursor filter-type filter-status reset-data?]}]
|
||||
(when-not (get-in db [:activity-center :notifications filter-type filter-status :loading?])
|
||||
{:db (assoc-in db [:activity-center :notifications filter-type filter-status :loading?] true)
|
||||
::json-rpc/call [{:method (filter-status->rpc-method filter-status)
|
||||
:params [cursor (defaults :notifications-per-page) filter-type]
|
||||
:on-success #(re-frame/dispatch [:activity-center.notifications/fetch-success filter-type filter-status reset-data? %])
|
||||
:on-error #(re-frame/dispatch [:activity-center.notifications/fetch-error filter-type filter-status %])}]}))
|
||||
[{:keys [db]} cursor notifications-group]
|
||||
(when-not (get-in db [:activity-center notifications-group :loading?])
|
||||
{:db (assoc-in db [:activity-center notifications-group :loading?] true)
|
||||
::json-rpc/call [{:method (notifications-group->rpc-method notifications-group)
|
||||
:params [cursor notifications-per-page]
|
||||
:on-success #(re-frame/dispatch [:activity-center.notifications/fetch-success notifications-group %])
|
||||
:on-error #(re-frame/dispatch [:activity-center.notifications/fetch-error notifications-group %])}]}))
|
||||
|
||||
(fx/defn notifications-fetch-first-page
|
||||
{:events [:activity-center.notifications/fetch-first-page]}
|
||||
[{:keys [db] :as cofx} {:keys [filter-type filter-status]}]
|
||||
(tap> {:EVT-fetch-first-page (utils.datetime/now->iso8601)})
|
||||
(let [filter-type (or filter-type
|
||||
(get-in db [:activity-center :filter :type]
|
||||
(defaults :filter-type)))
|
||||
filter-status (or filter-status
|
||||
(get-in db [:activity-center :filter :status]
|
||||
(defaults :filter-status)))]
|
||||
(as-> {:db (-> db
|
||||
(assoc-in [:activity-center :filter :type] filter-type)
|
||||
(assoc-in [:activity-center :filter :status] filter-status)
|
||||
(assoc-in [:activity-center :notifications filter-type filter-status :loading?] true)
|
||||
;; Comment this assoc call and the UI becomes less
|
||||
;; responsive. If you use the fake orange rectangles in the
|
||||
;; UI you still notice the latency when this line is
|
||||
;; commented. This is worrisome news.
|
||||
(assoc-in [:activity-center :notifications filter-type filter-status :data] [])
|
||||
)}
|
||||
cofx'
|
||||
(if (and (= 0 filter-type) (= :read filter-status))
|
||||
(assoc cofx' :dispatch-later [;; Lower the delay and eventually the UI becomes less responsive.
|
||||
{:ms 50
|
||||
:dispatch [:activity-center.notifications/fetch-success
|
||||
filter-type
|
||||
filter-status
|
||||
true
|
||||
{:cursor "" :notifications response-notifications}]}])
|
||||
(if (and (= 0 filter-type) (= :unread filter-status))
|
||||
(assoc cofx' :dispatch-later [;; Lower the delay and eventually the UI becomes less responsive.
|
||||
{:ms 50
|
||||
:dispatch [:activity-center.notifications/fetch-success
|
||||
filter-type
|
||||
filter-status
|
||||
true
|
||||
{:cursor "" :notifications response-unread-notifications}]}])
|
||||
(assoc cofx' :dispatch [:activity-center.notifications/fetch-success
|
||||
filter-type
|
||||
filter-status
|
||||
true
|
||||
{:cursor "" :notifications []}]))))))
|
||||
[{:keys [db] :as cofx} {:keys [status-filter] :or {status-filter :unread}}]
|
||||
(let [notifications-group (notifications-read-status->group status-filter)]
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:activity-center :current-status-filter] status-filter)
|
||||
(update-in [:activity-center notifications-group] dissoc :loading?)
|
||||
(update-in [:activity-center notifications-group] dissoc :data))}
|
||||
(notifications-fetch start-or-end-cursor notifications-group))))
|
||||
|
||||
(fx/defn notifications-fetch-next-page
|
||||
{:events [:activity-center.notifications/fetch-next-page]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [type status]} (get-in db [:activity-center :filter])
|
||||
{:keys [cursor]} (get-in db [:activity-center :notifications type status])]
|
||||
(when (valid-cursor? cursor)
|
||||
(tap> {:EVT-fetch-next-page (utils.datetime/now->iso8601)})
|
||||
(notifications-fetch cofx {:cursor cursor
|
||||
:filter-type type
|
||||
:filter-status status
|
||||
:reset-data? false}))))
|
||||
(let [status-filter (get-in db [:activity-center :current-status-filter])
|
||||
notifications-group (notifications-read-status->group status-filter)
|
||||
{:keys [cursor]} (get-in db [:activity-center notifications-group])]
|
||||
(when-not (= cursor start-or-end-cursor)
|
||||
(notifications-fetch cofx cursor notifications-group))))
|
||||
|
||||
(fx/defn notifications-fetch-success
|
||||
{:events [:activity-center.notifications/fetch-success]}
|
||||
[{:keys [db]}
|
||||
filter-type
|
||||
filter-status
|
||||
reset-data?
|
||||
{:keys [cursor notifications]}]
|
||||
(tap> {:EVT-fetch-success (utils.datetime/now->iso8601)})
|
||||
(let [processed (map data-store.activities/<-rpc notifications)]
|
||||
{:db (-> db
|
||||
(assoc-in [:activity-center :notifications filter-type filter-status :cursor] cursor)
|
||||
(update-in [:activity-center :notifications filter-type filter-status] dissoc :loading?)
|
||||
(update-in [:activity-center :notifications filter-type filter-status :data]
|
||||
(if reset-data?
|
||||
(constantly processed)
|
||||
#(concat %1 processed))))}))
|
||||
[{:keys [db]} notifications-group {:keys [cursor notifications]}]
|
||||
{:db (-> db
|
||||
(update-in [:activity-center notifications-group] dissoc :loading?)
|
||||
(assoc-in [:activity-center notifications-group :cursor] cursor)
|
||||
(update-in [:activity-center notifications-group :data]
|
||||
concat
|
||||
(map data-store.activities/<-rpc notifications)))})
|
||||
|
||||
(fx/defn notifications-fetch-error
|
||||
{:events [:activity-center.notifications/fetch-error]}
|
||||
[{:keys [db]} filter-type filter-status error]
|
||||
[{:keys [db]} notifications-group error]
|
||||
(log/warn "Failed to load Activity Center notifications" error)
|
||||
{:db (update-in db [:activity-center :notifications filter-type filter-status] dissoc :loading?)})
|
||||
|
||||
(fx/defn notifications-quick-toggle
|
||||
{:events [:activity-center.notifications/quick-toggle]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc db :activity-center-notifications-filter-status
|
||||
(if (= :read (:activity-center-notifications-filter-status db))
|
||||
:unread
|
||||
:read))})
|
||||
|
||||
(comment
|
||||
(fx/defn notifications-quick-toggle
|
||||
{:events [:activity-center.notifications/quick-toggle]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:activity-center :filter :status]
|
||||
(if (= :read (get-in db [:activity-center :filter :status]))
|
||||
:unread
|
||||
:read))})
|
||||
|
||||
(re-frame/reg-event-db
|
||||
:dev/reset-activity-center
|
||||
(fn [db]
|
||||
(-> db
|
||||
(assoc-in [:activity-center]
|
||||
{:filter {:status :read
|
||||
:type 0}
|
||||
:notifications {}}))))
|
||||
|
||||
(re-frame/dispatch [:dev/reset-activity-center]))
|
||||
{:db (update-in db [:activity-center notifications-group] dissoc :loading?)})
|
||||
|
||||
@@ -2,285 +2,99 @@
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[day8.re-frame.test :as rf-test]
|
||||
[re-frame.core :as rf]
|
||||
[status-im.constants :as c]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
status-im.events
|
||||
[status-im.test-helpers :as h]))
|
||||
[status-im.test-helpers :as h]
|
||||
status-im.events))
|
||||
|
||||
(defn setup []
|
||||
(h/register-helper-events)
|
||||
(rf/dispatch [:init/app-started]))
|
||||
|
||||
(defn remove-color-key
|
||||
"Remove `:color` key from notifications because they have random values that we
|
||||
can't assert against."
|
||||
[grouped-notifications {:keys [type status]}]
|
||||
(update-in grouped-notifications
|
||||
[type status :data]
|
||||
(fn [old _]
|
||||
(map #(dissoc % :color) old))
|
||||
nil))
|
||||
|
||||
(deftest notifications-reconcile-test
|
||||
(testing "does nothing when there are no new notifications"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(let [notifications {c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat}
|
||||
{:id "0x2"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}
|
||||
:unread {:cursor ""
|
||||
:data [{:id "0x3"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}}
|
||||
c/activity-center-notification-type-private-group-chat
|
||||
{:unread {:cursor ""
|
||||
:data [{:id "0x4"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat}]}}}]
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications])
|
||||
(let [read [{:id "0x1" :read true}]
|
||||
unread [{:id "0x4" :read false}]]
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-read :data] read])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-unread :data] unread])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/reconcile nil])
|
||||
|
||||
(is (= notifications (get-in (h/db) [:activity-center :notifications]))))))
|
||||
(is (= read (get-in (h/db) [:activity-center :notifications-read :data])))
|
||||
(is (= unread (get-in (h/db) [:activity-center :notifications-unread :data]))))))
|
||||
|
||||
(testing "removes dismissed or accepted notifications"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
|
||||
{c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x1" :read true :type c/activity-center-notification-type-one-to-one-chat}
|
||||
{:id "0x2" :read true :type c/activity-center-notification-type-one-to-one-chat}]}
|
||||
:unread {:cursor ""
|
||||
:data [{:id "0x3" :read false :type c/activity-center-notification-type-one-to-one-chat}]}}
|
||||
2 {:unread {:cursor ""
|
||||
:data [{:id "0x4" :read false :type 2}
|
||||
{:id "0x6" :read false :type 2}]}}}])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-read :data]
|
||||
[{:id "0x1" :read true}
|
||||
{:id "0x2" :read true}
|
||||
{:id "0x3" :read true}]])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-unread :data]
|
||||
[{:id "0x4" :read false}
|
||||
{:id "0x5" :read false}
|
||||
{:id "0x6" :read false}]])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/reconcile
|
||||
[{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:dismissed true}
|
||||
{:id "0x3"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:accepted true}
|
||||
{:id "0x4"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat
|
||||
:dismissed true}
|
||||
{:id "0x5"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat
|
||||
:accepted true}]])
|
||||
[{:id "0x1" :read true :dismissed true}
|
||||
{:id "0x3" :read true :accepted true}
|
||||
{:id "0x4" :read false :dismissed true}
|
||||
{:id "0x5" :read false :accepted true}]])
|
||||
|
||||
(is (= {c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x2"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}
|
||||
:unread {:cursor ""
|
||||
:data []}}
|
||||
c/activity-center-notification-type-private-group-chat
|
||||
{:read {:data []}
|
||||
:unread {:cursor ""
|
||||
:data [{:id "0x6"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat}]}}}
|
||||
(get-in (h/db) [:activity-center :notifications])))))
|
||||
(is (= [{:id "0x2" :read true}]
|
||||
(get-in (h/db) [:activity-center :notifications-read :data])))
|
||||
(is (= [{:id "0x6" :read false}]
|
||||
(get-in (h/db) [:activity-center :notifications-unread :data])))))
|
||||
|
||||
(testing "replaces old notifications with newly arrived ones"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
|
||||
{c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}}
|
||||
c/activity-center-notification-type-private-group-chat
|
||||
{:unread {:cursor ""
|
||||
:data [{:id "0x4"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat}
|
||||
{:id "0x6"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat}]}}}])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-read :data]
|
||||
[{:id "0x1" :read true}
|
||||
{:id "0x2" :read true}]])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-unread :data]
|
||||
[{:id "0x3" :read false}
|
||||
{:id "0x4" :read false}]])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/reconcile
|
||||
[{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:last-message {}}
|
||||
{:id "0x4"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat
|
||||
:author "0xabc"}
|
||||
{:id "0x6"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat}]])
|
||||
[{:id "0x1" :read true :name "ABC"}
|
||||
{:id "0x3" :read false :name "XYZ"}]])
|
||||
|
||||
(is (= {c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:last-message {}}]}
|
||||
:unread {:data []}}
|
||||
c/activity-center-notification-type-private-group-chat
|
||||
{:read {:data []}
|
||||
:unread {:cursor ""
|
||||
:data [{:id "0x6"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat}
|
||||
{:id "0x4"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-private-group-chat
|
||||
:author "0xabc"}]}}}
|
||||
(get-in (h/db) [:activity-center :notifications])))))
|
||||
|
||||
(testing "reconciles notifications that switched their read/unread status"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
|
||||
{c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}}}])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/reconcile
|
||||
[{:id "0x1"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]])
|
||||
|
||||
(is (= {c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data []}
|
||||
:unread {:data [{:id "0x1"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}}}
|
||||
(get-in (h/db) [:activity-center :notifications])))))
|
||||
|
||||
;; Sorting by timestamp and ID is compatible with what the backend does when
|
||||
;; returning paginated results.
|
||||
(testing "sorts notifications by timestamp and id in descending order"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
|
||||
{c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x1" :read true :type c/activity-center-notification-type-one-to-one-chat :timestamp 1}
|
||||
{:id "0x2" :read true :type c/activity-center-notification-type-one-to-one-chat :timestamp 1}]}
|
||||
:unread {:cursor ""
|
||||
:data [{:id "0x3" :read false :type c/activity-center-notification-type-one-to-one-chat :timestamp 50}
|
||||
{:id "0x4" :read false :type c/activity-center-notification-type-one-to-one-chat :timestamp 100}
|
||||
{:id "0x5" :read false :type c/activity-center-notification-type-one-to-one-chat :timestamp 100}]}}}])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/reconcile
|
||||
[{:id "0x1" :read true :type c/activity-center-notification-type-one-to-one-chat :timestamp 1 :last-message {}}
|
||||
{:id "0x4" :read false :type c/activity-center-notification-type-one-to-one-chat :timestamp 100 :last-message {}}]])
|
||||
|
||||
(is (= {c/activity-center-notification-type-one-to-one-chat
|
||||
{:read {:cursor ""
|
||||
:data [{:id "0x2"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:timestamp 1}
|
||||
{:id "0x1"
|
||||
:read true
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:timestamp 1
|
||||
:last-message {}}]}
|
||||
:unread {:cursor ""
|
||||
:data [{:id "0x5"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:timestamp 100}
|
||||
{:id "0x4"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:timestamp 100
|
||||
:last-message {}}
|
||||
{:id "0x3"
|
||||
:read false
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:timestamp 50}]}}}
|
||||
(get-in (h/db) [:activity-center :notifications]))))))
|
||||
(is (= [{:id "0x1" :read true :name "ABC"}
|
||||
{:id "0x2" :read true}]
|
||||
(get-in (h/db) [:activity-center :notifications-read :data])))
|
||||
(is (= [{:id "0x3" :read false :name "XYZ"}
|
||||
{:id "0x4" :read false}]
|
||||
(get-in (h/db) [:activity-center :notifications-unread :data]))))))
|
||||
|
||||
(deftest notifications-fetch-test
|
||||
(testing "fetches first page"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks
|
||||
::json-rpc/call
|
||||
:on-success (constantly {:cursor "10"
|
||||
:notifications [{:id "0x1"
|
||||
:type c/activity-center-notification-type-one-to-one-chat
|
||||
:read false
|
||||
:chatId "0x9"}]}))
|
||||
(h/stub-fx-with-callbacks ::json-rpc/call
|
||||
:on-success (constantly {:cursor "10"
|
||||
:notifications [{:chatId "0x1"}]}))
|
||||
(h/spy-fx spy-queue ::json-rpc/call)
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/fetch-first-page
|
||||
{:filter-type c/activity-center-notification-type-one-to-one-chat}])
|
||||
(rf/dispatch [:activity-center.notifications/fetch-first-page])
|
||||
|
||||
(is (= :unread (get-in (h/db) [:activity-center :filter :status])))
|
||||
(is (= "" (get-in @spy-queue [0 :args 0 :params 0]))
|
||||
"Should be called with empty cursor when fetching first page")
|
||||
(is (= {c/activity-center-notification-type-one-to-one-chat
|
||||
{:unread {:cursor "10"
|
||||
:data [{:chat-id "0x9"
|
||||
:chat-name nil
|
||||
:chat-type c/activity-center-notification-type-one-to-one-chat
|
||||
:group-chat false
|
||||
:id "0x1"
|
||||
:public? false
|
||||
:last-message nil
|
||||
:message nil
|
||||
:read false
|
||||
:reply-message nil
|
||||
:type c/activity-center-notification-type-one-to-one-chat}]}}}
|
||||
(remove-color-key (get-in (h/db) [:activity-center :notifications])
|
||||
{:status :unread
|
||||
:type c/activity-center-notification-type-one-to-one-chat}))))))
|
||||
(is (= :unread (get-in (h/db) [:activity-center :current-status-filter])))
|
||||
(is (nil? (get-in (h/db) [:activity-center :notifications-unread :loading?])))
|
||||
(is (= "10" (get-in (h/db) [:activity-center :notifications-unread :cursor])))
|
||||
(is (= "" (get-in @spy-queue [0 :args 0 :params 0])))
|
||||
(is (= [{:chat-id "0x1"}]
|
||||
(->> (get-in (h/db) [:activity-center :notifications-unread :data])
|
||||
(map #(select-keys % [:chat-id]))))))))
|
||||
|
||||
(testing "does not fetch next page when pagination cursor reached the end"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue ::json-rpc/call)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :status]
|
||||
:unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :type]
|
||||
c/activity-center-notification-type-one-to-one-chat])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications c/activity-center-notification-type-one-to-one-chat :unread :cursor]
|
||||
""])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/fetch-next-page])
|
||||
|
||||
(is (= [] @spy-queue)))))
|
||||
|
||||
;; The cursor can be nil sometimes because the reconciliation doesn't care
|
||||
;; about updating the cursor value, but we have to make sure the next page is
|
||||
;; only fetched if the current cursor is valid.
|
||||
(testing "does not fetch next page when cursor is nil"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue ::json-rpc/call)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :status]
|
||||
:unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :type]
|
||||
c/activity-center-notification-type-one-to-one-chat])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications c/activity-center-notification-type-one-to-one-chat :unread :cursor]
|
||||
nil])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :current-status-filter] :unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-unread :cursor] ""])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/fetch-next-page])
|
||||
|
||||
@@ -290,54 +104,30 @@
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/stub-fx-with-callbacks
|
||||
::json-rpc/call
|
||||
:on-success (constantly {:cursor ""
|
||||
:notifications [{:id "0x1"
|
||||
:type c/activity-center-notification-type-mention
|
||||
:read false
|
||||
:chatId "0x9"}]}))
|
||||
(h/stub-fx-with-callbacks ::json-rpc/call
|
||||
:on-success (constantly {:cursor ""
|
||||
:notifications [{:chatId "0x1"}]}))
|
||||
(h/spy-fx spy-queue ::json-rpc/call)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :status]
|
||||
:unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :type]
|
||||
c/activity-center-notification-type-mention])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications c/activity-center-notification-type-mention :unread :cursor]
|
||||
"10"])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :current-status-filter] :unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-unread :cursor] "10"])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/fetch-next-page])
|
||||
|
||||
(is (= "wakuext_unreadActivityCenterNotifications" (get-in @spy-queue [0 :args 0 :method])))
|
||||
(is (= "10" (get-in @spy-queue [0 :args 0 :params 0]))
|
||||
"Should be called with current cursor")
|
||||
(is (= {c/activity-center-notification-type-mention
|
||||
{:unread {:cursor ""
|
||||
:data [{:chat-id "0x9"
|
||||
:chat-name nil
|
||||
:chat-type 3
|
||||
:id "0x1"
|
||||
:last-message nil
|
||||
:message nil
|
||||
:read false
|
||||
:reply-message nil
|
||||
:type c/activity-center-notification-type-mention}]}}}
|
||||
(remove-color-key (get-in (h/db) [:activity-center :notifications])
|
||||
{:status :unread
|
||||
:type c/activity-center-notification-type-mention}))))))
|
||||
(is (= "10" (get-in @spy-queue [0 :args 0 :params 0])))
|
||||
(is (= "" (get-in (h/db) [:activity-center :notifications-unread :cursor])))
|
||||
(is (= [{:chat-id "0x1"}]
|
||||
(->> (get-in (h/db) [:activity-center :notifications-unread :data])
|
||||
(map #(select-keys % [:chat-id]))))))))
|
||||
|
||||
(testing "does not fetch next page while it is still loading"
|
||||
(rf-test/run-test-sync
|
||||
(setup)
|
||||
(let [spy-queue (atom [])]
|
||||
(h/spy-fx spy-queue ::json-rpc/call)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :status]
|
||||
:read])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :type]
|
||||
c/activity-center-notification-type-one-to-one-chat])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications c/activity-center-notification-type-one-to-one-chat :read :cursor]
|
||||
"10"])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications c/activity-center-notification-type-one-to-one-chat :read :loading?]
|
||||
true])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :current-status-filter] :read])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-read :cursor] "10"])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-read :loading?] true])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/fetch-next-page])
|
||||
|
||||
@@ -350,18 +140,13 @@
|
||||
(h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error))
|
||||
(h/spy-event-fx spy-queue :activity-center.notifications/fetch-error)
|
||||
(h/spy-fx spy-queue ::json-rpc/call)
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :status]
|
||||
:unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :filter :type]
|
||||
c/activity-center-notification-type-one-to-one-chat])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications c/activity-center-notification-type-one-to-one-chat :unread :cursor]
|
||||
""])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :current-status-filter] :unread])
|
||||
(rf/dispatch [:test/assoc-in [:activity-center :notifications-unread :cursor] ""])
|
||||
|
||||
(rf/dispatch [:activity-center.notifications/fetch-first-page])
|
||||
|
||||
(is (nil? (get-in (h/db) [:activity-center :notifications c/activity-center-notification-type-one-to-one-chat :unread :loading?])))
|
||||
(is (nil? (get-in (h/db) [:activity-center :notifications-unread :loading?])))
|
||||
(is (= [:activity-center.notifications/fetch-error
|
||||
c/activity-center-notification-type-one-to-one-chat
|
||||
:unread
|
||||
:notifications-unread
|
||||
:fake-error]
|
||||
(:args (last @spy-queue))))))))
|
||||
|
||||
@@ -176,7 +176,6 @@
|
||||
(def ^:const docs-link "https://status.im/docs/")
|
||||
(def ^:const principles-link "https://our.status.im/our-principles/")
|
||||
|
||||
(def ^:const activity-center-notification-type-no-type 0)
|
||||
(def ^:const activity-center-notification-type-one-to-one-chat 1)
|
||||
(def ^:const activity-center-notification-type-private-group-chat 2)
|
||||
(def ^:const activity-center-notification-type-mention 3)
|
||||
@@ -184,13 +183,6 @@
|
||||
(def ^:const activity-center-notification-type-contact-request 5)
|
||||
(def ^:const activity-center-notification-type-contact-request-retracted 6)
|
||||
|
||||
;; TODO: Replace with correct enum values once status-go implements them.
|
||||
(def ^:const activity-center-notification-type-admin 66610)
|
||||
(def ^:const activity-center-notification-type-identity-verification 66611)
|
||||
(def ^:const activity-center-notification-type-tx 66612)
|
||||
(def ^:const activity-center-notification-type-membership 66613)
|
||||
(def ^:const activity-center-notification-type-system 66614)
|
||||
|
||||
(def ^:const visibility-status-unknown 0)
|
||||
(def ^:const visibility-status-automatic 1)
|
||||
(def ^:const visibility-status-dnd 2)
|
||||
|
||||
@@ -328,9 +328,8 @@
|
||||
;; Information Box
|
||||
|
||||
(def closable-information-boxes
|
||||
"[{:id information box id
|
||||
:global? true/false (close information box across all profiles)}]"
|
||||
[])
|
||||
[{:id :ens-banner
|
||||
:global? true}]) ;; global? - close information box across all profiles
|
||||
|
||||
(defn information-box-id-hash [id public-key global?]
|
||||
(if global?
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.wallet.core :as wallet]
|
||||
["@react-native-community/netinfo" :default net-info]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(fx/defn change-network-status
|
||||
[{:keys [db] :as cofx} is-connected?]
|
||||
[{:keys [db] :as cofx} is-connected? reconnected?]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db :network-status (if is-connected? :online :offline))}
|
||||
(cond-> {:db (assoc db :network-status (if is-connected? :online :offline))}
|
||||
reconnected? (assoc :dispatch-later [{:dispatch [:wallet-connect-legacy/get-connector-session-from-db]
|
||||
:ms 1500}]))
|
||||
(when (and is-connected?
|
||||
(or (not= (count (get-in db [:wallet :accounts]))
|
||||
(count (get db :multiaccount/accounts)))
|
||||
@@ -26,29 +29,39 @@
|
||||
|
||||
(fx/defn handle-network-info-change
|
||||
{:events [::network-info-changed]}
|
||||
[{:keys [db] :as cofx} {:keys [isConnected type details] :as state}]
|
||||
[{:keys [db] :as cofx} {:keys [isConnected type details isInternetReachable app-went-offline?] :as state}]
|
||||
(let [old-network-status (:network-status db)
|
||||
old-network-type (:network/type db)
|
||||
connectivity-status (if isConnected :online :offline)
|
||||
status-changed? (= connectivity-status old-network-status)
|
||||
type-changed? (= type old-network-type)]
|
||||
status-changed? (not= connectivity-status old-network-status)
|
||||
type-changed? (= type old-network-type)
|
||||
_ (when (and (not isConnected)
|
||||
(not isInternetReachable)
|
||||
(not @app-went-offline?))
|
||||
(swap! app-went-offline? not))
|
||||
reconnected? (when (and isInternetReachable
|
||||
@app-went-offline?)
|
||||
(swap! app-went-offline? not)
|
||||
true)]
|
||||
(log/debug "[net-info]"
|
||||
"old-network-status" old-network-status
|
||||
"old-network-type" old-network-type
|
||||
"old-network-status" old-network-status
|
||||
"old-network-type" old-network-type
|
||||
"connectivity-status" connectivity-status
|
||||
"type" type
|
||||
"details" details)
|
||||
"type" type
|
||||
"details" details)
|
||||
(fx/merge cofx
|
||||
(when-not status-changed?
|
||||
(change-network-status isConnected))
|
||||
(when (or status-changed? reconnected?)
|
||||
(change-network-status isConnected reconnected?))
|
||||
(when-not type-changed?
|
||||
(change-network-type old-network-type type (:is-connection-expensive details))))))
|
||||
|
||||
(defn add-net-info-listener []
|
||||
(when net-info
|
||||
(.addEventListener ^js net-info
|
||||
#(re-frame/dispatch [::network-info-changed
|
||||
(js->clj % :keywordize-keys true)]))))
|
||||
(let [app-went-offline? (reagent/atom false)]
|
||||
(when net-info
|
||||
(.addEventListener ^js net-info
|
||||
#(re-frame/dispatch [::network-info-changed
|
||||
(-> (js->clj % :keywordize-keys true)
|
||||
(assoc :app-went-offline? app-went-offline?))])))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::listen-to-network-info
|
||||
|
||||
@@ -55,16 +55,13 @@
|
||||
:podcasts (js/require "../resources/images/ui/podcasts.png")})
|
||||
|
||||
(def mock-images
|
||||
{:photo1 (js/require "../resources/images/mock/photo1.png")
|
||||
:photo2 (js/require "../resources/images/mock/photo2.png")
|
||||
:photo3 (js/require "../resources/images/mock/photo3.png")
|
||||
:community-banner (js/require "../resources/images/mock/community-banner.png")
|
||||
:community-logo (js/require "../resources/images/mock/community-logo.png")
|
||||
:gif (js/require "../resources/images/mock/gif.png")
|
||||
:sticker (js/require "../resources/images/mock/sticker.png")
|
||||
:user-picture-female2 (js/require "../resources/images/mock/user_picture_female2.png")
|
||||
:user-picture-male4 (js/require "../resources/images/mock/user_picture_male4.png")
|
||||
:user-picture-male5 (js/require "../resources/images/mock/user_picture_male5.png")})
|
||||
{:photo1 (js/require "../resources/images/mock/photo1.png")
|
||||
:photo2 (js/require "../resources/images/mock/photo2.png")
|
||||
:photo3 (js/require "../resources/images/mock/photo3.png")
|
||||
:community-banner (js/require "../resources/images/mock/community-banner.png")
|
||||
:community-logo (js/require "../resources/images/mock/community-logo.png")
|
||||
:gif (js/require "../resources/images/mock/gif.png")
|
||||
:sticker (js/require "../resources/images/mock/sticker.png")})
|
||||
|
||||
(defn get-theme-image [k]
|
||||
(get ui (when (colors/dark?) (keyword (str (name k) "-dark"))) (get ui k)))
|
||||
|
||||
@@ -3,53 +3,32 @@
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.datetime :as utils.datetime]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:activity-center/notifications
|
||||
:<- [:activity-center]
|
||||
(fn [activity-center]
|
||||
(:notifications activity-center)))
|
||||
:activity-center/notifications-read
|
||||
(fn [db]
|
||||
(get-in db [:activity-center :notifications-read :data])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:activity-center/filter-status
|
||||
:<- [:activity-center]
|
||||
(fn [activity-center]
|
||||
(get-in activity-center [:filter :status])))
|
||||
:activity-center/notifications-unread
|
||||
(fn [db]
|
||||
(get-in db [:activity-center :notifications-unread :data])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:activity-center/filter-type
|
||||
:<- [:activity-center]
|
||||
(fn [activity-center]
|
||||
(get-in activity-center [:filter :type] constants/activity-center-notification-type-no-type)))
|
||||
:activity-center/current-status-filter
|
||||
(fn [db]
|
||||
(get-in db [:activity-center :current-status-filter])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:activity-center/loading?
|
||||
:<- [:activity-center/filter-type]
|
||||
:<- [:activity-center/filter-status]
|
||||
:<- [:activity-center/notifications]
|
||||
(fn [[filter-type filter-status notifications]]
|
||||
(get-in notifications [filter-type filter-status :loading?])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:activity-center/filtered-notifications
|
||||
:<- [:activity-center/filter-type]
|
||||
:<- [:activity-center/filter-status]
|
||||
:<- [:activity-center/notifications]
|
||||
(fn [[filter-type filter-status notifications]]
|
||||
(tap> {:SUB-filtered-notifications (utils.datetime/now->iso8601)})
|
||||
(get-in notifications [filter-type filter-status :data])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:activity-center/filter-status-unread-enabled?
|
||||
:<- [:activity-center/filter-status]
|
||||
(fn [filter-status]
|
||||
(= :unread filter-status))
|
||||
;; (fn [db]
|
||||
;; (tap> {:SUB-filter-status-unread-enabled? (utils.datetime/now->iso8601)})
|
||||
;; (= :read (:activity-center-notifications-filter-status db)))
|
||||
)
|
||||
:activity-center/notifications-per-read-status
|
||||
:<- [:activity-center/notifications-read]
|
||||
:<- [:activity-center/notifications-unread]
|
||||
:<- [:activity-center/current-status-filter]
|
||||
(fn [[notifications-read notifications-unread status-filter]]
|
||||
(if (= status-filter :unread)
|
||||
notifications-unread
|
||||
notifications-read)))
|
||||
|
||||
(defn- group-notifications-by-date
|
||||
[notifications]
|
||||
@@ -85,4 +64,4 @@
|
||||
(map #(assoc %
|
||||
:timestamp (or (:timestamp %) (:timestamp (or (:message %) (:last-message %))))
|
||||
:contact (multiaccounts/contact-by-identity contacts (get-in % [:message :from])))
|
||||
supported-notifications)))))
|
||||
supported-notifications)))))
|
||||
@@ -228,7 +228,6 @@
|
||||
|
||||
(reg-root-key-sub :activity.center/notifications :activity.center/notifications)
|
||||
(reg-root-key-sub :activity.center/notifications-count :activity.center/notifications-count)
|
||||
(reg-root-key-sub :activity-center :activity-center)
|
||||
|
||||
(reg-root-key-sub :bug-report/description-error :bug-report/description-error)
|
||||
(reg-root-key-sub :bug-report/details :bug-report/details)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
:refer (SafeAreaProvider SafeAreaInsetsContext)]
|
||||
["@react-native-community/clipboard" :default Clipboard]
|
||||
["react-native-linear-gradient" :default LinearGradient]
|
||||
["@react-native-community/masked-view" :default MaskedView]
|
||||
["react-native-navigation" :refer (Navigation)]
|
||||
["react-native-fast-image" :as FastImage]
|
||||
["@react-native-community/blur" :as blur])
|
||||
@@ -41,8 +40,6 @@
|
||||
|
||||
(def linear-gradient (reagent/adapt-react-class LinearGradient))
|
||||
|
||||
(def masked-view (reagent/adapt-react-class MaskedView))
|
||||
|
||||
(def blur-view (reagent/adapt-react-class (.-BlurView blur)))
|
||||
|
||||
(defn valid-source? [source]
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
(ns status-im.ui.screens.activity-center.views
|
||||
(:require [quo.components.animated.pressable :as animation]
|
||||
[quo.design-system.colors :as quo.colors]
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.notifications.activity-logs :as activity-logs]
|
||||
[quo2.components.tabs.tabs :as tabs]
|
||||
[quo2.components.tags.context-tags :as context-tags]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.utils.handlers :refer [<sub >evt]]))
|
||||
|
||||
@@ -30,8 +28,8 @@
|
||||
[{:keys [type]}]
|
||||
(case type
|
||||
constants/activity-center-notification-type-contact-request
|
||||
:main-icons2/add-user
|
||||
:main-icons2/placeholder))
|
||||
:add-user
|
||||
:placeholder))
|
||||
|
||||
(defn activity-context
|
||||
[{:keys [message last-message type]}]
|
||||
@@ -79,7 +77,7 @@
|
||||
nil))
|
||||
|
||||
(defn activity-pressable
|
||||
[notification activity]
|
||||
[notification & children]
|
||||
(case (get-in notification [:message :contact-request-state])
|
||||
constants/contact-request-message-state-accepted
|
||||
;; NOTE [2022-09-21]: We need to dispatch to
|
||||
@@ -87,154 +85,46 @@
|
||||
;; `:chat.ui/navigate-to-chat`, otherwise the chat screen looks completely
|
||||
;; broken if it has never been opened before for the accepted contact.
|
||||
[animation/pressable {:on-press #(>evt [:contact.ui/send-message-pressed {:public-key (:author notification)}])}
|
||||
activity]
|
||||
activity))
|
||||
children]
|
||||
[:<> children]))
|
||||
|
||||
(defn render-notification
|
||||
[notification index]
|
||||
(tap> {:render-notification (datetime/now->iso8601)})
|
||||
[rn/view {:margin-top (if (= 0 index) 0 4)
|
||||
:padding-horizontal 20}
|
||||
;; Use this fake notification rectangle to see a massive rendering
|
||||
;; performance difference.
|
||||
(if true
|
||||
[rn/view {:style {:width 100
|
||||
:height 100
|
||||
:background-color :orange
|
||||
:padding-vertical 10}}]
|
||||
[activity-pressable notification
|
||||
[activity-logs/activity-log
|
||||
(merge {:context (activity-context notification)
|
||||
:icon (activity-icon notification)
|
||||
:message (activity-message notification)
|
||||
:status (activity-status notification)
|
||||
:timestamp (datetime/timestamp->relative (:timestamp notification))
|
||||
:title (activity-title notification)
|
||||
:unread? (not (:read notification))}
|
||||
(activity-buttons notification))]])])
|
||||
[rn/view {:flex 1
|
||||
:flex-direction :column
|
||||
:margin-top (if (= 0 index) 0 4)}
|
||||
[activity-pressable notification
|
||||
[activity-logs/activity-log
|
||||
(merge {:context (activity-context notification)
|
||||
:icon (activity-icon notification)
|
||||
:message (activity-message notification)
|
||||
:status (activity-status notification)
|
||||
:timestamp (datetime/timestamp->relative (:timestamp notification))
|
||||
:title (activity-title notification)
|
||||
:unread? (not (:read notification))}
|
||||
(activity-buttons notification))]]])
|
||||
|
||||
(defn filter-selector-read-toggle
|
||||
(defn notifications-list
|
||||
[]
|
||||
(tap> {:filter-selector-read-toggle (datetime/now->iso8601)})
|
||||
(let [unread-filter-enabled? (<sub [:activity-center/filter-status-unread-enabled?])]
|
||||
;; TODO: Replace the button by a Filter Selector component once available for use.
|
||||
[button/button {:icon true
|
||||
:type (if unread-filter-enabled? :primary :outline)
|
||||
:size 32
|
||||
:on-press #(do
|
||||
(tap> {:filter-selector-read-toggle-ON-PRESS (datetime/now->iso8601)})
|
||||
(>evt [:activity-center.notifications/fetch-first-page
|
||||
{:filter-status (if unread-filter-enabled?
|
||||
:read
|
||||
:unread)}]))}
|
||||
:main-icons2/unread]))
|
||||
(let [notifications (<sub [:activity-center/notifications-per-read-status])]
|
||||
[rn/flat-list {:style {:padding-horizontal 8}
|
||||
:data notifications
|
||||
:key-fn :id
|
||||
:on-end-reached #(>evt [:activity-center.notifications/fetch-next-page])
|
||||
:render-fn render-notification}]))
|
||||
|
||||
;; TODO(2022-10-07): The empty state is still under design analysis, so we
|
||||
;; shouldn't even care about translations at this point. A placeholder box is
|
||||
;; used instead of an image.
|
||||
(defn empty-tab
|
||||
[]
|
||||
[rn/view {:style {:align-items :center
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:padding-vertical 12}}
|
||||
[rn/view {:style {:background-color colors/neutral-80
|
||||
:height 120
|
||||
:margin-bottom 20
|
||||
:width 120}}]
|
||||
[text/text {:size :paragraph-1
|
||||
:style {:padding-bottom 2}
|
||||
:weight :semi-bold}
|
||||
"No notifications"]
|
||||
[text/text {:size :paragraph-2}
|
||||
"Your notifications will be here"]])
|
||||
|
||||
(defn tabs
|
||||
[]
|
||||
(tap> {:tabs (datetime/now->iso8601)})
|
||||
(let [filter-type (<sub [:activity-center/filter-type])]
|
||||
[tabs/scrollable-tabs {:size 32
|
||||
:style {:padding-left 20}
|
||||
:fade-end-percentage 0.79
|
||||
:scroll-on-press? true
|
||||
:fade-end? true
|
||||
:on-change #(>evt [:activity-center.notifications/fetch-first-page {:filter-type %}])
|
||||
:default-active filter-type
|
||||
:data [{:id constants/activity-center-notification-type-no-type
|
||||
:label (i18n/label :t/all)}
|
||||
{:id constants/activity-center-notification-type-admin
|
||||
:label (i18n/label :t/admin)}
|
||||
{:id constants/activity-center-notification-type-mention
|
||||
:label (i18n/label :t/mentions)}
|
||||
{:id constants/activity-center-notification-type-reply
|
||||
:label (i18n/label :t/replies)}
|
||||
{:id constants/activity-center-notification-type-contact-request
|
||||
:label (i18n/label :t/contact-requests)}
|
||||
{:id constants/activity-center-notification-type-identity-verification
|
||||
:label (i18n/label :t/identity-verification)}
|
||||
{:id constants/activity-center-notification-type-tx
|
||||
:label (i18n/label :t/transactions)}
|
||||
{:id constants/activity-center-notification-type-membership
|
||||
:label (i18n/label :t/membership)}
|
||||
{:id constants/activity-center-notification-type-system
|
||||
:label (i18n/label :t/system)}]}]))
|
||||
|
||||
(defn header
|
||||
[]
|
||||
(tap> {:header (datetime/now->iso8601)})
|
||||
(let [screen-padding 20]
|
||||
;; TODO: Remove temporary (and old) background color when the screen and
|
||||
;; header are properly blurred.
|
||||
[rn/view {:background-color (:ui-background @quo.colors/theme)}
|
||||
[button/button {:icon true
|
||||
:type :grey
|
||||
:size 32
|
||||
:style {:margin-vertical 12
|
||||
:margin-left screen-padding}
|
||||
:on-press #(>evt [:navigate-back])}
|
||||
:main-icons2/close]
|
||||
[text/text {:size :heading-1
|
||||
:weight :semi-bold
|
||||
:style {:padding-horizontal screen-padding
|
||||
:padding-vertical 12}}
|
||||
(i18n/label :t/notifications)]
|
||||
[rn/view {:flex-direction :row
|
||||
:padding-vertical 12}
|
||||
[rn/view {:flex 1
|
||||
:align-self :stretch}
|
||||
[tabs]]
|
||||
[rn/view {:flex-grow 0
|
||||
:margin-left 16
|
||||
:padding-right screen-padding}
|
||||
[filter-selector-read-toggle]]]]))
|
||||
|
||||
(defn loading-indicator
|
||||
[]
|
||||
(tap> {:loading-indicator (datetime/now->iso8601)})
|
||||
(when (<sub [:activity-center/loading?])
|
||||
[rn/view {:background-color :orange
|
||||
:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:width 100
|
||||
:height 50}]))
|
||||
|
||||
(defn activity-center
|
||||
[]
|
||||
(defn activity-center []
|
||||
(reagent/create-class
|
||||
{:component-did-mount #(>evt [:activity-center.notifications/fetch-first-page])
|
||||
{:component-did-mount #(>evt [:activity-center.notifications/fetch-first-page {:status-filter :unread}])
|
||||
:reagent-render
|
||||
(fn []
|
||||
(tap> {:activity-center (datetime/now->iso8601)})
|
||||
(let [notifications (<sub [:activity-center/filtered-notifications])]
|
||||
[:<>
|
||||
[loading-indicator]
|
||||
[rn/flat-list {:content-container-style {:flex-grow 1}
|
||||
:data notifications
|
||||
:empty-component [empty-tab]
|
||||
:header [header]
|
||||
:key-fn :id
|
||||
;; Commented to simplify analysis.
|
||||
;; :on-end-reached #(>evt [:activity-center.notifications/fetch-next-page])
|
||||
:render-fn render-notification
|
||||
:sticky-header-indices [0]}]]))}))
|
||||
[:<>
|
||||
[topbar/topbar {:navigation {:on-press #(>evt [:navigate-back])}
|
||||
:title (i18n/label :t/activity)}]
|
||||
;; TODO(ilmotta): Temporary solution to switch between read/unread
|
||||
;; notifications while the Design team works on the mockups.
|
||||
[button/button {:on-press #(>evt [:activity-center.notifications/fetch-first-page {:status-filter :unread}])}
|
||||
"Unread"]
|
||||
[button/button {:on-press #(>evt [:activity-center.notifications/fetch-first-page {:status-filter :read}])}
|
||||
"Read"]
|
||||
[notifications-list]])}))
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
(:require [status-im.ui.components.icons.icons :as icons]
|
||||
[quo.react-native :as rn]
|
||||
[oops.core :refer [oget]]
|
||||
[quo.react :as quo.react]
|
||||
[quo.react :as react]
|
||||
[quo.platform :as platform]
|
||||
[quo.components.text :as text]
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.screens.chat.components.style :as styles]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.handlers :refer [<sub]]
|
||||
[status-im.ui.screens.chat.components.reply :as reply]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.chat.constants :as chat.constants]
|
||||
@@ -28,7 +27,7 @@
|
||||
[quo.components.safe-area :as safe-area]))
|
||||
|
||||
(defn input-focus [text-input-ref]
|
||||
(some-> ^js (quo.react/current-ref text-input-ref) .focus))
|
||||
(some-> ^js (react/current-ref text-input-ref) .focus))
|
||||
|
||||
(def panel->icons {:extensions :main-icons/commands
|
||||
:images :main-icons/photo})
|
||||
@@ -158,7 +157,7 @@
|
||||
(quo.react/set-native-props sticker-ref #js {:width nil :right nil})))
|
||||
|
||||
(defn reset-input [refs chat-id]
|
||||
(some-> ^js (quo.react/current-ref (:text-input-ref refs)) .clear)
|
||||
(some-> ^js (react/current-ref (:text-input-ref refs)) .clear)
|
||||
(swap! mentions-enabled update :render not)
|
||||
(swap! input-texts dissoc chat-id))
|
||||
|
||||
@@ -205,11 +204,11 @@
|
||||
(re-frame/reg-fx
|
||||
:set-input-text
|
||||
(fn [[chat-id text]]
|
||||
;; We enable mentions
|
||||
;; We enable mentions
|
||||
(swap! mentions-enabled assoc chat-id true)
|
||||
(on-text-change text chat-id)
|
||||
;; We update the key so that we force a refresh of the text input, as those
|
||||
;; are not ratoms
|
||||
;; We update the key so that we force a refresh of the text input, as those
|
||||
;; are not ratoms
|
||||
(force-text-input-update!)))
|
||||
|
||||
(fx/defn set-input-text
|
||||
@@ -462,12 +461,12 @@
|
||||
:input-focus #(input-focus text-input-ref)
|
||||
:set-active set-active-panel}])])]]]))))
|
||||
|
||||
(defn calculate-y [context keyboard-shown min-y max-y added-value]
|
||||
(defn calculate-y [context keyboard-shown min-y max-y]
|
||||
(if keyboard-shown
|
||||
(if (= (:state @context) :max)
|
||||
max-y
|
||||
(if (< (:y @context) max-y)
|
||||
(+ (:y @context) added-value)
|
||||
(:y @context)
|
||||
(do
|
||||
(swap! context assoc :state :max)
|
||||
max-y)))
|
||||
@@ -555,31 +554,30 @@
|
||||
:pdy 0 ;used for gesture
|
||||
:state :min ;:min, :custom-chat-available, :custom-chat-unavailable, :max
|
||||
:clear false})
|
||||
keyboard-was-shown (atom false)
|
||||
text-input-ref (quo.react/create-ref)
|
||||
send-ref (quo.react/create-ref)
|
||||
refs {:send-ref send-ref
|
||||
:text-input-ref text-input-ref}]
|
||||
keyboard-was-shown (atom false)]
|
||||
(fn []
|
||||
[:f>
|
||||
(fn []
|
||||
(let [reply (<sub [:chats/reply-message])
|
||||
(let [text-input-ref (quo.react/create-ref)
|
||||
send-ref (quo.react/create-ref)
|
||||
refs {:send-ref send-ref
|
||||
:text-input-ref text-input-ref}
|
||||
|
||||
{window-height :height} (rn/use-window-dimensions)
|
||||
{:keys [keyboard-shown keyboard-height]} (rn/use-keyboard)
|
||||
|
||||
max-y (- window-height (if (> keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - default height
|
||||
max-height (- max-y 56 (:bottom insets)) ; 56 - top-bar height
|
||||
added-value (if reply 38 0) ; increased height of input box needed when reply
|
||||
min-y (+ min-y added-value)
|
||||
y (calculate-y context keyboard-shown min-y max-y added-value)
|
||||
max-y (- window-height (if (> keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - defaul height
|
||||
max-height (- max-y 56 (:bottom insets)) ; 56 - topbar height
|
||||
y (calculate-y context keyboard-shown min-y max-y)
|
||||
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
shared-height (reanimated/use-shared-value min-y)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
|
||||
bottom-sheet-gesture (get-bottom-sheet-gesture context translate-y text-input-ref keyboard-shown
|
||||
min-y max-y shared-height max-height bg-opacity)
|
||||
input-content-change (get-input-content-change context translate-y shared-height max-height
|
||||
bg-opacity keyboard-shown min-y max-y)
|
||||
bottom-sheet-gesture (get-bottom-sheet-gesture context translate-y (:text-input-ref refs) keyboard-shown
|
||||
min-y max-y shared-height max-height bg-opacity)]
|
||||
bg-opacity keyboard-shown min-y max-y)]
|
||||
(quo.react/effect! #(do
|
||||
(when (and @keyboard-was-shown (not keyboard-shown))
|
||||
(swap! context assoc :state :min))
|
||||
@@ -599,8 +597,7 @@
|
||||
(styles/new-input-bottom-sheet window-height))}
|
||||
;handle
|
||||
[rn/view {:style (styles/new-bottom-sheet-handle)}]
|
||||
[reply/reply-message-auto-focus-wrapper (:text-input-ref refs) reply]
|
||||
[rn/view {:style {:height (- max-y 80 added-value)}}
|
||||
[rn/view {:style {:height (- max-y 80)}}
|
||||
[text-input {:chat-id chat-id
|
||||
:on-content-size-change input-content-change
|
||||
:sending-image false
|
||||
@@ -622,4 +619,4 @@
|
||||
;black background
|
||||
[reanimated/view {:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity}
|
||||
(styles/new-bottom-sheet-background window-height))}]]))])))])
|
||||
(styles/new-bottom-sheet-background window-height))}]]))])))])
|
||||
@@ -89,7 +89,7 @@
|
||||
[rn/view {:style (styles/reply-content)}
|
||||
[icons/icon :main-icons/connector {:color (theme-colors quo2.colors/neutral-40 quo2.colors/neutral-60)
|
||||
:container-style {:position :absolute :left 10 :bottom -4 :width 16 :height 16}}]
|
||||
[rn/view {:style {:position :absolute :left 34 :top 3 :flex-direction :row :align-items :center :width "45%"}}
|
||||
[rn/view {:style {:position :absolute :left 34 :right 54 :top 3 :flex-direction :row :align-items :center}}
|
||||
[photos/member-photo from identicon 16]
|
||||
[quo2.text/text {:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
@@ -144,8 +144,7 @@
|
||||
(when-not (= reply @had-reply)
|
||||
(reset! had-reply reply)
|
||||
(when reply
|
||||
;; A setTimeout of 0 is necessary to ensure the statement is enqueued and will get executed ASAP.
|
||||
(js/setTimeout #(input-focus text-input-ref) 0))))
|
||||
(js/setTimeout #(input-focus text-input-ref) 250))))
|
||||
|
||||
(defn reply-message-wrapper-old [reply]
|
||||
[rn/view {:style {:padding-horizontal 15
|
||||
@@ -156,6 +155,8 @@
|
||||
|
||||
(defn reply-message-wrapper [reply]
|
||||
[rn/view {:style {:padding-horizontal 15
|
||||
:border-top-width 1
|
||||
:border-top-color (:ui-01 @quo.colors/theme)
|
||||
:padding-vertical 8}}
|
||||
[reply-message reply true]])
|
||||
|
||||
@@ -167,9 +168,10 @@
|
||||
(when reply
|
||||
[reply-message-wrapper-old reply])))))
|
||||
|
||||
(defn reply-message-auto-focus-wrapper [text-input-ref _]
|
||||
(defn reply-message-auto-focus-wrapper [text-input-ref]
|
||||
(let [had-reply (atom nil)]
|
||||
(fn [_ reply]
|
||||
(focus-input-on-reply reply had-reply text-input-ref)
|
||||
(when reply
|
||||
[reply-message-wrapper reply]))))
|
||||
(fn []
|
||||
(let [reply @(re-frame/subscribe [:chats/reply-message])]
|
||||
(focus-input-on-reply reply had-reply text-input-ref)
|
||||
(when reply
|
||||
[reply-message-wrapper reply])))))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[reagent.core :as reagent]
|
||||
[goog.string :as gstring]
|
||||
[status-im.audio.core :as audio]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ui.screens.chat.styles.message.audio :as style]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
[quo.design-system.colors :as colors]
|
||||
@@ -183,6 +184,15 @@
|
||||
:accessibility-label :play-pause-audio-message-button
|
||||
:color color}]])))
|
||||
|
||||
(fx/defn on-background
|
||||
{:events [:audio-message/on-background]}
|
||||
[_]
|
||||
(when (and @current-active-state-ref-ref
|
||||
@@current-active-state-ref-ref)
|
||||
(update-state {:state-ref @current-active-state-ref-ref
|
||||
:message-id @current-player-message-id}))
|
||||
nil)
|
||||
|
||||
(defview message-content [{:keys [audio audio-duration-ms message-id]}]
|
||||
(letsubs [state (reagent/atom nil)
|
||||
progress (reagent/atom 0)
|
||||
|
||||
@@ -423,38 +423,6 @@
|
||||
:inverted (when platform/ios? true)
|
||||
:style (when platform/android? {:scaleY -1})})]))
|
||||
|
||||
(def show-floating-scroll-down-button (reagent/atom false))
|
||||
(def threshold-percentage-to-show-floating-scroll-down-button 75)
|
||||
|
||||
(defn scroll-to-bottom []
|
||||
(some-> ^js @messages-list-ref (.scrollToOffset #js {:y 0 :animated true})))
|
||||
|
||||
(defn floating-scroll-down-button [show-input?]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press scroll-to-bottom}
|
||||
[rn/view {:style {:position :absolute
|
||||
:bottom (if show-input? 126 12)
|
||||
:right 12
|
||||
:height 24
|
||||
:width 24
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius (/ 24 2)
|
||||
:background-color (quo2.colors/theme-colors quo2.colors/neutral-80-opa-70 quo2.colors/white-opa-70)}}
|
||||
[icons/icon
|
||||
:main-icons/arrow-down {:color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-100)
|
||||
:width 12
|
||||
:height 12}]]])
|
||||
|
||||
(defn on-scroll [^js ev]
|
||||
(let [y (-> ev .-nativeEvent .-contentOffset .-y)
|
||||
layout-height (-> ev .-nativeEvent .-layoutMeasurement .-height)
|
||||
threshold-height (* (/ layout-height 100) threshold-percentage-to-show-floating-scroll-down-button)
|
||||
reached-threshold? (> y threshold-height)]
|
||||
(when (not= reached-threshold? @show-floating-scroll-down-button)
|
||||
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets))
|
||||
(reset! show-floating-scroll-down-button reached-threshold?))))
|
||||
|
||||
(defn messages-view [{:keys [chat
|
||||
bottom-space
|
||||
pan-responder
|
||||
@@ -470,43 +438,39 @@
|
||||
mutual-contact-requests-enabled?
|
||||
one-to-one?
|
||||
(not contact-added?))]
|
||||
[:<>
|
||||
;;do not use anonymous functions for handlers
|
||||
[list/flat-list
|
||||
(merge
|
||||
pan-responder
|
||||
{:key-fn list-key-fn
|
||||
:ref list-ref
|
||||
:header [list-header chat]
|
||||
:footer [list-footer chat]
|
||||
:data (when-not should-send-contact-request?
|
||||
messages)
|
||||
:render-data (get-render-data {:group-chat group-chat
|
||||
:chat-id chat-id
|
||||
:public? public?
|
||||
:community-id community-id
|
||||
:admins admins
|
||||
:show-input? show-input?
|
||||
:edit-enabled true
|
||||
:in-pinned-view? false})
|
||||
:render-fn render-fn
|
||||
:on-viewable-items-changed on-viewable-items-changed
|
||||
:on-end-reached list-on-end-reached
|
||||
:on-scroll-to-index-failed identity ;;don't remove this
|
||||
:content-container-style {:padding-top (+ bottom-space 16)
|
||||
:padding-bottom 16}
|
||||
:scroll-indicator-insets {:top bottom-space} ;;ios only
|
||||
:keyboard-dismiss-mode :interactive
|
||||
:keyboard-should-persist-taps :handled
|
||||
:onMomentumScrollBegin state/start-scrolling
|
||||
:onMomentumScrollEnd state/stop-scrolling
|
||||
:scrollEventThrottle 16
|
||||
:on-scroll on-scroll
|
||||
|
||||
;;do not use anonymous functions for handlers
|
||||
[list/flat-list
|
||||
(merge
|
||||
pan-responder
|
||||
{:key-fn list-key-fn
|
||||
:ref list-ref
|
||||
:header [list-header chat]
|
||||
:footer [list-footer chat]
|
||||
:data (when-not should-send-contact-request?
|
||||
messages)
|
||||
:render-data (get-render-data {:group-chat group-chat
|
||||
:chat-id chat-id
|
||||
:public? public?
|
||||
:community-id community-id
|
||||
:admins admins
|
||||
:show-input? show-input?
|
||||
:edit-enabled true
|
||||
:in-pinned-view? false})
|
||||
:render-fn render-fn
|
||||
:on-viewable-items-changed on-viewable-items-changed
|
||||
:on-end-reached list-on-end-reached
|
||||
:on-scroll-to-index-failed identity ;;don't remove this
|
||||
:content-container-style {:padding-top (+ bottom-space 16)
|
||||
:padding-bottom 16}
|
||||
:scroll-indicator-insets {:top bottom-space} ;;ios only
|
||||
:keyboard-dismiss-mode :interactive
|
||||
:keyboard-should-persist-taps :handled
|
||||
:onMomentumScrollBegin state/start-scrolling
|
||||
:onMomentumScrollEnd state/stop-scrolling
|
||||
;;TODO https://github.com/facebook/react-native/issues/30034
|
||||
:inverted (when platform/ios? true)
|
||||
:style (when platform/android? {:scaleY -1})})]
|
||||
(when @show-floating-scroll-down-button
|
||||
[floating-scroll-down-button show-input?])]))
|
||||
:inverted (when platform/ios? true)
|
||||
:style (when platform/android? {:scaleY -1})})]))
|
||||
|
||||
(defn back-button []
|
||||
[quo2.button/button {:type :grey
|
||||
|
||||
@@ -28,21 +28,14 @@
|
||||
(def sort-list-by (reagent/atom :name))
|
||||
|
||||
(def mock-community-item-data ;; TODO: remove once communities are loaded with this data.
|
||||
{:data {:status :gated
|
||||
:locked true
|
||||
:cover (resources/get-image :community-cover)
|
||||
:tokens [{:id 1
|
||||
:group [{:id 1
|
||||
:token-icon (resources/get-image :status-logo)}]}]
|
||||
:tags [{:id 1
|
||||
:tag-label (i18n/label :t/music)
|
||||
:resource (resources/get-image :music)}
|
||||
{:id 2
|
||||
:tag-label (i18n/label :t/lifestyle)
|
||||
:resource (resources/get-image :lifestyle)}
|
||||
{:id 3
|
||||
:tag-label (i18n/label :t/podcasts)
|
||||
:resource (resources/get-image :podcasts)}]}})
|
||||
{:data {:status :gated
|
||||
:locked true
|
||||
;; :images {:thumbnail {:uri []}} ;; TODO address issue with context tag image
|
||||
:cover (resources/get-image :community-cover)
|
||||
:tokens [{:id 1 :group [{:id 1 :token-icon (resources/get-image :status-logo)}]}]
|
||||
:tags [{:id 1 :tag-label (i18n/label :t/music) :resource (resources/get-image :music)}
|
||||
{:id 2 :tag-label (i18n/label :t/lifestyle) :resource (resources/get-image :lifestyle)}
|
||||
{:id 3 :tag-label (i18n/label :t/podcasts) :resource (resources/get-image :podcasts)}]}})
|
||||
|
||||
(defn plus-button []
|
||||
(let [logging-in? (<sub [:multiaccounts/login])]
|
||||
@@ -186,7 +179,7 @@
|
||||
(let [filters [{:id 1 :tag-label (i18n/label :t/music) :resource (resources/get-image :music)}
|
||||
{:id 2 :tag-label (i18n/label :t/lifestyle) :resource (resources/get-image :lifestyle)}
|
||||
{:id 3 :tag-label (i18n/label :t/podcasts) :resource (resources/get-image :podcasts)}
|
||||
{:id 4 :tag-label (i18n/label :t/podcasts) :resource (resources/get-image :podcasts)}]]
|
||||
{:id 3 :tag-label (i18n/label :t/podcasts) :resource (resources/get-image :podcasts)}]]
|
||||
[react/scroll-view {:horizontal true
|
||||
:height 48
|
||||
:shows-horizontal-scroll-indicator false
|
||||
|
||||
@@ -1,141 +1,72 @@
|
||||
(ns status-im.ui.screens.communities.community-overview-redesign
|
||||
(:require [status-im.i18n.i18n :as i18n]
|
||||
[status-im.ui.components.react :as react]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.list-items.preview-list :as preview-list]
|
||||
[quo2.components.list-items.channel :as channel]
|
||||
[quo2.components.dividers.divider-label :as divider-label]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[quo2.components.buttons.button :as quo2.button]
|
||||
[quo2.components.community.community-view :as community-view]
|
||||
[quo2.components.tags.status-tags :as status-tags]
|
||||
[status-im.ui.screens.communities.request-to-join-bottom-sheet-redesign :as request-to-join]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.utils.handlers :refer [<sub >evt]]
|
||||
[status-im.ui.screens.communities.styles :as styles]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im.ui.screens.communities.icon :as communities.icon]))
|
||||
|
||||
;; Mocked list items
|
||||
(def user-list
|
||||
[{:full-name "Alicia K"}
|
||||
{:full-name "Marcus C"}
|
||||
{:full-name "MNO PQR"}
|
||||
{:full-name "STU VWX"}])
|
||||
|
||||
(defn preview-user-list []
|
||||
[react/view {:style {:flex-direction :row
|
||||
:align-items :center
|
||||
:margin-top 20}}
|
||||
[preview-list/preview-list {:type :user
|
||||
:user user-list :list-size 4 :size 24}]
|
||||
[text/text {:accessibility-label :communities-screen-title
|
||||
:style {:margin-left 8}
|
||||
:size :label}
|
||||
"Join Alicia, Marcus and 2 more"]]) ;; TODO remove mocked data and use from contacts list/communities members
|
||||
|
||||
(def list-of-channels {:Welcome [{:name "welcome"
|
||||
:emoji "🤝"}
|
||||
{:name "onboarding"
|
||||
:emoji "🍑"}
|
||||
{:name "intro"
|
||||
:emoji "🦄"}]
|
||||
:General [{:name "general"
|
||||
:emoji "🐷"}
|
||||
{:name "people-ops"
|
||||
:emoji "🌏"}
|
||||
{:name "announcements"
|
||||
:emoji "🎺"}]
|
||||
:Mobile [{:name "mobile"
|
||||
:emoji "👽"}]})
|
||||
(defn preview-list-component []
|
||||
[react/view {:style {:height 20 :margin-top 20}}
|
||||
[quo2.text/text {:accessibility-label :communities-screen-title
|
||||
:weight :semi-bold
|
||||
:size :label}
|
||||
"placeholder for preview list component"]])
|
||||
|
||||
(defn channel-list-component []
|
||||
[react/scroll-view {:style {:margin-top 20}}
|
||||
[:<> {:style {:flex 1}}
|
||||
(map (fn [category]
|
||||
^{:key (get category 0)}
|
||||
[react/view {:flex 1}
|
||||
[divider-label/divider-label
|
||||
{:label (first category)
|
||||
:chevron-position :left}]
|
||||
[react/view
|
||||
{:margin-left 8
|
||||
:margin-top 10
|
||||
:margin-bottom 8}
|
||||
[list/flat-list
|
||||
{:shows-horizontal-scroll-indicator false
|
||||
:separator [react/view {:margin-top 4}]
|
||||
:data ((first category) list-of-channels)
|
||||
:render-fn channel/list-item}]]])
|
||||
list-of-channels)]])
|
||||
[react/view {:style {:height 200 :margin-top 20}}
|
||||
[quo2.text/text {:accessibility-label :communities-screen-title
|
||||
:weight :semi-bold
|
||||
:size :label}
|
||||
"placeholder for channel list component"]])
|
||||
|
||||
(defn community-card-page-view [{:keys [name description locked joined
|
||||
status tokens cover tags] :as community}]
|
||||
[react/view
|
||||
{:style
|
||||
{:flex 1
|
||||
{:height "100%"
|
||||
:border-radius 20}}
|
||||
[react/view (styles/community-cover-container 148)
|
||||
|
||||
[react/image
|
||||
{:source cover
|
||||
:style {:position :relative
|
||||
:style {:height 180
|
||||
:flex 1}}]]
|
||||
[react/view {:flex 1
|
||||
:height 20
|
||||
:border-radius 16
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)}
|
||||
[react/view {:padding-horizontal 20}
|
||||
[react/view {:border-radius 40
|
||||
:border-width 1
|
||||
:border-color colors/white
|
||||
:position :absolute
|
||||
:top (- (/ 80 2))
|
||||
:left (/ 70 4)
|
||||
:padding 2
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)}
|
||||
[communities.icon/community-icon-redesign community 80]]
|
||||
(when (and (not joined)
|
||||
(= status :gated))
|
||||
[react/view (styles/permission-tag-styles)
|
||||
[community-view/permission-tag-container
|
||||
{:locked locked
|
||||
:status status
|
||||
:tokens tokens}]])
|
||||
(when joined
|
||||
[react/view {:position :absolute
|
||||
:top 12
|
||||
:right 12}
|
||||
[status-tags/status-tag {:status {:type :positive} :label (i18n/label :joined)}]])
|
||||
[community-view/community-title
|
||||
{:title name
|
||||
:size :large
|
||||
:description description}]
|
||||
[community-view/community-stats-column :card-view]
|
||||
[community-view/community-tags tags]
|
||||
[preview-user-list]
|
||||
(when (not joined)
|
||||
[button/button
|
||||
{:on-press #(>evt [:bottom-sheet/show-sheet
|
||||
{:content (constantly [request-to-join/request-to-join community])
|
||||
:content-height 300}])
|
||||
:style
|
||||
{:width "100%"
|
||||
:margin-top 20
|
||||
:margin-left :auto
|
||||
:margin-right :auto}
|
||||
:before :main-icons2/communities}
|
||||
(i18n/label :join-open-community)])]
|
||||
[react/view (styles/card-view-content-container 20)
|
||||
[react/view (styles/card-view-chat-icon 80)
|
||||
[communities.icon/community-icon-redesign community 80]]
|
||||
(when (= status :gated)
|
||||
[react/view (styles/permission-tag-styles)
|
||||
[community-view/permission-tag-container
|
||||
{:locked locked
|
||||
:status status
|
||||
:tokens tokens}]])
|
||||
[community-view/community-title
|
||||
{:title name
|
||||
:size :large
|
||||
:description description}]
|
||||
[community-view/community-stats-column :card-view]
|
||||
[community-view/community-tags tags]
|
||||
[preview-list-component]
|
||||
(when (not joined)
|
||||
[quo2.button/button
|
||||
{:on-press #(>evt [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [request-to-join/request-to-join community])
|
||||
:content-height 300}])
|
||||
:style
|
||||
{:width "100%"
|
||||
:margin-top 20
|
||||
:margin-left :auto
|
||||
:margin-right :auto}
|
||||
:before :main-icons/community}
|
||||
(i18n/label :join-open-community)])
|
||||
[channel-list-component]]])
|
||||
|
||||
(defn overview []
|
||||
(let [community-mock (<sub [:get-screen-params :community-overview]) ;;TODO stop using mock data and only pass community id
|
||||
community (<sub [:communities/community (:id community-mock)])]
|
||||
[react/view {:style
|
||||
{:height "100%"}}
|
||||
(let [community (<sub [:get-screen-params :community-overview])]
|
||||
[react/view {:style {}}
|
||||
[community-card-page-view
|
||||
(merge community-mock {:joined (:joined community)})]]))
|
||||
community]]))
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
(ns status-im.ui.screens.communities.request-to-join-bottom-sheet-redesign
|
||||
(:require [status-im.i18n.i18n :as i18n]
|
||||
[quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.selectors.disclaimer :as disclaimer]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[quo2.components.buttons.button :as quo2.button]
|
||||
[quo2.components.icon :as quo2.icon]
|
||||
[status-im.utils.handlers :refer [>evt]]
|
||||
[quo2.components.tags.context-tags :as context-tags]
|
||||
;; [quo2.components.tags.context-tags :as quo2.context-tags]
|
||||
[status-im.communities.core :as communities]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
[quo2.foundations.colors :as quo2.colors]))
|
||||
|
||||
;; TODO: update with real data
|
||||
(def community-rules [{:index 1
|
||||
@@ -47,75 +46,84 @@
|
||||
:width 18
|
||||
:margin-left 1
|
||||
:margin-right 9
|
||||
:background-color colors/white
|
||||
:border-color colors/neutral-20
|
||||
:background-color quo2.colors/white
|
||||
:border-color quo2.colors/neutral-20
|
||||
:border-width 1
|
||||
:border-radius 6}}
|
||||
[text/text {:style
|
||||
{:margin-left :auto
|
||||
:margin-right :auto
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto}
|
||||
:accessibility-label :communities-rule-index
|
||||
:weight :medium
|
||||
:size :label}
|
||||
[quo2.text/text {:style
|
||||
{:margin-left :auto
|
||||
:margin-right :auto
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto}
|
||||
:accessibility-label :communities-rule-index
|
||||
:weight :medium
|
||||
:size :label}
|
||||
|
||||
(str index)]]
|
||||
[text/text
|
||||
[quo2.text/text
|
||||
{:accessibility-label :communities-rule-title
|
||||
:weight :semi-bold
|
||||
:size :paragraph-2}
|
||||
title]]
|
||||
[text/text
|
||||
{:style {:margin-left 28 :margin-top 1}
|
||||
[quo2.text/text
|
||||
{:style {:margin-left 28}
|
||||
:accessibility-label :communities-rule-content
|
||||
:size :paragraph-2}
|
||||
content]])
|
||||
|
||||
(defn community-rules-list [rules]
|
||||
|
||||
[list/flat-list
|
||||
{:shows-horizontal-scroll-indicator false
|
||||
:data rules
|
||||
:separator [react/view {:margin-top 1}]
|
||||
:render-fn community-rule-item}])
|
||||
|
||||
(defn rules-checkbox [agreed-to-rules?]
|
||||
[react/view {:style
|
||||
{:flex 1
|
||||
:flex-direction :row
|
||||
:margin-top 20
|
||||
:background-color quo2.colors/neutral-20
|
||||
:padding 12
|
||||
:border-radius 12
|
||||
:border-width 1
|
||||
:border-color quo2.colors/neutral-30}}
|
||||
[quo/checkbox {:value @agreed-to-rules?
|
||||
:on-change #(swap! agreed-to-rules? not)}]
|
||||
[quo2.text/text {:accessibility-label :communities-accept-rules
|
||||
:size :paragraph-2
|
||||
:style {:margin-left 8}}
|
||||
(i18n/label :t/accept-community-rules)]])
|
||||
|
||||
(defn request-to-join [community]
|
||||
(let [agreed-to-rules? (reagent/atom false)]
|
||||
(fn []
|
||||
[react/view {:style {:flex 1 :margin-left 20 :margin-right 20 :margin-bottom 20}}
|
||||
[react/view {:style {:flex 1 :margin-left 20 :margin-right 20 :margin-bottom 20}}
|
||||
[react/view {:style {:flex 1 :flex-direction :row :align-items :center :justify-content :space-between}}
|
||||
|
||||
[text/text {:accessibility-label :communities-join-community
|
||||
:weight :semi-bold
|
||||
:size :heading-1}
|
||||
[quo2.text/text {:accessibility-label :communities-join-community
|
||||
:weight :semi-bold
|
||||
:size :heading-1}
|
||||
(i18n/label :t/join-open-community)]
|
||||
[react/view {:style {:height 32
|
||||
:width 32
|
||||
:align-items :center
|
||||
:background-color colors/white
|
||||
:border-color colors/neutral-20
|
||||
:background-color quo2.colors/white
|
||||
:border-color quo2.colors/neutral-20
|
||||
:border-width 1
|
||||
:border-radius 8
|
||||
:border-radius 6
|
||||
:display :flex
|
||||
:justify-content :center}}
|
||||
[icon/icon :main-icons2/info]]]
|
||||
;; TODO get tag image from community data
|
||||
[context-tags/context-tag
|
||||
{:style
|
||||
{:margin-right :auto
|
||||
:margin-top 8}}
|
||||
(resources/get-image :status-logo) (:name community)]
|
||||
[text/text {:style {:margin-top 24}
|
||||
:accessibility-label :communities-rules-title
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
[quo2.icon/icon :main-icons2/info]]]
|
||||
;; TODO address issue with context tag image
|
||||
;; [quo2.context-tags/context-tag {:style {:margin-right :auto :margin-top 8}} (get-in community [:images :thumbnail :uri]) (:name community)]
|
||||
[quo2.text/text {:style {:margin-top 24}
|
||||
:accessibility-label :communities-rules-title
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
(i18n/label :t/community-rules)]
|
||||
[community-rules-list community-rules]
|
||||
|
||||
[disclaimer/disclaimer
|
||||
{:container-style {:margin-top 20}
|
||||
:on-change #(swap! agreed-to-rules? not)}
|
||||
(i18n/label :t/accept-community-rules)]
|
||||
[rules-checkbox agreed-to-rules?]
|
||||
|
||||
[react/view {:style {:width "100%"
|
||||
:margin-top 32 :margin-bottom 16
|
||||
@@ -123,10 +131,8 @@
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-evenly}}
|
||||
[button/button {:on-press #(>evt [:bottom-sheet/hide])
|
||||
:type :grey :style {:flex 1 :margin-right 12}} (i18n/label :t/cancel)]
|
||||
[button/button
|
||||
{:on-press (fn []
|
||||
(>evt [::communities/join (:id community)])
|
||||
(>evt [:bottom-sheet/hide]))
|
||||
:disabled (not @agreed-to-rules?) :style {:flex 1}} (i18n/label :t/join-open-community)]]])))
|
||||
[quo2.button/button {:on-press #(>evt [:bottom-sheet/hide])
|
||||
:type :grey :style {:flex 1 :margin-right 12}} (i18n/label :t/cancel)]
|
||||
[quo2.button/button
|
||||
{:on-press #(>evt [::communities/join (:id community)])
|
||||
:disabled (not agreed-to-rules?) :style {:flex 1}} (i18n/label :t/join-open-community)]]])))
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
[status-im.utils.config :as config]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[status-im.qr-scanner.core :as qr-scanner]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[status-im.ui.components.chat-icon.styles :as chat-icon.styles]
|
||||
[quo2.foundations.colors :as quo2.colors]
|
||||
[quo2.components.buttons.button :as quo2.button])
|
||||
[quo2.components.buttons.button :as quo2.button]
|
||||
[quo2.components.info.information-box :as information-box])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn home-tooltip-view []
|
||||
@@ -187,9 +189,12 @@
|
||||
[home-tooltip-view]
|
||||
[react/view {:height 68}])}])))
|
||||
|
||||
(def ens-banner-expire-timestamp 1665010800)
|
||||
|
||||
(views/defview communities-and-chats-old []
|
||||
(views/letsubs [{:keys [items search-filter]} [:home-items]
|
||||
hide-home-tooltip? [:hide-home-tooltip?]]
|
||||
hide-home-tooltip? [:hide-home-tooltip?]
|
||||
information-box-closed? [:information-box-closed? :ens-banner]]
|
||||
(if (and (empty? items)
|
||||
(empty? search-filter)
|
||||
hide-home-tooltip?
|
||||
@@ -205,6 +210,19 @@
|
||||
:header [:<>
|
||||
(when (or (seq items) @search-active? (seq search-filter))
|
||||
[search-input-wrapper-old search-filter (empty? items)])
|
||||
(when (< (datetime/timestamp-sec) ens-banner-expire-timestamp)
|
||||
[information-box/information-box
|
||||
{:type :informative
|
||||
:closable? true
|
||||
:closed? information-box-closed?
|
||||
:icon :main-icons/info
|
||||
:style {:margin 20}
|
||||
:button-label (i18n/label :t/open-dapp2)
|
||||
:on-button-press #(re-frame/dispatch
|
||||
[:browser.ui/open-url "https://ens-collect.status.im/"])
|
||||
:id :ens-banner
|
||||
:on-close #(re-frame/dispatch [:close-information-box :ens-banner true])}
|
||||
(i18n/label :t/ens-banner-message)])
|
||||
(when (and (empty? items)
|
||||
(or @search-active? (seq search-filter)))
|
||||
[start-suggestion search-filter])]
|
||||
|
||||
@@ -6,17 +6,29 @@
|
||||
[quo.core :as quo]
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.utils.utils :as utils]))
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im.ui.screens.wallet-connect.session-proposal.views :refer [app-management-sheet-view]]
|
||||
[status-im.ui.components.bottom-panel.views :as bottom-panel]
|
||||
[status-im.utils.handlers :refer [<sub]]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn print-session-info [session]
|
||||
(let [peer-meta (get-in session [:params 0 :peerMeta])
|
||||
peer-id (get-in session [:params 0 :peerId])
|
||||
name (get peer-meta :name)
|
||||
url (get peer-meta :url)
|
||||
account (get-in session [:params 0 :accounts 0])
|
||||
icons (get peer-meta :icons)
|
||||
icon-uri (first (status-im.utils.utils/exclude-svg-resources icons))
|
||||
visible-accounts @(re-frame/subscribe [:visible-accounts-without-watch-only])
|
||||
(defn account-selector-bottom-sheet [{:keys [session show-account-selector? idx]}]
|
||||
(when @show-account-selector?
|
||||
[rn/view {:style (cond-> {:height 50}
|
||||
(= idx 0) (assoc :margin-top 50))}
|
||||
[bottom-panel/animated-bottom-panel
|
||||
session
|
||||
app-management-sheet-view
|
||||
true]]))
|
||||
|
||||
(defn print-session-info [{:keys [session visible-accounts show-account-selector?]}]
|
||||
(let [peer-meta (get-in session [:params 0 :peerMeta])
|
||||
peer-id (get-in session [:params 0 :peerId])
|
||||
name (get peer-meta :name)
|
||||
url (get peer-meta :url)
|
||||
account (get-in session [:params 0 :accounts 0])
|
||||
icons (get peer-meta :icons)
|
||||
icon-uri (first (status-im.utils.utils/exclude-svg-resources icons))
|
||||
selected-account (first (filter
|
||||
#(= account
|
||||
(:address %))
|
||||
@@ -25,28 +37,51 @@
|
||||
[rn/view
|
||||
[:<>
|
||||
[rn/view {:style styles/app-row}
|
||||
[react/image {:style styles/dapp-icon :source {:uri icon-uri}}]
|
||||
[react/image {:style styles/dapp-icon
|
||||
:source {:uri icon-uri}}]
|
||||
[rn/view {:style styles/app-column}
|
||||
[quo/text {:style styles/dapp-name} name]
|
||||
[quo/text {:style styles/dapp-url} url]]
|
||||
|
||||
[rn/view {:flex-direction :row
|
||||
:position :absolute
|
||||
:right 10
|
||||
:align-items :center}
|
||||
[rn/touchable-opacity {:style styles/delete-icon-container
|
||||
:position :absolute
|
||||
:right 10
|
||||
:align-items :center}
|
||||
[rn/touchable-opacity {:style styles/delete-icon-container
|
||||
:on-press #(re-frame/dispatch [:wallet-connect-legacy/disconnect session])}
|
||||
|
||||
[icons/icon :icons/delete {:width 20
|
||||
:height 20
|
||||
[icons/icon :icons/delete {:width 20
|
||||
:height 20
|
||||
:container-style {:elevation 3}
|
||||
:color colors/red}]]
|
||||
|
||||
:color colors/red}]]
|
||||
(when selected-account ;; The account might not be available in theory, if deleted
|
||||
[rn/view {:style (styles/selected-account-container (:color selected-account))}
|
||||
[rn/touchable-opacity {:style (styles/selected-account-container (:color selected-account))
|
||||
:on-press #(swap! show-account-selector? not)}
|
||||
[rn/text {:style styles/selected-account} (:name selected-account)]])]]]]))
|
||||
|
||||
(defn list-item [{:keys [session visible-accounts show-account-selector?]} idx]
|
||||
[rn/view
|
||||
[print-session-info {:session session
|
||||
:visible-accounts visible-accounts
|
||||
:show-account-selector? show-account-selector?}]
|
||||
[account-selector-bottom-sheet {:session session
|
||||
:show-account-selector? show-account-selector?
|
||||
:idx idx}]])
|
||||
|
||||
(defn list-comp [sessions visible-accounts]
|
||||
(let [items (reagent/atom (doall (map (fn [session]
|
||||
(let [show-account-selector? (reagent/atom false)]
|
||||
{:visible-accounts visible-accounts
|
||||
:show-account-selector? show-account-selector?
|
||||
:session session}))
|
||||
@sessions)))]
|
||||
[rn/flat-list {:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:data @items
|
||||
:render-fn list-item
|
||||
:key-fn str}]))
|
||||
|
||||
(defn views []
|
||||
(let [legacy-sessions @(re-frame/subscribe [:wallet-connect-legacy/sessions])]
|
||||
[rn/view {:margin-top 10}
|
||||
(doall (map print-session-info legacy-sessions))]))
|
||||
(let [sessions (reagent/atom (<sub [:wallet-connect-legacy/sessions]))
|
||||
visible-accounts (<sub [:visible-accounts-without-watch-only])]
|
||||
[list-comp sessions visible-accounts]))
|
||||
|
||||
@@ -181,4 +181,4 @@
|
||||
;; TODO: Remove this (highly) temporary flag once the new Activity Center is
|
||||
;; usable enough to replace the old one **in the new UI**.
|
||||
(def new-activity-center-enabled?
|
||||
(atom true))
|
||||
(atom false))
|
||||
|
||||
@@ -240,9 +240,3 @@
|
||||
|
||||
(defn to-ms [sec]
|
||||
(* 1000 sec))
|
||||
|
||||
(defn now->iso8601 []
|
||||
(unparse {:format-str "HH:mm:ss.SSS"}
|
||||
(-> (timestamp)
|
||||
(from-long)
|
||||
(plus time-zone-offset))))
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
(ns status-im.utils.number)
|
||||
|
||||
(defn naive-round
|
||||
"Quickly and naively round number `n` up to `decimal-places`.
|
||||
|
||||
Example usage: use it to avoid re-renders caused by floating-point number
|
||||
changes in Reagent atoms. Such numbers can be rounded up to a certain number
|
||||
of `decimal-places` in order to avoid re-rendering due to tiny fractional
|
||||
changes.
|
||||
|
||||
Don't use this function for arbitrary-precision arithmetic."
|
||||
[n decimal-places]
|
||||
(let [scale (Math/pow 10 decimal-places)]
|
||||
(/ (Math/round (* n scale))
|
||||
scale)))
|
||||
@@ -0,0 +1,10 @@
|
||||
(ns status-im.utils.profiler)
|
||||
|
||||
(defmacro with-measure
|
||||
[name & body]
|
||||
`(let [start# (js/performance.now)
|
||||
res# (do ~@body)
|
||||
end# (js/performance.now)
|
||||
time# (.toFixed (- end# start#) 2)]
|
||||
(taoensso.timbre/info "[perf|" ~name "] => " time#)
|
||||
res#))
|
||||
@@ -0,0 +1,39 @@
|
||||
(ns status-im.utils.profiler
|
||||
"Performance profiling for react components."
|
||||
(:require-macros [status-im.utils.profiler])
|
||||
(:require [reagent.core :as reagent]
|
||||
[taoensso.timbre :as log]
|
||||
[oops.core :refer [oget ocall]]
|
||||
[goog.functions :as f]))
|
||||
|
||||
(defonce memo (atom {}))
|
||||
|
||||
(def td (js/require "tdigest"))
|
||||
(def tdigest (oget td "TDigest"))
|
||||
|
||||
(def react (js/require "react"))
|
||||
(def profiler (reagent/adapt-react-class (oget react "Profiler")))
|
||||
|
||||
(defn on-render-factory
|
||||
[label]
|
||||
(let [buf (new tdigest)
|
||||
log (f/debounce
|
||||
(fn [phase buf]
|
||||
(log/info "[profile:" label "(" phase ")]: \n"
|
||||
(ocall buf "summary")))
|
||||
300)]
|
||||
(fn [_ phase adur _ _ _ _]
|
||||
(.push buf adur)
|
||||
(log phase buf))))
|
||||
|
||||
(defn perf [{:keys [label]}]
|
||||
(let [this (reagent/current-component)
|
||||
children (reagent/children this)
|
||||
on-render (if-let [render-fn (get @memo label)]
|
||||
render-fn
|
||||
(do
|
||||
(swap! memo assoc label (on-render-factory label))
|
||||
(get @memo label)))]
|
||||
(into [profiler {:id label
|
||||
:on-render on-render}]
|
||||
children)))
|
||||
@@ -105,6 +105,15 @@
|
||||
(.then #(log/debug "[wallet-connect] session topic " topic " changed to account " (first accounts)))
|
||||
(.catch #(log/error "[wallet-connect] " %)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-change-session
|
||||
(fn [[client topic accounts]]
|
||||
(-> ^js client
|
||||
(.update (clj->js {:topic topic
|
||||
:state {:accounts accounts}}))
|
||||
(.then #(log/debug "[wallet-connect] session topic " topic " changed to account " (first accounts)))
|
||||
(.catch #(log/error "[wallet-connect] " %)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:wc-2-pair
|
||||
(fn [[client uri]]
|
||||
|
||||
@@ -142,31 +142,41 @@
|
||||
(:wallet-connect-legacy/sessions db))]
|
||||
{:wc-1-clean-up-sessions connectors}))
|
||||
|
||||
(fx/defn session-connected
|
||||
{:events [:wallet-connect-legacy/created]}
|
||||
[{:keys [db]} session]
|
||||
(let [connector (get db :wallet-connect-legacy/proposal-connector)
|
||||
session (assoc (types/js->clj session)
|
||||
:wc-version constants/wallet-connect-version-1
|
||||
:connector connector)
|
||||
info (.stringify js/JSON (.-session connector))
|
||||
peer-id (get-in session [:params 0 :peerId])
|
||||
dapp-name (get-in session [:params 0 :peerMeta :name])
|
||||
dapp-url (get-in session [:params 0 :peerMeta :url])]
|
||||
{:show-wallet-connect-success-sheet nil
|
||||
:db (-> db
|
||||
(assoc :wallet-connect/session-connected session)
|
||||
(update :wallet-connect-legacy/sessions
|
||||
conj
|
||||
session))
|
||||
::json-rpc/call [{:method "wakuext_addWalletConnectSession"
|
||||
(fx/defn save-session
|
||||
{:events [:wallet-connect-legacy/save-session]}
|
||||
[{:keys [db]} {:keys [peer-id dapp-name dapp-url connector]}]
|
||||
(let [info (.stringify js/JSON (.-session connector))]
|
||||
{::json-rpc/call [{:method "wakuext_addWalletConnectSession"
|
||||
:params [{:id peer-id
|
||||
:info info
|
||||
;; info will be the updated value
|
||||
:dappName dapp-name
|
||||
:dappUrl dapp-url}]
|
||||
:on-success #(log/info "wakuext_addWalletConnectSession success call back , data =>" %)
|
||||
:on-error #(log/error "wakuext_addWalletConnectSession error call back , data =>" %)}]}))
|
||||
|
||||
(fx/defn session-connected
|
||||
{:events [:wallet-connect-legacy/created]}
|
||||
[{:keys [db] :as cofx} session]
|
||||
(let [connector (get db :wallet-connect-legacy/proposal-connector)
|
||||
session (assoc (types/js->clj session)
|
||||
:wc-version constants/wallet-connect-version-1
|
||||
:connector connector)
|
||||
peer-id (get-in session [:params 0 :peerId])
|
||||
dapp-name (get-in session [:params 0 :peerMeta :name])
|
||||
dapp-url (get-in session [:params 0 :peerMeta :url])]
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc :wallet-connect/session-connected session)
|
||||
(update :wallet-connect-legacy/sessions
|
||||
conj
|
||||
session))
|
||||
:show-wallet-connect-success-sheet nil}
|
||||
(save-session {:peer-id peer-id
|
||||
:dapp-name dapp-name
|
||||
:dapp-url dapp-url
|
||||
:connector connector}))))
|
||||
|
||||
(fx/defn manage-app
|
||||
{:events [:wallet-connect-legacy/manage-app]}
|
||||
[{:keys [db]} session]
|
||||
@@ -211,16 +221,20 @@
|
||||
|
||||
(fx/defn change-session-account
|
||||
{:events [:wallet-connect-legacy/change-session-account]}
|
||||
[{:keys [db]} session account]
|
||||
(let [connector (:connector session)
|
||||
address (:address account)
|
||||
networks (get db :networks/networks)
|
||||
[{:keys [db] :as cofx} session account]
|
||||
(let [connector (:connector session)
|
||||
address (:address account)
|
||||
networks (get db :networks/networks)
|
||||
current-network-id (get db :networks/current-network)
|
||||
current-network (get networks current-network-id)
|
||||
chain-id (get-in current-network [:config :NetworkId])]
|
||||
{:hide-wallet-connect-app-management-sheet nil
|
||||
:wc-1-update-session [connector chain-id address]
|
||||
:db (assoc db :wallet-connect/showing-app-management-sheet? false)}))
|
||||
current-network (get networks current-network-id)
|
||||
dapp-name (get-in session [:params 0 :peerMeta :name])
|
||||
dapp-url (get-in session [:params 0 :peerMeta :url])
|
||||
peer-id (get-in session [:params 0 :peerId])
|
||||
chain-id (get-in current-network [:config :NetworkId])]
|
||||
(fx/merge cofx
|
||||
{:hide-wallet-connect-app-management-sheet nil
|
||||
:wc-1-update-session [connector chain-id address]
|
||||
:db (assoc db :wallet-connect/showing-app-management-sheet? false)})))
|
||||
|
||||
(fx/defn disconnect-by-peer-id
|
||||
{:events [:wallet-connect-legacy/disconnect-by-peer-id]}
|
||||
@@ -268,10 +282,18 @@
|
||||
(let [sessions (get db :wallet-connect-legacy/sessions)
|
||||
accounts-new (:accounts (first (:params payload)))
|
||||
session (first (filter #(= (:connector %) connector) sessions))
|
||||
updated-session (assoc-in session [:params 0 :accounts] accounts-new)]
|
||||
{:db (-> db
|
||||
(assoc :wallet-connect-legacy/sessions (conj (filter #(not= (:connector %) connector) sessions) updated-session))
|
||||
(dissoc :wallet-connect/session-managed))}))
|
||||
updated-session (assoc-in session [:params 0 :accounts] accounts-new)
|
||||
peer-id (get-in updated-session [:params 0 :peerId])
|
||||
dapp-name (get-in updated-session [:params 0 :peerMeta :name])
|
||||
dapp-url (get-in updated-session [:params 0 :peerMeta :url])]
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(assoc :wallet-connect-legacy/sessions (conj (filter #(not= (:connector %) connector) sessions) updated-session))
|
||||
(dissoc :wallet-connect/session-managed))
|
||||
:dispatch [:wallet-connect-legacy/save-session {:peer-id peer-id
|
||||
:dapp-url dapp-url
|
||||
:dapp-name dapp-name
|
||||
:connector connector}]})))
|
||||
|
||||
(fx/defn wallet-connect-legacy-complete-transaction
|
||||
{:events [:wallet-connect-legacy.dapp/transaction-on-result]}
|
||||
@@ -338,7 +360,8 @@
|
||||
(fx/defn sync-app-db-with-wc-sessions
|
||||
{:events [:sync-wallet-connect-app-sessions]}
|
||||
[{:keys [db]} session-data]
|
||||
(let [chain-id (get-in db [:networks/networks (:networks/current-network db) :config :NetworkId])
|
||||
(let [_ (log/debug "sync-app-db-with-wc-sessions")
|
||||
chain-id (get-in db [:networks/networks (:networks/current-network db) :config :NetworkId])
|
||||
sessions (->> session-data
|
||||
(map :info)
|
||||
(map js/JSON.parse)
|
||||
@@ -347,7 +370,7 @@
|
||||
{:initialize-wc-sessions [chain-id sessions]})))
|
||||
|
||||
(fx/defn get-connector-session-from-db
|
||||
{:events [:get-connector-session-from-db]}
|
||||
{:events [:wallet-connect-legacy/get-connector-session-from-db]}
|
||||
[_]
|
||||
{::json-rpc/call [{:method "wakuext_getWalletConnectSession"
|
||||
:on-success #(re-frame/dispatch [:sync-wallet-connect-app-sessions %])
|
||||
|
||||
@@ -298,8 +298,7 @@ class TestrailReport(BaseTestReport):
|
||||
try:
|
||||
test_id = self.get('get_results_for_case/%s/%s' % (test_run_id, test_case_id))['results'][0]['test_id']
|
||||
return '%stests/view/%s' % (self.url, test_id)
|
||||
except (KeyError, JSONDecodeError):
|
||||
print('Cannot extract result for %s e2e' % test_case_id)
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def get_not_executed_tests(self, test_run_id):
|
||||
|
||||
@@ -280,21 +280,18 @@ class TestBrowserProfileOneDevice(MultipleSharedDeviceTestCase):
|
||||
@marks.testrail_id(702166)
|
||||
def test_profile_add_custom_network(self):
|
||||
self.home.get_back_to_home_view()
|
||||
rpc, name, id, symbol = 'https://polygon-rpc.com/', 'Polygon', '137', 'MATIC'
|
||||
profile = self.home.profile_button.click()
|
||||
profile.add_custom_network(rpc_url=rpc, netwrok_id=id, symbol=symbol, name=name)
|
||||
profile.add_custom_network()
|
||||
self.sign_in.sign_in()
|
||||
wallet = self.home.wallet_button.click()
|
||||
if not wallet.element_by_text_part(symbol).is_element_displayed():
|
||||
self.errors.append("No %s currency is shown when switching to custom network" % symbol)
|
||||
self.home.profile_button.click()
|
||||
profile.advanced_button.click()
|
||||
profile.network_settings_button.scroll_to_element(10, 'up')
|
||||
if not profile.element_by_text_part(name).is_element_displayed():
|
||||
self.driver.fail("Custom network %s was not added!" % name)
|
||||
if not profile.element_by_text_part('custom_ropsten').is_element_displayed():
|
||||
self.driver.fail("Network custom_ropsten was not added!")
|
||||
profile.get_back_to_home_view()
|
||||
# Switching back to Goerli for the next cases
|
||||
profile.switch_network('Goerli with upstream RPC')
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702164)
|
||||
|
||||
@@ -298,13 +298,12 @@ class ProfileView(BaseView):
|
||||
self.active_network_name = Text(self.driver,
|
||||
xpath="//android.widget.TextView[contains(@text,'with upstream RPC')]")
|
||||
self.plus_button = Button(self.driver, xpath="(//android.widget.ImageView[@content-desc='icon'])[2]")
|
||||
self.custom_chain_button = Button(self.driver, translation_id="custom")
|
||||
self.ropsten_chain_button = Button(self.driver, translation_id="ropsten-network")
|
||||
self.custom_network_url_input = EditBox(self.driver, translation_id="rpc-url",
|
||||
suffix="/following-sibling::*[1]/android.widget.EditText")
|
||||
self.custom_network_symbol_input = EditBox(self.driver, translation_id="specify-symbol")
|
||||
self.specify_name_input = EditBox(self.driver, translation_id="name",
|
||||
suffix="/following-sibling::*[1]/android.widget.EditText")
|
||||
self.specify_network_id_input = EditBox(self.driver, translation_id="specify-network-id")
|
||||
self.connect_button = Button(self.driver, accessibility_id="network-connect-button")
|
||||
## Toggles
|
||||
self.transaction_management_enabled_toggle = Button(self.driver,
|
||||
@@ -362,18 +361,19 @@ class ProfileView(BaseView):
|
||||
from views.chat_view import ChatView
|
||||
return ChatView(self.driver)
|
||||
|
||||
def add_custom_network(self, rpc_url: str, name: str, symbol: str, netwrok_id:str):
|
||||
self.driver.info("## Add custom network", device=False)
|
||||
def add_custom_network(self, rpc_url='https://ropsten.infura.io/v3/f315575765b14720b32382a61a89341a',
|
||||
name='custom_ropsten', symbol='ETHro'):
|
||||
self.driver.info("## Add predefined custom network", device=False)
|
||||
self.advanced_button.click()
|
||||
self.network_settings_button.scroll_to_element()
|
||||
self.network_settings_button.click()
|
||||
self.plus_button.click_until_presence_of_element(self.custom_chain_button)
|
||||
self.custom_network_url_input.set_value(rpc_url)
|
||||
self.specify_name_input.set_value(name)
|
||||
self.plus_button.click_until_presence_of_element(self.ropsten_chain_button)
|
||||
self.custom_network_url_input.send_keys(rpc_url)
|
||||
self.specify_name_input.send_keys(name)
|
||||
self.custom_network_symbol_input.set_value(symbol)
|
||||
self.custom_chain_button.scroll_and_click()
|
||||
self.specify_network_id_input.scroll_to_element()
|
||||
self.specify_network_id_input.set_value(netwrok_id)
|
||||
self.ropsten_chain_button.scroll_to_element()
|
||||
self.ropsten_chain_button.click()
|
||||
self.ropsten_chain_button.click()
|
||||
self.save_button.click()
|
||||
self.element_by_text_part(name).scroll_to_element()
|
||||
self.element_by_text_part(name).click_until_presence_of_element(self.connect_button)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"active-online": "Online",
|
||||
"active-unknown": "Unknown",
|
||||
"add": "Add",
|
||||
"added": "added",
|
||||
"add-a-watch-account": "Add a watch-only address",
|
||||
"add-account": "Add an account",
|
||||
"add-account-description": "You can import any type of Ethereum account to add it to your Status wallet",
|
||||
@@ -857,8 +856,6 @@
|
||||
"members-active-none": "no members",
|
||||
"members-title": "Members",
|
||||
"message": "Message",
|
||||
"message-deleted": "Message deleted",
|
||||
"message-deleted-for-you": "Message deleted for you",
|
||||
"message-not-sent": "Message not sent",
|
||||
"message-options-cancel": "Cancel",
|
||||
"message-reply": "Reply",
|
||||
@@ -994,6 +991,8 @@
|
||||
"open": "Open",
|
||||
"open-home": "Open...",
|
||||
"open-dapp": "Open ÐApp",
|
||||
"open-dapp2": "Open dApp",
|
||||
"ens-banner-message": "If you registered a stateofus.eth name you might be eligible to collect $ENS",
|
||||
"open-dapp-store": "Discover ÐApps",
|
||||
"open-nfc-settings": "Open NFC settings",
|
||||
"open-on-block-explorer": "Open on block explorer",
|
||||
@@ -1305,7 +1304,6 @@
|
||||
"last-backup-performed": "Last backup performed:",
|
||||
"unable-to-read-this-code": "Unable to read this code",
|
||||
"unblock-contact": "Unblock this user",
|
||||
"undo": "Undo",
|
||||
"unknown-status-go-error": "Unknown status-go error",
|
||||
"unlock": "Unlock",
|
||||
"unpair-card": "Unpair card",
|
||||
@@ -1657,7 +1655,6 @@
|
||||
"accept-and-continue": "Accept and continue",
|
||||
"empty-activity-center": "Your chat notifications\nwill appear here",
|
||||
"pinned-messages": "Pinned messages",
|
||||
"pinned-a-message": "pinned a message",
|
||||
"pin": "Pin",
|
||||
"unpin": "Unpin",
|
||||
"no-pinned-messages": "No pinned messages",
|
||||
@@ -1765,7 +1762,6 @@
|
||||
"new-ui": "New UI",
|
||||
"send-contact-request-message": "To start a chat you need to become contacts",
|
||||
"contact-request": "Contact request",
|
||||
"contact-requests": "Contact Requests",
|
||||
"say-hi": "Say hi",
|
||||
"opened" : "Opened",
|
||||
"accepted": "Accepted",
|
||||
@@ -1802,11 +1798,5 @@
|
||||
"edit-message": "Edit message",
|
||||
"save-image-library": "Save image to library",
|
||||
"share-image": "Share image",
|
||||
"see-sticker-set": "See the full sticker set",
|
||||
"mentions": "Mentions",
|
||||
"admin": "Admin",
|
||||
"replies": "Replies",
|
||||
"identity-verification": "Identity verification",
|
||||
"membership": "Membership",
|
||||
"jump-to": "Jump to"
|
||||
"see-sticker-set": "See the full sticker set"
|
||||
}
|
||||
|
||||
@@ -564,6 +564,7 @@
|
||||
"ens-10-SNT": "10 एसएनटी",
|
||||
"ens-add-username": "उपयोगकर्ता नाम जोड़ें",
|
||||
"ens-agree-to": "सहमत होना",
|
||||
"ens-banner-message": "यदि आपने एक Stateofus.eth नाम पंजीकृत किया है तो आप $ENS एकत्र करने के योग्य हो सकते हैं",
|
||||
"ens-chat-settings": "चैट सेटिंग्स",
|
||||
"ens-custom-domain": "कस्टम डोमेन",
|
||||
"ens-custom-username-hints": "कस्टम डोमेन जैसे username.domain.eth . सहित संपूर्ण उपयोगकर्ता नाम टाइप करें",
|
||||
@@ -1176,6 +1177,7 @@
|
||||
"open-chat": "चैट खोलें",
|
||||
"open-dapp": "ऐप . खोलें",
|
||||
"open-dapp-store": "ऐप्स . खोजें",
|
||||
"open-dapp2": "डीएपी खोलें",
|
||||
"open-home": "खुला...",
|
||||
"open-in-new-tab": "नए टैब में खोलें",
|
||||
"open-membership": "खुली सदस्यता",
|
||||
@@ -1775,4 +1777,4 @@
|
||||
"your-recovery-phrase-description": "यह आपका बीज वाक्यांश है। आप इसका उपयोग यह साबित करने के लिए करते हैं कि यह आपका बटुआ है। आप इसे केवल एक बार देख सकते हैं! इसे कागज पर लिखकर सुरक्षित स्थान पर रख दें। यदि आप अपना बटुआ खो देते हैं या पुनः स्थापित करते हैं तो आपको इसकी आवश्यकता होगी।",
|
||||
"your-tip-limit": "आपकी टिप सीमा",
|
||||
"youre-on-mobile-network": "आप मोबाइल नेटवर्क पर हैं"
|
||||
}
|
||||
}
|
||||
@@ -553,6 +553,7 @@
|
||||
"ens-10-SNT": "10 SNT",
|
||||
"ens-add-username": "ユーザ名を追加",
|
||||
"ens-agree-to": "に同意する",
|
||||
"ens-banner-message": "stateofus.eth 名を登録した方は、$ENS を収集する資格がある可能性があります",
|
||||
"ens-chat-settings": "チャット設定",
|
||||
"ens-custom-domain": "カスタムドメイン",
|
||||
"ens-custom-username-hints": "username.domain.eth のようにカスタムドメインを含むユーザ名全体を入力してください",
|
||||
@@ -1163,6 +1164,7 @@
|
||||
"open-chat": "チャットを開く",
|
||||
"open-dapp": "ÐAppを開く",
|
||||
"open-dapp-store": "ÐAppsを見つける",
|
||||
"open-dapp2": "dAppを開く",
|
||||
"open-home": "開く",
|
||||
"open-in-new-tab": "新しいタブで開く",
|
||||
"open-membership": "オープンメンバーシップ",
|
||||
@@ -1760,4 +1762,4 @@
|
||||
"your-recovery-phrase-description": "これはあなたのシードフレーズです。ウォレットがあなたのものであることを証明するために使用します。一度だけしか見ることができません。紙に書くか安全な場所で保管してください。紛失やアプリを再インストールする際に必要になります。",
|
||||
"your-tip-limit": "チップ設定値",
|
||||
"youre-on-mobile-network": "モバイルネットワークを利用しています"
|
||||
}
|
||||
}
|
||||
@@ -564,6 +564,7 @@
|
||||
"ens-10-SNT": "10 SNT",
|
||||
"ens-add-username": "Adicionar nome de usuário ",
|
||||
"ens-agree-to": "Concordo com",
|
||||
"ens-banner-message": "Se você registrou um nome stateofus.eth, pode ser elegível para receber $ENS",
|
||||
"ens-chat-settings": "Configurações de bate-papo",
|
||||
"ens-custom-domain": "Domínio personalizado",
|
||||
"ens-custom-username-hints": "Digite o nome de usuário inteiro, incluindo o domínio personalizado, como nomedeusuario.domínio.eth",
|
||||
@@ -1175,6 +1176,7 @@
|
||||
"open-chat": "Abrir chat",
|
||||
"open-dapp": "Abrir ÐApp",
|
||||
"open-dapp-store": "Descubra ÐApps",
|
||||
"open-dapp2": "Abrir dApp",
|
||||
"open-home": "Abrir...",
|
||||
"open-in-new-tab": "Abrir em nova aba",
|
||||
"open-membership": "Participação aberta",
|
||||
@@ -1771,4 +1773,4 @@
|
||||
"your-recovery-phrase-description": "Esta é sua frase-semente. Você a usa para provar que esta é sua carteira. Você só pode vê-la uma vez! Escreva no papel e mantenha em um lugar seguro. Você vai precisar dela se perder ou reinstalar sua carteira.",
|
||||
"your-tip-limit": "Seu limite de gorjeta",
|
||||
"youre-on-mobile-network": "Você está em uma rede móvel"
|
||||
}
|
||||
}
|
||||
@@ -597,6 +597,7 @@
|
||||
"ens-10-SNT": "10 SNT",
|
||||
"ens-add-username": "Добавить имя пользователя",
|
||||
"ens-agree-to": "Согласиться с ",
|
||||
"ens-banner-message": "Если вы зарегистрировали имя на stateofus.eth, вы можете получить право на получение $ENS.",
|
||||
"ens-chat-settings": "Настройки чата",
|
||||
"ens-custom-domain": "Пользовательский домен",
|
||||
"ens-custom-username-hints": "Введите полное имя пользователя, включая пользовательский домен, например username.domain.eth",
|
||||
@@ -1215,6 +1216,7 @@
|
||||
"open-chat": "Создать чат",
|
||||
"open-dapp": "Открыть ÐApp",
|
||||
"open-dapp-store": "Откройте для себя мир ÐApp-приложений",
|
||||
"open-dapp2": "Открыть dApp",
|
||||
"open-home": "Открыть...",
|
||||
"open-in-new-tab": "Открыть в новой вкладке",
|
||||
"open-membership": "Открытое участие",
|
||||
@@ -1820,4 +1822,4 @@
|
||||
"your-recovery-phrase-description": "Это ваша сид-фраза. Она используется для доказательства владения кошельком. Вы увидите ее только один раз! Запишите ее на бумаге и храните в надежном месте. Она понадобится вам, если вы потеряете или переустановите кошелек.",
|
||||
"your-tip-limit": "Ваш лимит чаевых",
|
||||
"youre-on-mobile-network": "Вы используете мобильную сеть"
|
||||
}
|
||||
}
|
||||
@@ -2628,6 +2628,11 @@ bindings@^1.5.0:
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bintrees@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524"
|
||||
integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=
|
||||
|
||||
binwrap@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/binwrap/-/binwrap-0.2.2.tgz#7d1ea74b28332f18dfdc75548aef993041ffafc9"
|
||||
@@ -2879,7 +2884,7 @@ buffer@^4.3.0, buffer@^4.9.1:
|
||||
ieee754 "^1.1.4"
|
||||
isarray "^1.0.0"
|
||||
|
||||
buffer@^5.4.3:
|
||||
buffer@^5.4.2, buffer@^5.4.3:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786"
|
||||
integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==
|
||||
@@ -4011,10 +4016,10 @@ eth-lib@0.2.7:
|
||||
elliptic "^6.4.0"
|
||||
xhr-request-promise "^0.1.2"
|
||||
|
||||
eth-phishing-detect@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eth-phishing-detect/-/eth-phishing-detect-1.2.0.tgz#11b357776b2d1b98a9ac594a1343e5184fc26bf0"
|
||||
integrity sha512-+M7D4dhu5tkSA9b5eiBwDeJCjwy+7Lv49nuTEw8fNZIZUAVZC3d2XHatBq1MOW7J8kxNGbBdgBuIf65opI7Tkg==
|
||||
eth-phishing-detect@^1.1.13:
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/eth-phishing-detect/-/eth-phishing-detect-1.1.14.tgz#64dcd35dd3a7a95266d875cbc5280842cda133d7"
|
||||
integrity sha512-nMQmzrgYabZ52YpuKZ38lStJy9Lozww2WBhyFbu/oepjsZzPvnl2KwJ6TJ78kk14USdl8Htt+eEMk2WAdAjlWg==
|
||||
dependencies:
|
||||
fast-levenshtein "^2.0.6"
|
||||
|
||||
@@ -4763,6 +4768,11 @@ hermes-profile-transformer@^0.0.6:
|
||||
dependencies:
|
||||
source-map "^0.7.3"
|
||||
|
||||
hi-base32@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/hi-base32/-/hi-base32-0.5.0.tgz#61329f76a31f31008533f1c36f2473e259d64571"
|
||||
integrity sha512-DDRmxSyoYuvjUb9EnXdoiMChBZ7ZcUVJsK5Frd3kqMhuBxvmZdnBeynAVfj7/ECbn++CekcoprvC/rprHPAtow==
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
@@ -9383,6 +9393,13 @@ tar@^6.1.0, tar@^6.1.11:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
tdigest@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021"
|
||||
integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=
|
||||
dependencies:
|
||||
bintrees "1.0.1"
|
||||
|
||||
temp@0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59"
|
||||
|
||||