Compare commits

...
Author SHA1 Message Date
Omar Basem 0e08529da0 tests 2022-12-07 19:13:25 +04:00
Omar Basem 95d927c941 lint 2022-12-06 09:38:30 +04:00
Omar Basem 9dfb855090 refactor 2022-12-06 09:38:30 +04:00
Omar Basem 775d9e5457 lint 2022-12-06 09:38:30 +04:00
Omar Basem 294eb34418 updates 2022-12-06 09:38:29 +04:00
flexsurfer da0f0d3a81 move messages main screen to status-im2 (#14491)
* move messages main screen to status-im2
2022-12-05 14:22:06 +01:00
frank f7af7ca25d Allow owner/admin to delete messages of a community (#14366) 2022-12-02 20:13:02 +08:00
Christoph Pader f3ad8beb6d fix: channel list-item not clickable (#14469) 2022-12-02 11:45:26 +01:00
yqrashawn 2e68fb22f5 feat: add display-name in author component (#14473) 2022-12-02 14:42:16 +08:00
Christoph Pader f18044c9dc Implement Token Gating (#13899)
* feat: implement token gating component

* fix: add .calva to gitignore
2022-12-01 13:30:07 +00:00
Jamie Caprani 5947769881 chore: update action drawer with designer feedback (#14465) 2022-12-01 03:58:50 -08:00
Parvesh Monu d4897de205 partially implement shell jump-to navigation (#14410) 2022-11-30 21:46:01 +05:30
Jamie Caprani d948939ce3 fix: adjust community cards on discover page (#14444)
fix: adjust community cards on discover page
2022-11-30 01:58:44 -08:00
Yevheniia Berdnyk 1000cb79a2 Creating users and getting names in parallel 2022-11-29 18:09:39 +02:00
Mohamed Javid f55b646c20 [Chore] Use common for repeated code (#14454)
* [Chore] Use common for repeated code

* [Chore] Removed empty file
2022-11-29 22:47:35 +08:00
Mohamed Javid bc7578ae85 [Feature] Added Mentions in Activity Center (#14451)
* [Feature][#14352] Added mentions in Activity Center

* [Update][#14352] Update in namespace

* [Update][#14352] Code Style

* [Update][#14352] Created commons for AC and fix warning on text
2022-11-29 21:55:33 +08:00
Omar Basem 49e9738ff8 Group Details Screen (2) (#14427)
* feat: group details screen (2)
2022-11-29 10:41:19 +04:00
Brian Sztamfater 9e1412007f fix: edit message
Signed-off-by: Brian Sztamfater <brian@status.im>
2022-11-28 10:21:50 -03:00
Icaro Motta c198133769 Update guidelines (#14445) 2022-11-28 09:58:36 -03:00
Jamie Caprani 6d5ff4aa92 chore: fix issues with e2e tests after refactors (#14440) 2022-11-28 03:17:12 -08:00
Jamie Caprani 0e614d51ef feat: add scrolling in community (#14281) 2022-11-28 02:24:31 -08:00
Icaro Motta 42de2a6384 Mark notifications as read based on call to action (#14439) 2022-11-25 16:10:29 -03:00
Ibrahem Khalil 3d71fdba98 [14429] Fix mentions (#14442) 2022-11-25 15:04:15 +02:00
Jamie Caprani 9de4417f03 chore: update nix config to reference babel.config.js file (#14436)
* chore: update nix config to reference babel.config.js file

* chore: update component test make command
2022-11-24 13:05:58 -08:00
Parvesh Monu 9e7db45d08 fix everyone is displaying as online in community channel and chat list (#14431)
also fixes issue with visibility status popover not opening
2022-11-24 19:45:27 +05:30
Omar Basem 14c243803f Photo Selector (1) (#14426)
* feat: photo-selector (1)
2022-11-24 15:29:54 +04:00
jakub e61889f16c ci: add missing suffix to android e2e builds
Fix for same naming of e2e and universal builds.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2022-11-24 10:23:28 +01:00
Parvesh Monu 1230594046 test build fix (#14435) 2022-11-24 14:50:57 +05:30
jakub 3fc1ba357e ci: bump jenkins lib to match desktop
Related to: https://github.com/status-im/status-desktop/pull/8420
Depends on: https://github.com/status-im/status-jenkins-lib/pull/53

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2022-11-23 19:48:55 +01:00
flexsurfer 3152cf0aa3 adjust navigation colors and small bugfixes (#14403)
* adjust navigation colors and small bugfixes
2022-11-23 17:30:11 +01:00
Jamie Caprani c6e8aad745 feat: add component tests using react-testing-library and jest (#14331) 2022-11-23 05:59:18 -08:00
flexsurfer bab0fc7ac0 move chats home (#14419)
* move chats home
2022-11-23 14:33:40 +01:00
frank 32d85d5059 Allow styling text in composer when selecting it with native actions (#14249) 2022-11-23 10:28:44 +08:00
Churikova Tetiana a9295ac17e e2e: test sections and fix 2022-11-22 17:44:28 +01:00
jakub 7dccbf2395 ci: separate buckets for mobile and desktop builds
Possible fix for slow upload speeds and failures caused by most probably
hitting per-bucket rate limits of DigitalOcean:

>- 500 total operations per second to any individual bucket.
>- 300 combined PUT, POST, COPY, DELETE, and LIST operations per second to any individual Space. We may further limit LIST operations if necessary under periods of high load.y

https://docs.digitalocean.com/products/spaces/details/limits/#rate-limits

Depends on: https://github.com/status-im/status-jenkins-lib/pull/52

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2022-11-22 16:55:59 +01:00
Brian Sztamfater 4a87122336 feat: author component
Signed-off-by: Brian Sztamfater <brian@status.im>
2022-11-21 15:46:56 -03:00
Roman Volosovskyi d18c3ad102 [#14381] Wrap texts with view to ensure separate accessibility labels 2022-11-21 15:40:29 +01:00
Icaro Motta e53f58d8c0 Fix various Activity Log layout issues (#14405) 2022-11-21 11:19:50 -03:00
Omar Basem 5492fb472f Group Details Screen (#14377)
* feat: group details screen
2022-11-21 16:03:49 +04:00
flexsurfer c08d58577d move quo preview (#14409) 2022-11-21 11:03:07 +01:00
Yevheniia Berdnyk 946640339a e2e: pin messages in 1-1 and group chats 2022-11-21 06:49:53 +02:00
Jamie CapraniandErik Seppanen 72d43ba745 Visual tests setup (#14329)
feat: configuration setup for visual tests

Co-authored-by: Erik Seppanen <esep@protonmail.com>
2022-11-20 15:46:04 -08:00
Icaro Motta f4d9162ff8 Fix reconciliation for new filter type :all (#14401) 2022-11-18 06:15:39 -03:00
Omar Basem 73bbfa7d31 Fix Metro Warnings ⚠️ (#14389)
* fix: metro warnings ⚠️
2022-11-17 21:19:54 +04:00
Mohamed Javid 84da3128bf [Fix] Activity Centre UI bug (#14398)
* [Fix] Activity Centre UI bug

* [Fix] Namespace update for config

* [Chore] Moved navigation to Activity Center as reframe event

* [Chore] Code Format
2022-11-18 00:15:49 +08:00
flexsurfer 3777ebc36e move communities 2 (#14394) 2022-11-17 16:43:02 +01:00
Roman Volosovskyi 4c6b4e2d02 [#14388] Re-enable bug reporting 2022-11-17 15:01:45 +01:00
Roman Volosovskyi e469d97702 [#14372] Fix message content type on editing 2022-11-17 08:23:53 +01:00
Roman Volosovskyi cf753a0892 [#14381] Add accessibility lables for chat key and timestamp in message 2022-11-17 07:16:30 +01:00
Icaro Motta 0f7ccce3df Implement identity verification flow (#14365) 2022-11-16 16:46:04 -03:00
Mohamed Javid 509ffc2a01 [Feature] Added messages skeleton (#14072)
* [Feature][#14025] Added Messages Skeleton while loading messages

* [Improvements][#14025] Added animation to message skeleton

* [Improvements][#14025] Changed to Reanimated2 for message skeleton animation

* [Chores][#14025] Removed unused code

* [Improvements][#14025] Added preview screen for messages skeleton

* [Improvements][#14025] Style update for messages skeleton

* [Chore][#14025] Indentation for message skeleton

* [Improvements][#14025] On Layout calculation cleanup

* [Fix][#14025] Added Skeleton on New UI only

* [Chore] Moved Message Skeleton to new UI

* [Feature][#14025] Added Message Skeleton on message gap

* [TEMP][#14025] Added delay of preloading messages for testing

* [Lint][#14025] Lint fixes for Message Gap component

* [Chore][#14025] Reanimated namespace update

* [Chore][#14025] React native namespace update

* [Chore][#14025] Rollback preload messages
2022-11-17 00:43:58 +08:00
John Ngei e44d4c83c0 communites home screen context actions (#14371) 2022-11-16 17:48:18 +03:00
flexsurfer cc733a379c move communities (#14384) 2022-11-16 14:09:16 +01:00
flexsurfer 803328dc4c move switcher (#14378)
* move switcher
2022-11-16 12:00:16 +01:00
Roman Volosovskyi 255049c312 Fix uniq :key warning on opening chat 2022-11-16 10:46:32 +01:00
flexsurfer 31b6e076be new structure continue, move utils, move fx macro to re-frame utils n… (#14373)
* new structure continue, move utils, move fx macro to re-frame utils namespace
2022-11-16 09:09:25 +01:00
frank 433f9185c8 Use WakuNodes in ClusterConfig for Waku V2 (#14283) 2022-11-16 00:27:19 +08:00
Andrea Maria Piana 04408af45c Fix logout & upgrade status-go 2022-11-15 15:17:59 +00:00
Omar Basem ea7548d54a Confirmation Dialog (#14348)
* feat: confirmation dialog
2022-11-15 17:34:38 +04:00
Andrea Maria Piana c7ac53fdd0 Add icons & mentions/unread counts to community list 2022-11-15 13:03:48 +00:00
Roman Volosovskyi 48f86ff862 [#14311] Fix icons in message actions bottom sheet 2022-11-15 13:29:12 +01:00
316 changed files with 11228 additions and 5144 deletions
-8
View File
@@ -1,8 +0,0 @@
{
"presets": [
"module:metro-react-native-babel-preset"
],
"plugins": [
"react-native-reanimated/plugin"
]
}
+1 -1
View File
@@ -200,7 +200,7 @@ status-im.utils.platform/isMacOs?
status-im.utils.platform/isNix?
status-im.utils.platform/isWin?
status-im.utils.platform/android-version>=
status-im.utils.debounce/clear-all
utils.debounce/clear-all
status-im.transport.db/create-chat
status-im.utils.priority-map/priority-map
status-im.utils.priority-map/priority-map-by
+2 -1
View File
@@ -2,12 +2,13 @@
status-im.utils.views/letsubs clojure.core/let
reagent.core/with-let clojure.core/let
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
quo.react/with-deps-check clojure.core/fn
quo.previews.preview/list-comp clojure.core/for
status-im.utils.styles/def clojure.core/def
status-im.utils.styles/defn clojure.core/defn
taoensso.tufte/defnp clojure.core/defn}
:linters {:invalid-arity {:skip-args [status-im.utils.fx/defn]}
:linters {:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
;;TODO remove number when this is fixed
;;https://github.com/borkdude/clj-kondo/issues/867
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY number]}}}
+37
View File
@@ -0,0 +1,37 @@
module.exports = {
"testRunner": "jest",
"testRegex": "\\.visual\\.js$",
"runner-config": "visual-test/config.json",
"devices": {
"simulator": {
"type": "ios.simulator",
"device": {
"type": "iPhone 11 Pro"
}
}
},
"apps": {
"ios.release": {
"name": "StatusIm",
"type": "ios.app",
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/StatusIm.app",
"build": "make release-ios"
},
"ios.debug": {
"name": "StatusIm",
"type": "ios.app",
"binaryPath": process.env.TEST_BINARY_PATH,
"build": "make run-ios SIMULATOR='iPhone 11 Pro'"
}
},
"configurations": {
"ios.sim.release": {
"device": "simulator",
"app": "ios.release"
},
"ios.sim.debug": {
"device": "simulator",
"app": "ios.debug"
}
}
}
+6
View File
@@ -7,6 +7,7 @@
# Xcode
#
/component-spec
result/
build/
*.pbxuser
@@ -175,3 +176,8 @@ test/appium/tests/users.py
##node bindings
/bin/
/lib/
## visual tests
/artifacts
/.calva/
+26 -3
View File
@@ -48,7 +48,7 @@ export _NIX_GCROOTS = /nix/var/nix/gcroots/per-user/$(USER)/status-mobile
# Defines which variables will be kept for Nix pure shell, use semicolon as divider
export _NIX_KEEP ?= TMPDIR,BUILD_ENV,STATUS_GO_SRC_OVERRIDE
# Useful for Andoird release builds
# Useful for Android release builds
TMP_BUILD_NUMBER := $(shell ./scripts/version/gen_build_no.sh | cut -c1-10)
# MacOS root is read-only, read nix/README.md for details
@@ -307,13 +307,36 @@ test-watch: ##@ Watch tests and re-run no changes to cljs files
test: export TARGET := clojure
test: ##@test Run tests once in NodeJS
# Here we creates the gyp bindings for nodejs
# Here we create the gyp bindings for nodejs
yarn install
yarn shadow-cljs compile mocks && \
yarn shadow-cljs compile test && \
node --require ./test-resources/override.js target/test/test.js
#--------------
run-visual-test-ios: export TARGET := clojure
run-visual-test-ios: XCODE_DERIVED_DATA := $(HOME)/Library/Developer/Xcode/DerivedData
run-visual-test-ios: APPLICATION_NAME := StatusIm-brfnruzfrkkycpbndmdoeyrigthc
run-visual-test-ios: export TEST_BINARY_PATH := $(XCODE_DERIVED_DATA)/$(APPLICATION_NAME)/Build/Products/Debug-iphonesimulator/StatusIm.app
run-visual-test-ios: ##@test Run tests once in NodeJS
detox test --configuration ios.sim.debug
component-test-watch: export TARGET := clojure
component-test-watch: export COMPONENT_TEST := true
component-test-watch: export BABEL_ENV := test
component-test-watch: ##@ Watch tests and re-run no changes to cljs files
yarn install
nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js' -e cljs
component-test: export TARGET := clojure
component-test: export COMPONENT_TEST := true
component-test: export BABEL_ENV := test
component-test: ##@test Run tests once in NodeJS
# Here we create the gyp bindings for nodejs
yarn install
yarn shadow-cljs compile component-test && \
jest --config=test/jest/jest.config.js
# Other
#--------------
+24
View File
@@ -0,0 +1,24 @@
module.exports = {
"presets": [
"module:metro-react-native-babel-preset"
],
"plugins": [
"react-native-reanimated/plugin"
],
"env": {
"test": {
"presets": [
'@babel/preset-react',
[
'@babel/preset-env',
{
targets: {
node: '14',
},
},
],
],
}
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -36,7 +36,7 @@ pipeline {
LANG = "en_US.UTF-8"
LC_ALL = "en_US.UTF-8"
LANGUAGE = "en_US.UTF-8"
TARGET = 'android'
TARGET = "android${utils.isE2EBuild() ? "-e2e" : ""}"
BUILD_ENV = 'prod'
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
FASTLANE_DISABLE_COLORS = 1
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
pipeline {
agent { label params.AGENT_LABEL }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -62,7 +62,7 @@ pipeline {
--rerun_count=2 \
--testrail_report=True \
-m testrail_id \
-m \"new_ui_critical\" \
-m \"new_ui_critical or new_ui_medium\" \
-k \"${params.KEYWORD_EXPRESSION}\" \
--apk=${params.APK_NAME}
"""
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
pipeline {
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.1'
library 'status-jenkins-lib@v1.6.3'
pipeline {
agent { label 'linux' }
+50
View File
@@ -62,6 +62,31 @@ with the source file using it. For a real example, see
(do-something)]])
```
#### Styles def vs defn
Always use `def` over `defn`, unless the style relies on dynamic values, such as
deref'ed atoms.
```clojure
;; bad
(defn title-column []
{:height 56})
;; good
(def title-column
{:height 56})
```
```clojure
;; bad
(def community-card
{:background-color (colors/theme-colors colors/white colors/neutral-90)})
;; good
(defn community-card []
{:background-color (colors/theme-colors colors/white colors/neutral-90)})
```
### Using TODOs comments
_TODO_ comments are used extensively in the codebase, but prefer to use them
@@ -249,6 +274,31 @@ test macros `deftest` and `is`, which are ubiquitous in the Clojure community.
(:require [cljs-time.coerce :as time.coerce]))
```
### Namespace aliases
Prefer the following namespace aliases:
```clojure
[clojure.string :as string]
[taoensso.timbre :as log]
```
### Javascript interop
Use [binaryage/oops](https://github.com/binaryage/cljs-oops) macros instead of
core interop macros.
```clojure
;; bad
(fn [^js event]
(.-width (.-nativeEvent event)))
;; good
(require '[oops.core :as oops])
(fn [event]
(oops/oget event "nativeEvent.width"))
```
### Accessibility labels
Use keywords instead of strings. As a bonus, remember keywords are cached in
+179 -179
View File
@@ -4,14 +4,14 @@ PODS:
- React
- CryptoSwift (1.5.1)
- DoubleConversion (1.1.6)
- FBLazyVector (0.63.4)
- FBReactNativeSpec (0.63.4):
- FBLazyVector (0.63.5)
- FBReactNativeSpec (0.63.5):
- Folly (= 2020.01.13.00)
- RCTRequired (= 0.63.4)
- RCTTypeSafety (= 0.63.4)
- React-Core (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- RCTRequired (= 0.63.5)
- RCTTypeSafety (= 0.63.5)
- React-Core (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- Folly (2020.01.13.00):
- boost-for-react-native
- DoubleConversion
@@ -40,172 +40,172 @@ PODS:
- RNPermissions
- Permission-Microphone (2.1.5):
- RNPermissions
- RCTRequired (0.63.4)
- RCTTypeSafety (0.63.4):
- FBLazyVector (= 0.63.4)
- RCTRequired (0.63.5)
- RCTTypeSafety (0.63.5):
- FBLazyVector (= 0.63.5)
- Folly (= 2020.01.13.00)
- RCTRequired (= 0.63.4)
- React-Core (= 0.63.4)
- React (0.63.4):
- React-Core (= 0.63.4)
- React-Core/DevSupport (= 0.63.4)
- React-Core/RCTWebSocket (= 0.63.4)
- React-RCTActionSheet (= 0.63.4)
- React-RCTAnimation (= 0.63.4)
- React-RCTBlob (= 0.63.4)
- React-RCTImage (= 0.63.4)
- React-RCTLinking (= 0.63.4)
- React-RCTNetwork (= 0.63.4)
- React-RCTSettings (= 0.63.4)
- React-RCTText (= 0.63.4)
- React-RCTVibration (= 0.63.4)
- React-callinvoker (0.63.4)
- React-Core (0.63.4):
- RCTRequired (= 0.63.5)
- React-Core (= 0.63.5)
- React (0.63.5):
- React-Core (= 0.63.5)
- React-Core/DevSupport (= 0.63.5)
- React-Core/RCTWebSocket (= 0.63.5)
- React-RCTActionSheet (= 0.63.5)
- React-RCTAnimation (= 0.63.5)
- React-RCTBlob (= 0.63.5)
- React-RCTImage (= 0.63.5)
- React-RCTLinking (= 0.63.5)
- React-RCTNetwork (= 0.63.5)
- React-RCTSettings (= 0.63.5)
- React-RCTText (= 0.63.5)
- React-RCTVibration (= 0.63.5)
- React-callinvoker (0.63.5)
- React-Core (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-Core/Default (= 0.63.5)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/CoreModulesHeaders (0.63.4):
- React-Core/CoreModulesHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/Default (0.63.4):
- React-Core/Default (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/DevSupport (0.63.4):
- React-Core/DevSupport (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default (= 0.63.4)
- React-Core/RCTWebSocket (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-jsinspector (= 0.63.4)
- React-Core/Default (= 0.63.5)
- React-Core/RCTWebSocket (= 0.63.5)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- React-jsinspector (= 0.63.5)
- Yoga
- React-Core/RCTActionSheetHeaders (0.63.4):
- React-Core/RCTActionSheetHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTAnimationHeaders (0.63.4):
- React-Core/RCTAnimationHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTBlobHeaders (0.63.4):
- React-Core/RCTBlobHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTImageHeaders (0.63.4):
- React-Core/RCTImageHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTLinkingHeaders (0.63.4):
- React-Core/RCTLinkingHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTNetworkHeaders (0.63.4):
- React-Core/RCTNetworkHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTSettingsHeaders (0.63.4):
- React-Core/RCTSettingsHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTTextHeaders (0.63.4):
- React-Core/RCTTextHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTVibrationHeaders (0.63.4):
- React-Core/RCTVibrationHeaders (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-Core/RCTWebSocket (0.63.4):
- React-Core/RCTWebSocket (0.63.5):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-Core/Default (= 0.63.5)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsiexecutor (= 0.63.5)
- Yoga
- React-CoreModules (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- React-CoreModules (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/CoreModulesHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- React-RCTImage (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-cxxreact (0.63.4):
- RCTTypeSafety (= 0.63.5)
- React-Core/CoreModulesHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- React-RCTImage (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-cxxreact (0.63.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-callinvoker (= 0.63.4)
- React-jsinspector (= 0.63.4)
- React-jsi (0.63.4):
- React-callinvoker (= 0.63.5)
- React-jsinspector (= 0.63.5)
- React-jsi (0.63.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-jsi/Default (= 0.63.4)
- React-jsi/Default (0.63.4):
- React-jsi/Default (= 0.63.5)
- React-jsi/Default (0.63.5):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-jsiexecutor (0.63.4):
- React-jsiexecutor (0.63.5):
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsinspector (0.63.4)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- React-jsinspector (0.63.5)
- react-native-background-timer (2.2.0):
- React
- react-native-blob-util (0.13.18):
@@ -243,66 +243,66 @@ PODS:
- React
- react-native-webview (11.16.0):
- React-Core
- React-RCTActionSheet (0.63.4):
- React-Core/RCTActionSheetHeaders (= 0.63.4)
- React-RCTAnimation (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- React-RCTActionSheet (0.63.5):
- React-Core/RCTActionSheetHeaders (= 0.63.5)
- React-RCTAnimation (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTAnimationHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTBlob (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- RCTTypeSafety (= 0.63.5)
- React-Core/RCTAnimationHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-RCTBlob (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- React-Core/RCTBlobHeaders (= 0.63.4)
- React-Core/RCTWebSocket (= 0.63.4)
- React-jsi (= 0.63.4)
- React-RCTNetwork (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTImage (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- React-Core/RCTBlobHeaders (= 0.63.5)
- React-Core/RCTWebSocket (= 0.63.5)
- React-jsi (= 0.63.5)
- React-RCTNetwork (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-RCTImage (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTImageHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- React-RCTNetwork (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTLinking (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- React-Core/RCTLinkingHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTNetwork (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- RCTTypeSafety (= 0.63.5)
- React-Core/RCTImageHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- React-RCTNetwork (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-RCTLinking (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- React-Core/RCTLinkingHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-RCTNetwork (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTNetworkHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTSettings (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- RCTTypeSafety (= 0.63.5)
- React-Core/RCTNetworkHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-RCTSettings (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTSettingsHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTText (0.63.4):
- React-Core/RCTTextHeaders (= 0.63.4)
- React-RCTVibration (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- RCTTypeSafety (= 0.63.5)
- React-Core/RCTSettingsHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- React-RCTText (0.63.5):
- React-Core/RCTTextHeaders (= 0.63.5)
- React-RCTVibration (0.63.5):
- FBReactNativeSpec (= 0.63.5)
- Folly (= 2020.01.13.00)
- React-Core/RCTVibrationHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- ReactCommon/turbomodule/core (0.63.4):
- React-Core/RCTVibrationHeaders (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactCommon/turbomodule/core (= 0.63.5)
- ReactCommon/turbomodule/core (0.63.5):
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-callinvoker (= 0.63.4)
- React-Core (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-callinvoker (= 0.63.5)
- React-Core (= 0.63.5)
- React-cxxreact (= 0.63.5)
- React-jsi (= 0.63.5)
- ReactNativeAudioToolkit (2.0.3):
- React
- ReactNativeNavigation (7.27.1):
@@ -637,25 +637,25 @@ SPEC CHECKSUMS:
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
FBLazyVector: 352a8ca9bbc8e2f097d680747a8c97ecef12d469
FBReactNativeSpec: 7dfb84f624136a45727c813ed21d130cd3e61beb
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 997518ea2aa2d8cd5df9797b641b758d52ecf2bc
glog: 36ce0530c6d2c3a5a4326885ef4069564887a1db
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
Permission-Microphone: 0ffabc3fe1c75cfb260525ee3f529383c9f4368c
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
React-callinvoker: c3f44dd3cb195b6aa46621fff95ded79d59043fe
React-Core: d3b2a1ac9a2c13c3bcde712d9281fc1c8a5b315b
React-CoreModules: 0581ff36cb797da0943d424f69e7098e43e9be60
React-cxxreact: c1480d4fda5720086c90df537ee7d285d4c57ac3
React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
RCTRequired: 5520387431beaa5f32aa8726bf746cd5353119fe
RCTTypeSafety: bc90d6e287fa427c50ed770922bac30faf0bbfa3
React: 83a7f231f462b09260a53c5c51005e7659c66890
React-callinvoker: 1c3fdb5562c792212e149637b8a167516bb4b58e
React-Core: 8baca8644a516e772c77e3923697cfe2b58c1606
React-CoreModules: 200c931e17b332024c2e9d878f67b87c00c2c83b
React-cxxreact: 9096ebaeebf6a1475a14448fa8bfc380c13d7882
React-jsi: 7d908b17758178b076a05a254523f1a4227b53d2
React-jsiexecutor: e06a32e42affb2bd89e4c8369349b5fcf787710c
React-jsinspector: fdbc08866b34ae8e1b788ea1cbd9f9d1ca2aa3d6
react-native-background-timer: 1f7d560647b40e6a60b01c452ba29c54bf581fc4
react-native-blob-util: 600972b1782380a5a7d5db61a3817ea32349dae9
react-native-blur: 4568dd93d1d82748c180df8beb2d929c97b13b47
@@ -673,16 +673,16 @@ SPEC CHECKSUMS:
react-native-status: 21f75d492fd311dc111303da38a7a2b23a8a8466
react-native-status-keycard: f60ca57d789aad6875c64ece81ab06ef0609e0d3
react-native-webview: 28a8636d97ee641f2ee8f20492d7a6c269c1d703
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0
React-RCTImage: c1b1f2d3f43a4a528c8946d6092384b5c880d2f0
React-RCTLinking: 35ae4ab9dc0410d1fcbdce4d7623194a27214fb2
React-RCTNetwork: 29ec2696f8d8cfff7331fac83d3e893c95ef43ae
React-RCTSettings: 60f0691bba2074ef394f95d4c2265ec284e0a46a
React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
React-RCTActionSheet: e911b99f0d6fa7711ffc2f62d236b12a32771835
React-RCTAnimation: ad8b853170a059faf31d6add34f67d22391bbe01
React-RCTBlob: 134c7270b6672c9c05383b2e0f7f044ba39d7dda
React-RCTImage: c5c74ba8850a193d73aef8efb8fcbb4f9cad7653
React-RCTLinking: 12468e952704555c8cb4e3de94c7b5a266811326
React-RCTNetwork: e9cfaeb9f3657ae91f895e798734141db6e1af5b
React-RCTSettings: 9a09419bd5e8494f6e146e2c9f5c8e2c6e90ed58
React-RCTText: 393f059d7ec02c733da57240694201e734f0dc84
React-RCTVibration: 3e83f53610d63d3c1fc4db303305e934e73047cc
ReactCommon: b9ff54b6dd22ba4a776eda22d7f83ec27544ca35
ReactNativeAudioToolkit: de9610f323e855ac6574be8c99621f3d57c5df06
ReactNativeNavigation: 94979dd1572a3f093fc85d4599360530a1bed8c8
RNCAsyncStorage: b2489b49e38c85e10ed45a888d13a2a4c7b32ea1
@@ -708,7 +708,7 @@ SPEC CHECKSUMS:
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
Yoga: 0276e9f20976c8568e107cfc1163a8629051adc0
PODFILE CHECKSUM: a1de9468266e7f0b5273acea713782ab759690f1
@@ -0,0 +1,78 @@
package im.status.ethereum.module;
import android.view.ActionMode;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.views.textinput.ReactEditText;
import javax.annotation.Nonnull;
class RNSelectableTextInputModule extends ReactContextBaseJavaModule {
private ActionMode lastActionMode;
public RNSelectableTextInputModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Nonnull
@Override
public String getName() {
return "RNSelectableTextInputManager";
}
@ReactMethod
public void setupMenuItems(final Integer selectableTextViewReactTag, final Integer textInputReactTag) {
ReactApplicationContext reactContext = this.getReactApplicationContext();
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
public void execute (NativeViewHierarchyManager nvhm) {
RNSelectableTextInputViewManager rnSelectableTextManager = (RNSelectableTextInputViewManager) nvhm.resolveViewManager(selectableTextViewReactTag);
ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag);
rnSelectableTextManager.registerSelectionListener(reactTextView);
}
});
}
@ReactMethod
public void startActionMode(final Integer textInputReactTag) {
ReactApplicationContext reactContext = this.getReactApplicationContext();
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
public void execute (NativeViewHierarchyManager nvhm) {
ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag);
lastActionMode = reactTextView.startActionMode(reactTextView.getCustomSelectionActionModeCallback(), ActionMode.TYPE_FLOATING);
}
});
}
@ReactMethod
public void hideLastActionMode(){
ReactApplicationContext reactContext = this.getReactApplicationContext();
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
public void execute (NativeViewHierarchyManager nvhm) {
if(lastActionMode!=null){
lastActionMode.finish();
lastActionMode = null;
}
}
});
}
@ReactMethod
public void setSelection(final Integer textInputReactTag, final Integer start, final Integer end){
ReactApplicationContext reactContext = this.getReactApplicationContext();
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
public void execute (NativeViewHierarchyManager nvhm) {
ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag);
reactTextView.setSelection(start, end);
}
});
}
}
@@ -0,0 +1,102 @@
package im.status.ethereum.module;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.Menu;
import android.view.MenuItem;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.views.textinput.ReactEditText;
import com.facebook.react.views.view.ReactViewGroup;
import com.facebook.react.views.view.ReactViewManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RNSelectableTextInputViewManager extends ReactViewManager {
public static final String REACT_CLASS = "RNSelectableTextInput";
private String[] _menuItems = new String[0];
@Override
public String getName() {
return REACT_CLASS;
}
@Override
public ReactViewGroup createViewInstance(ThemedReactContext context) {
return new ReactViewGroup(context);
}
@ReactProp(name = "menuItems")
public void setMenuItems(ReactViewGroup reactViewGroup, ReadableArray items) {
if(items != null) {
List<String> result = new ArrayList<String>(items.size());
for (int i = 0; i < items.size(); i++) {
result.add(items.getString(i));
}
this._menuItems = result.toArray(new String[items.size()]);
}
}
public void registerSelectionListener(final ReactEditText view) {
view.setCustomSelectionActionModeCallback(new Callback() {
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
menu.clear();
for (int i = 0; i < _menuItems.length; i++) {
menu.add(0, i, 0, _menuItems[i]);
}
return true;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
int selectionStart = view.getSelectionStart();
int selectionEnd = view.getSelectionEnd();
String selectedText = view.getText().toString().substring(selectionStart, selectionEnd);
// Dispatch event
onSelectNativeEvent(view, item.getItemId(), selectedText, selectionStart, selectionEnd);
mode.finish();
return true;
}
});
}
public void onSelectNativeEvent(ReactEditText view, int eventType, String content, int selectionStart, int selectionEnd) {
WritableMap event = Arguments.createMap();
event.putInt("eventType", eventType);
event.putString("content", content);
event.putInt("selectionStart", selectionStart);
event.putInt("selectionEnd", selectionEnd);
// Dispatch
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(view.getId(), "topSelection", event);
}
@Override
public Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.builder()
.put("topSelection", MapBuilder.of("registrationName","onSelection"))
.build();
}
}
@@ -7,6 +7,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -29,12 +30,15 @@ public class StatusPackage implements ReactPackage {
List<NativeModule> modules = new ArrayList<>();
modules.add(new StatusModule(reactContext, this.rootedDevice));
modules.add(new RNSelectableTextInputModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
return Arrays.<ViewManager>asList(
new RNSelectableTextInputViewManager()
);
}
}
+2 -2
View File
@@ -45,8 +45,8 @@ in stdenv.mkDerivation rec {
filter = lib.mkFilter {
root = path;
include = [
"package.json" "yarn.lock" "metro.config.js" ".babelrc"
"resources/.*" "translations/.*" "src/js/worklet_factory.js"
"package.json" "yarn.lock" "metro.config.js" "babel.config.js"
"resources/.*" "translations/.*" "src/js/.*"
"modules/react-native-status/android.*" "android/.*"
envFileName "VERSION" "status-go-version.json" "react-native.config.js"
];
+10 -1
View File
@@ -74,7 +74,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",
"react-syntax-highlighter": "^15.5.0",
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#refs/tags/v0.4.3",
"rn-emoji-keyboard": "0.7.0",
"tdigest": "^0.1.1"
},
"devDependencies": {
@@ -82,12 +82,21 @@
"@babel/helper-builder-react-jsx": "7.0.0",
"@babel/plugin-transform-block-scoping": "7.0.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "^7.18.6",
"@babel/register": "7.0.0",
"@jest/globals": "^25.1.0",
"@mapbox/node-pre-gyp": "^1.0.9",
"@testing-library/jest-native": "^5.0.0",
"@testing-library/react-native": "^11.2.0",
"@types/jest": "^28.1.6",
"detox": "^19.9.1",
"jest": "^25.1.0",
"jest-circus": "^26.0.0",
"jest-image-snapshot": "^5.1.0",
"nodemon": "^2.0.16",
"nyc": "^14.1.1",
"process": "0.11.10",
"react-test-renderer": "16.13.1",
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#refs/tags/v2.0.2-status",
"shadow-cljs": "2.11.16"
},
+161 -127
View File
@@ -1,131 +1,165 @@
{
"fleets": {
"eth.prod": {
"boot": {
"boot-01.ac-cn-hongkong-c.eth.prod": "enode://6e6554fb3034b211398fcd0f0082cbb6bd13619e1a7e76ba66e1809aaa0c5f1ac53c9ae79cf2fd4a7bacb10d12010899b370c75fed19b991d9c0cdd02891abad@47.75.99.169:443",
"boot-01.do-ams3.eth.prod": "enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@178.128.138.128:443",
"boot-01.gc-us-central1-a.eth.prod": "enode://32ff6d88760b0947a3dee54ceff4d8d7f0b4c023c6dad34568615fcae89e26cc2753f28f12485a4116c977be937a72665116596265aa0736b53d46b27446296a@34.70.75.208:443",
"boot-02.ac-cn-hongkong-c.eth.prod": "enode://23d0740b11919358625d79d4cac7d50a34d79e9c69e16831c5c70573757a1f5d7d884510bc595d7ee4da3c1508adf87bbc9e9260d804ef03f8c1e37f2fb2fc69@47.52.106.107:443",
"boot-02.do-ams3.eth.prod": "enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@178.128.140.188:443",
"boot-02.gc-us-central1-a.eth.prod": "enode://5405c509df683c962e7c9470b251bb679dd6978f82d5b469f1f6c64d11d50fbd5dd9f7801c6ad51f3b20a5f6c7ffe248cc9ab223f8bcbaeaf14bb1c0ef295fd0@35.223.215.156:443"
},
"mail": {
"mail-01.ac-cn-hongkong-c.eth.prod": "enode://606ae04a71e5db868a722c77a21c8244ae38f1bd6e81687cc6cfe88a3063fa1c245692232f64f45bd5408fed5133eab8ed78049332b04f9c110eac7f71c1b429@47.75.247.214:443",
"mail-01.do-ams3.eth.prod": "enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@178.128.142.54:443",
"mail-01.gc-us-central1-a.eth.prod": "enode://ee2b53b0ace9692167a410514bca3024695dbf0e1a68e1dff9716da620efb195f04a4b9e873fb9b74ac84de801106c465b8e2b6c4f0d93b8749d1578bfcaf03e@104.197.238.144:443",
"mail-02.ac-cn-hongkong-c.eth.prod": "enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443",
"mail-02.do-ams3.eth.prod": "enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@178.128.142.26:443",
"mail-02.gc-us-central1-a.eth.prod": "enode://30211cbd81c25f07b03a0196d56e6ce4604bb13db773ff1c0ea2253547fafd6c06eae6ad3533e2ba39d59564cfbdbb5e2ce7c137a5ebb85e99dcfc7a75f99f55@23.236.58.92:443",
"mail-03.ac-cn-hongkong-c.eth.prod": "enode://e85f1d4209f2f99da801af18db8716e584a28ad0bdc47fbdcd8f26af74dbd97fc279144680553ec7cd9092afe683ddea1e0f9fc571ebcb4b1d857c03a088853d@47.244.129.82:443",
"mail-03.do-ams3.eth.prod": "enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@178.128.142.94:443",
"mail-03.gc-us-central1-a.eth.prod": "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443"
},
"rendezvous": {
"boot-01.ac-cn-hongkong-c.eth.prod": "/ip4/47.75.99.169/tcp/30703/ethv4/16Uiu2HAmV8Hq9e3zm9TMVP4zrVHo3BjqW5D6bDVV6VQntQd687e4",
"boot-01.do-ams3.eth.prod": "/ip4/178.128.138.128/tcp/30703/ethv4/16Uiu2HAmRHPzF3rQg55PgYPcQkyvPVH9n2hWsYPhUJBZ6kVjJgdV",
"boot-01.gc-us-central1-a.eth.prod": "/ip4/34.70.75.208/tcp/30703/ethv4/16Uiu2HAm6ZsERLx2BwVD2UM9SVPnnMU6NBycG8XPtu8qKys5awsU",
"boot-02.ac-cn-hongkong-c.eth.prod": "/ip4/47.52.106.107/tcp/30703/ethv4/16Uiu2HAmEHiptiDDd9gqNY8oQqo8hHUWMHJzfwt5aLRdD6W2zcXR",
"boot-02.do-ams3.eth.prod": "/ip4/178.128.140.188/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf",
"boot-02.gc-us-central1-a.eth.prod": "/ip4/35.223.215.156/tcp/30703/ethv4/16Uiu2HAmQEUFE2YaJohavWtHxPTEFv3sEGJtDqvtGEv78DFoEWQF"
},
"whisper": {
"node-01.ac-cn-hongkong-c.eth.prod": "enode://b957e51f41e4abab8382e1ea7229e88c6e18f34672694c6eae389eac22dab8655622bbd4a08192c321416b9becffaab11c8e2b7a5d0813b922aa128b82990dab@47.75.222.178:443",
"node-01.do-ams3.eth.prod": "enode://66ba15600cda86009689354c3a77bdf1a97f4f4fb3ab50ffe34dbc904fac561040496828397be18d9744c75881ffc6ac53729ddbd2cdbdadc5f45c400e2622f7@178.128.141.87:443",
"node-01.gc-us-central1-a.eth.prod": "enode://182ed5d658d1a1a4382c9e9f7c9e5d8d9fec9db4c71ae346b9e23e1a589116aeffb3342299bdd00e0ab98dbf804f7b2d8ae564ed18da9f45650b444aed79d509@34.68.132.118:443",
"node-02.ac-cn-hongkong-c.eth.prod": "enode://8bebe73ddf7cf09e77602c7d04c93a73f455b51f24ae0d572917a4792f1dec0bb4c562759b8830cc3615a658d38c1a4a38597a1d7ae3ba35111479fc42d65dec@47.75.85.212:443",
"node-02.do-ams3.eth.prod": "enode://4ea35352702027984a13274f241a56a47854a7fd4b3ba674a596cff917d3c825506431cf149f9f2312a293bb7c2b1cca55db742027090916d01529fe0729643b@134.209.136.79:443",
"node-02.gc-us-central1-a.eth.prod": "enode://fbeddac99d396b91d59f2c63a3cb5fc7e0f8a9f7ce6fe5f2eed5e787a0154161b7173a6a73124a4275ef338b8966dc70a611e9ae2192f0f2340395661fad81c0@34.67.230.193:443",
"node-03.ac-cn-hongkong-c.eth.prod": "enode://ac3948b2c0786ada7d17b80cf869cf59b1909ea3accd45944aae35bf864cc069126da8b82dfef4ddf23f1d6d6b44b1565c4cf81c8b98022253c6aea1a89d3ce2@47.75.88.12:443",
"node-03.do-ams3.eth.prod": "enode://ce559a37a9c344d7109bd4907802dd690008381d51f658c43056ec36ac043338bd92f1ac6043e645b64953b06f27202d679756a9c7cf62fdefa01b2e6ac5098e@134.209.136.123:443",
"node-03.gc-us-central1-a.eth.prod": "enode://c07aa0deea3b7056c5d45a85bca42f0d8d3b1404eeb9577610f386e0a4744a0e7b2845ae328efc4aa4b28075af838b59b5b3985bffddeec0090b3b7669abc1f3@35.226.92.155:443",
"node-04.ac-cn-hongkong-c.eth.prod": "enode://385579fc5b14e04d5b04af7eee835d426d3d40ccf11f99dbd95340405f37cf3bbbf830b3eb8f70924be0c2909790120682c9c3e791646e2d5413e7801545d353@47.244.221.249:443",
"node-04.do-ams3.eth.prod": "enode://4e0a8db9b73403c9339a2077e911851750fc955db1fc1e09f81a4a56725946884dd5e4d11258eac961f9078a393c45bcab78dd0e3bc74e37ce773b3471d2e29c@134.209.136.101:443",
"node-04.gc-us-central1-a.eth.prod": "enode://0624b4a90063923c5cc27d12624b6a49a86dfb3623fcb106801217fdbab95f7617b83fa2468b9ae3de593ff6c1cf556ccf9bc705bfae9cb4625999765127b423@35.222.158.246:443",
"node-05.ac-cn-hongkong-c.eth.prod": "enode://b77bffc29e2592f30180311dd81204ab845e5f78953b5ba0587c6631be9c0862963dea5eb64c90617cf0efd75308e22a42e30bc4eb3cd1bbddbd1da38ff6483e@47.75.10.177:443",
"node-05.do-ams3.eth.prod": "enode://a8bddfa24e1e92a82609b390766faa56cf7a5eef85b22a2b51e79b333c8aaeec84f7b4267e432edd1cf45b63a3ad0fc7d6c3a16f046aa6bc07ebe50e80b63b8c@178.128.141.249:443",
"node-05.gc-us-central1-a.eth.prod": "enode://a5fe9c82ad1ffb16ae60cb5d4ffe746b9de4c5fbf20911992b7dd651b1c08ba17dd2c0b27ee6b03162c52d92f219961cc3eb14286aca8a90b75cf425826c3bd8@104.154.230.58:443",
"node-06.ac-cn-hongkong-c.eth.prod": "enode://cf5f7a7e64e3b306d1bc16073fba45be3344cb6695b0b616ccc2da66ea35b9f35b3b231c6cf335fdfaba523519659a440752fc2e061d1e5bc4ef33864aac2f19@47.75.221.196:443",
"node-06.do-ams3.eth.prod": "enode://887cbd92d95afc2c5f1e227356314a53d3d18855880ac0509e0c0870362aee03939d4074e6ad31365915af41d34320b5094bfcc12a67c381788cd7298d06c875@178.128.141.0:443",
"node-06.gc-us-central1-a.eth.prod": "enode://282e009967f9f132a5c2dd366a76319f0d22d60d0c51f7e99795a1e40f213c2705a2c10e4cc6f3890319f59da1a535b8835ed9b9c4b57c3aad342bf312fd7379@35.223.240.17:443",
"node-07.ac-cn-hongkong-c.eth.prod": "enode://13d63a1f85ccdcbd2fb6861b9bd9d03f94bdba973608951f7c36e5df5114c91de2b8194d71288f24bfd17908c48468e89dd8f0fb8ccc2b2dedae84acdf65f62a@47.244.210.80:443",
"node-07.do-ams3.eth.prod": "enode://2b01955d7e11e29dce07343b456e4e96c081760022d1652b1c4b641eaf320e3747871870fa682e9e9cfb85b819ce94ed2fee1ac458904d54fd0b97d33ba2c4a4@134.209.136.112:443",
"node-07.gc-us-central1-a.eth.prod": "enode://b706a60572634760f18a27dd407b2b3582f7e065110dae10e3998498f1ae3f29ba04db198460d83ed6d2bfb254bb06b29aab3c91415d75d3b869cd0037f3853c@35.239.5.162:443",
"node-08.ac-cn-hongkong-c.eth.prod": "enode://32915c8841faaef21a6b75ab6ed7c2b6f0790eb177ad0f4ea6d731bacc19b938624d220d937ebd95e0f6596b7232bbb672905ee12601747a12ee71a15bfdf31c@47.75.59.11:443",
"node-08.do-ams3.eth.prod": "enode://0d9d65fcd5592df33ed4507ce862b9c748b6dbd1ea3a1deb94e3750052760b4850aa527265bbaf357021d64d5cc53c02b410458e732fafc5b53f257944247760@178.128.141.42:443",
"node-08.gc-us-central1-a.eth.prod": "enode://e87f1d8093d304c3a9d6f1165b85d6b374f1c0cc907d39c0879eb67f0a39d779be7a85cbd52920b6f53a94da43099c58837034afa6a7be4b099bfcd79ad13999@35.238.106.101:443"
}
},
"eth.staging": {
"boot": {
"boot-01.ac-cn-hongkong-c.eth.staging": "enode://630b0342ca4e9552f50714b6c8e28d6955bc0fd14e7950f93bc3b2b8cc8c1f3b6d103df66f51a13d773b5db0f130661fb5c7b8fa21c48890c64c79b41a56a490@47.91.229.44:443",
"boot-01.do-ams3.eth.staging": "enode://f79fb3919f72ca560ad0434dcc387abfe41e0666201ebdada8ede0462454a13deb05cda15f287d2c4bd85da81f0eb25d0a486bbbc8df427b971ac51533bd00fe@174.138.107.239:443",
"boot-01.gc-us-central1-a.eth.staging": "enode://10a78c17929a7019ef4aa2249d7302f76ae8a06f40b2dc88b7b31ebff4a623fbb44b4a627acba296c1ced3775d91fbe18463c15097a6a36fdb2c804ff3fc5b35@35.238.97.234:443"
},
"mail": {
"mail-01.ac-cn-hongkong-c.eth.staging": "enode://b74859176c9751d314aeeffc26ec9f866a412752e7ddec91b19018a18e7cca8d637cfe2cedcb972f8eb64d816fbd5b4e89c7e8c7fd7df8a1329fa43db80b0bfe@47.52.90.156:443",
"mail-01.do-ams3.eth.staging": "enode://69f72baa7f1722d111a8c9c68c39a31430e9d567695f6108f31ccb6cd8f0adff4991e7fdca8fa770e75bc8a511a87d24690cbc80e008175f40c157d6f6788d48@206.189.240.16:443",
"mail-01.gc-us-central1-a.eth.staging": "enode://e4fc10c1f65c8aed83ac26bc1bfb21a45cc1a8550a58077c8d2de2a0e0cd18e40fd40f7e6f7d02dc6cd06982b014ce88d6e468725ffe2c138e958788d0002a7f@35.239.193.41:443"
},
"rendezvous": {
"boot-01.ac-cn-hongkong-c.eth.staging": "/ip4/47.91.229.44/tcp/30703/ethv4/16Uiu2HAmRnt2Eyoknh3auxh4fJwkRgqkH1gqrWGes8Pk1k3MV4xu",
"boot-01.do-ams3.eth.staging": "/ip4/174.138.107.239/tcp/30703/ethv4/16Uiu2HAm8UZXUHEPZrpJbcQ3yVFH6UtKrwsG6jH4ai72PsbLfVFb",
"boot-01.gc-us-central1-a.eth.staging": "/ip4/35.238.97.234/tcp/30703/ethv4/16Uiu2HAm6G9sDMkrB4Xa5EH3Zx2dysCxFgBTSRzghic3Z9tRFRNE"
},
"whisper": {
"node-01.ac-cn-hongkong-c.eth.staging": "enode://088cf5a93c576fae52f6f075178467b8ff98bacf72f59e88efb16dfba5b30f80a4db78f8e3cb3d87f2f6521746ef4a8768465ef2896c6af24fd77a425e95b6dd@47.52.226.137:443",
"node-01.do-ams3.eth.staging": "enode://914c0b30f27bab30c1dfd31dad7652a46fda9370542aee1b062498b1345ee0913614b8b9e3e84622e84a7203c5858ae1d9819f63aece13ee668e4f6668063989@167.99.19.148:443",
"node-01.gc-us-central1-a.eth.staging": "enode://d3878441652f010326889f28360e69f2d09d06540f934fada0e17b374ce5319de64279aba3c44a5bf807d9967c6d705b3b4c6b03fa70763240e2ee6af01a539e@35.192.0.86:443"
}
},
"eth.test": {
"boot": {
"boot-01.ac-cn-hongkong-c.eth.test": "enode://daae2e72820e86e942fa2a8aa7d6e9954d4043a753483d8bd338e16be82cf962392d5c0e1ae57c3d793c3d3dddd8fd58339262e4234dc966f953cd73b535f5fa@47.52.188.149:443",
"boot-01.do-ams3.eth.test": "enode://9e0988575eb7717c25dea72fd11c7b37767dc09c1a7686f7c2ec577d308d24b377ceb675de4317474a1a870e47882732967f4fa785b02ba95d669b31d464dec0@206.189.243.164:443",
"boot-01.gc-us-central1-a.eth.test": "enode://c1e5018887c863d64e431b69bf617561087825430e4401733f5ba77c70db14236df381fefb0ebe1ac42294b9e261bbe233dbdb83e32c586c66ae26c8de70cb4c@35.188.168.137:443"
},
"mail": {
"mail-01.ac-cn-hongkong-c.eth.test": "enode://619dbb5dda12e85bf0eb5db40fb3de625609043242737c0e975f7dfd659d85dc6d9a84f9461a728c5ab68c072fed38ca6a53917ca24b8e93cc27bdef3a1e79ac@47.52.188.196:443",
"mail-01.do-ams3.eth.test": "enode://e4865fe6c2a9c1a563a6447990d8e9ce672644ae3e08277ce38ec1f1b690eef6320c07a5d60c3b629f5d4494f93d6b86a745a0bf64ab295bbf6579017adc6ed8@206.189.243.161:443",
"mail-01.gc-us-central1-a.eth.test": "enode://707e57453acd3e488c44b9d0e17975371e2f8fb67525eae5baca9b9c8e06c86cde7c794a6c2e36203bf9f56cae8b0e50f3b33c4c2b694a7baeea1754464ce4e3@35.192.229.172:443"
},
"rendezvous": {
"boot-01.ac-cn-hongkong-c.eth.test": "/ip4/47.52.188.149/tcp/30703/ethv4/16Uiu2HAm9Vatqr4GfVCqnyeaPtCF3q8fz8kDDUgqXVfFG7ZfSA7w",
"boot-01.do-ams3.eth.test": "/ip4/206.189.243.164/tcp/30703/ethv4/16Uiu2HAmBCh5bgYr6V3fDuLqUzvtSAsFTQJCQ3TVHT8ta8bTu2Jm",
"boot-01.gc-us-central1-a.eth.test": "/ip4/35.188.168.137/tcp/30703/ethv4/16Uiu2HAm3MUqtGjmetyZ9L4SN2R8oHDWvACUcec25LjtDD5euiRH"
},
"whisper": {
"node-01.ac-cn-hongkong-c.eth.test": "enode://ad38f94030a846cc7005b7a1f3b6b01bf4ef59d34e8d3d6f4d12df23d14ba8656702a435d34cf4df3b412c0c1923df5adcce8461321a0d8ffb9435b26e572c2a@47.52.255.194:443",
"node-01.do-ams3.eth.test": "enode://1d193635e015918fb85bbaf774863d12f65d70c6977506187ef04420d74ec06c9e8f0dcb57ea042f85df87433dab17a1260ed8dde1bdf9d6d5d2de4b7bf8e993@206.189.243.163:443",
"node-01.gc-us-central1-a.eth.test": "enode://f593a27731bc0f8eb088e2d39222c2d59dfb9bf0b3950d7a828d51e8ab9e08fffbd9916a82fd993c1a080c57c2bd70ed6c36f489a969de697aff93088dbee1a9@35.194.31.108:443"
}
},
"wakuv2.prod": {
"waku": {
"node-01.ac-cn-hongkong-c.wakuv2.prod": "/ip4/8.210.222.231/tcp/30303/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr24iDQpSN5Qa992BCjjwgrD",
"node-01.do-ams3.wakuv2.prod": "/ip4/188.166.135.145/tcp/30303/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e",
"node-01.gc-us-central1-a.wakuv2.prod": "/ip4/34.121.100.108/tcp/30303/p2p/16Uiu2HAmVkKntsECaYfefR1V2yCR79CegLATuTPE6B9TxgxBiiiA"
},
"waku-websocket": {
"node-01.ac-cn-hongkong-c.wakuv2.prod": "/dns4/node-01.ac-cn-hongkong-c.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr24iDQpSN5Qa992BCjjwgrD",
"node-01.do-ams3.wakuv2.prod": "/dns4/node-01.do-ams3.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e",
"node-01.gc-us-central1-a.wakuv2.prod": "/dns4/node-01.gc-us-central1-a.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmVkKntsECaYfefR1V2yCR79CegLATuTPE6B9TxgxBiiiA"
}
},
"wakuv2.test": {
"waku": {
"node-01.ac-cn-hongkong-c.wakuv2.test": "/ip4/47.242.210.73/tcp/30303/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
"node-01.do-ams3.wakuv2.test": "/ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
"node-01.gc-us-central1-a.wakuv2.test": "/ip4/104.154.239.128/tcp/30303/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS"
},
"waku-websocket": {
"node-01.ac-cn-hongkong-c.wakuv2.test": "/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
"node-01.do-ams3.wakuv2.test": "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
"node-01.gc-us-central1-a.wakuv2.test": "/dns4/node-01.gc-us-central1-a.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS"
}
}
"fleets": {
"eth.prod": {
"boot": {
"boot-01.ac-cn-hongkong-c.eth.prod": "enode://6e6554fb3034b211398fcd0f0082cbb6bd13619e1a7e76ba66e1809aaa0c5f1ac53c9ae79cf2fd4a7bacb10d12010899b370c75fed19b991d9c0cdd02891abad@47.75.99.169:443",
"boot-01.do-ams3.eth.prod": "enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@178.128.138.128:443",
"boot-01.gc-us-central1-a.eth.prod": "enode://32ff6d88760b0947a3dee54ceff4d8d7f0b4c023c6dad34568615fcae89e26cc2753f28f12485a4116c977be937a72665116596265aa0736b53d46b27446296a@34.70.75.208:443",
"boot-02.ac-cn-hongkong-c.eth.prod": "enode://23d0740b11919358625d79d4cac7d50a34d79e9c69e16831c5c70573757a1f5d7d884510bc595d7ee4da3c1508adf87bbc9e9260d804ef03f8c1e37f2fb2fc69@47.52.106.107:443",
"boot-02.do-ams3.eth.prod": "enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@178.128.140.188:443",
"boot-02.gc-us-central1-a.eth.prod": "enode://5405c509df683c962e7c9470b251bb679dd6978f82d5b469f1f6c64d11d50fbd5dd9f7801c6ad51f3b20a5f6c7ffe248cc9ab223f8bcbaeaf14bb1c0ef295fd0@35.223.215.156:443"
},
"mail": {
"mail-01.ac-cn-hongkong-c.eth.prod": "enode://606ae04a71e5db868a722c77a21c8244ae38f1bd6e81687cc6cfe88a3063fa1c245692232f64f45bd5408fed5133eab8ed78049332b04f9c110eac7f71c1b429@47.75.247.214:443",
"mail-01.do-ams3.eth.prod": "enode://c42f368a23fa98ee546fd247220759062323249ef657d26d357a777443aec04db1b29a3a22ef3e7c548e18493ddaf51a31b0aed6079bd6ebe5ae838fcfaf3a49@178.128.142.54:443",
"mail-01.gc-us-central1-a.eth.prod": "enode://ee2b53b0ace9692167a410514bca3024695dbf0e1a68e1dff9716da620efb195f04a4b9e873fb9b74ac84de801106c465b8e2b6c4f0d93b8749d1578bfcaf03e@104.197.238.144:443",
"mail-02.ac-cn-hongkong-c.eth.prod": "enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443",
"mail-02.do-ams3.eth.prod": "enode://7aa648d6e855950b2e3d3bf220c496e0cae4adfddef3e1e6062e6b177aec93bc6cdcf1282cb40d1656932ebfdd565729da440368d7c4da7dbd4d004b1ac02bf8@178.128.142.26:443",
"mail-02.gc-us-central1-a.eth.prod": "enode://30211cbd81c25f07b03a0196d56e6ce4604bb13db773ff1c0ea2253547fafd6c06eae6ad3533e2ba39d59564cfbdbb5e2ce7c137a5ebb85e99dcfc7a75f99f55@23.236.58.92:443",
"mail-03.ac-cn-hongkong-c.eth.prod": "enode://e85f1d4209f2f99da801af18db8716e584a28ad0bdc47fbdcd8f26af74dbd97fc279144680553ec7cd9092afe683ddea1e0f9fc571ebcb4b1d857c03a088853d@47.244.129.82:443",
"mail-03.do-ams3.eth.prod": "enode://8a64b3c349a2e0ef4a32ea49609ed6eb3364be1110253c20adc17a3cebbc39a219e5d3e13b151c0eee5d8e0f9a8ba2cd026014e67b41a4ab7d1d5dd67ca27427@178.128.142.94:443",
"mail-03.gc-us-central1-a.eth.prod": "enode://44160e22e8b42bd32a06c1532165fa9e096eebedd7fa6d6e5f8bbef0440bc4a4591fe3651be68193a7ec029021cdb496cfe1d7f9f1dc69eb99226e6f39a7a5d4@35.225.221.245:443"
},
"rendezvous": {
"boot-01.ac-cn-hongkong-c.eth.prod": "/ip4/47.75.99.169/tcp/30703/ethv4/16Uiu2HAmV8Hq9e3zm9TMVP4zrVHo3BjqW5D6bDVV6VQntQd687e4",
"boot-01.do-ams3.eth.prod": "/ip4/178.128.138.128/tcp/30703/ethv4/16Uiu2HAmRHPzF3rQg55PgYPcQkyvPVH9n2hWsYPhUJBZ6kVjJgdV",
"boot-01.gc-us-central1-a.eth.prod": "/ip4/34.70.75.208/tcp/30703/ethv4/16Uiu2HAm6ZsERLx2BwVD2UM9SVPnnMU6NBycG8XPtu8qKys5awsU",
"boot-02.ac-cn-hongkong-c.eth.prod": "/ip4/47.52.106.107/tcp/30703/ethv4/16Uiu2HAmEHiptiDDd9gqNY8oQqo8hHUWMHJzfwt5aLRdD6W2zcXR",
"boot-02.do-ams3.eth.prod": "/ip4/178.128.140.188/tcp/30703/ethv4/16Uiu2HAmLqTXuY4Sb6G28HNooaFUXUKzpzKXCcgyJxgaEE2i5vnf",
"boot-02.gc-us-central1-a.eth.prod": "/ip4/35.223.215.156/tcp/30703/ethv4/16Uiu2HAmQEUFE2YaJohavWtHxPTEFv3sEGJtDqvtGEv78DFoEWQF"
},
"whisper": {
"node-01.ac-cn-hongkong-c.eth.prod": "enode://b957e51f41e4abab8382e1ea7229e88c6e18f34672694c6eae389eac22dab8655622bbd4a08192c321416b9becffaab11c8e2b7a5d0813b922aa128b82990dab@47.75.222.178:443",
"node-01.do-ams3.eth.prod": "enode://66ba15600cda86009689354c3a77bdf1a97f4f4fb3ab50ffe34dbc904fac561040496828397be18d9744c75881ffc6ac53729ddbd2cdbdadc5f45c400e2622f7@178.128.141.87:443",
"node-01.gc-us-central1-a.eth.prod": "enode://182ed5d658d1a1a4382c9e9f7c9e5d8d9fec9db4c71ae346b9e23e1a589116aeffb3342299bdd00e0ab98dbf804f7b2d8ae564ed18da9f45650b444aed79d509@34.68.132.118:443",
"node-02.ac-cn-hongkong-c.eth.prod": "enode://8bebe73ddf7cf09e77602c7d04c93a73f455b51f24ae0d572917a4792f1dec0bb4c562759b8830cc3615a658d38c1a4a38597a1d7ae3ba35111479fc42d65dec@47.75.85.212:443",
"node-02.do-ams3.eth.prod": "enode://4ea35352702027984a13274f241a56a47854a7fd4b3ba674a596cff917d3c825506431cf149f9f2312a293bb7c2b1cca55db742027090916d01529fe0729643b@134.209.136.79:443",
"node-02.gc-us-central1-a.eth.prod": "enode://fbeddac99d396b91d59f2c63a3cb5fc7e0f8a9f7ce6fe5f2eed5e787a0154161b7173a6a73124a4275ef338b8966dc70a611e9ae2192f0f2340395661fad81c0@34.67.230.193:443",
"node-03.ac-cn-hongkong-c.eth.prod": "enode://ac3948b2c0786ada7d17b80cf869cf59b1909ea3accd45944aae35bf864cc069126da8b82dfef4ddf23f1d6d6b44b1565c4cf81c8b98022253c6aea1a89d3ce2@47.75.88.12:443",
"node-03.do-ams3.eth.prod": "enode://ce559a37a9c344d7109bd4907802dd690008381d51f658c43056ec36ac043338bd92f1ac6043e645b64953b06f27202d679756a9c7cf62fdefa01b2e6ac5098e@134.209.136.123:443",
"node-03.gc-us-central1-a.eth.prod": "enode://c07aa0deea3b7056c5d45a85bca42f0d8d3b1404eeb9577610f386e0a4744a0e7b2845ae328efc4aa4b28075af838b59b5b3985bffddeec0090b3b7669abc1f3@35.226.92.155:443",
"node-04.ac-cn-hongkong-c.eth.prod": "enode://385579fc5b14e04d5b04af7eee835d426d3d40ccf11f99dbd95340405f37cf3bbbf830b3eb8f70924be0c2909790120682c9c3e791646e2d5413e7801545d353@47.244.221.249:443",
"node-04.do-ams3.eth.prod": "enode://4e0a8db9b73403c9339a2077e911851750fc955db1fc1e09f81a4a56725946884dd5e4d11258eac961f9078a393c45bcab78dd0e3bc74e37ce773b3471d2e29c@134.209.136.101:443",
"node-04.gc-us-central1-a.eth.prod": "enode://0624b4a90063923c5cc27d12624b6a49a86dfb3623fcb106801217fdbab95f7617b83fa2468b9ae3de593ff6c1cf556ccf9bc705bfae9cb4625999765127b423@35.222.158.246:443",
"node-05.ac-cn-hongkong-c.eth.prod": "enode://b77bffc29e2592f30180311dd81204ab845e5f78953b5ba0587c6631be9c0862963dea5eb64c90617cf0efd75308e22a42e30bc4eb3cd1bbddbd1da38ff6483e@47.75.10.177:443",
"node-05.do-ams3.eth.prod": "enode://a8bddfa24e1e92a82609b390766faa56cf7a5eef85b22a2b51e79b333c8aaeec84f7b4267e432edd1cf45b63a3ad0fc7d6c3a16f046aa6bc07ebe50e80b63b8c@178.128.141.249:443",
"node-05.gc-us-central1-a.eth.prod": "enode://a5fe9c82ad1ffb16ae60cb5d4ffe746b9de4c5fbf20911992b7dd651b1c08ba17dd2c0b27ee6b03162c52d92f219961cc3eb14286aca8a90b75cf425826c3bd8@104.154.230.58:443",
"node-06.ac-cn-hongkong-c.eth.prod": "enode://cf5f7a7e64e3b306d1bc16073fba45be3344cb6695b0b616ccc2da66ea35b9f35b3b231c6cf335fdfaba523519659a440752fc2e061d1e5bc4ef33864aac2f19@47.75.221.196:443",
"node-06.do-ams3.eth.prod": "enode://887cbd92d95afc2c5f1e227356314a53d3d18855880ac0509e0c0870362aee03939d4074e6ad31365915af41d34320b5094bfcc12a67c381788cd7298d06c875@178.128.141.0:443",
"node-06.gc-us-central1-a.eth.prod": "enode://282e009967f9f132a5c2dd366a76319f0d22d60d0c51f7e99795a1e40f213c2705a2c10e4cc6f3890319f59da1a535b8835ed9b9c4b57c3aad342bf312fd7379@35.223.240.17:443",
"node-07.ac-cn-hongkong-c.eth.prod": "enode://13d63a1f85ccdcbd2fb6861b9bd9d03f94bdba973608951f7c36e5df5114c91de2b8194d71288f24bfd17908c48468e89dd8f0fb8ccc2b2dedae84acdf65f62a@47.244.210.80:443",
"node-07.do-ams3.eth.prod": "enode://2b01955d7e11e29dce07343b456e4e96c081760022d1652b1c4b641eaf320e3747871870fa682e9e9cfb85b819ce94ed2fee1ac458904d54fd0b97d33ba2c4a4@134.209.136.112:443",
"node-07.gc-us-central1-a.eth.prod": "enode://b706a60572634760f18a27dd407b2b3582f7e065110dae10e3998498f1ae3f29ba04db198460d83ed6d2bfb254bb06b29aab3c91415d75d3b869cd0037f3853c@35.239.5.162:443",
"node-08.ac-cn-hongkong-c.eth.prod": "enode://32915c8841faaef21a6b75ab6ed7c2b6f0790eb177ad0f4ea6d731bacc19b938624d220d937ebd95e0f6596b7232bbb672905ee12601747a12ee71a15bfdf31c@47.75.59.11:443",
"node-08.do-ams3.eth.prod": "enode://0d9d65fcd5592df33ed4507ce862b9c748b6dbd1ea3a1deb94e3750052760b4850aa527265bbaf357021d64d5cc53c02b410458e732fafc5b53f257944247760@178.128.141.42:443",
"node-08.gc-us-central1-a.eth.prod": "enode://e87f1d8093d304c3a9d6f1165b85d6b374f1c0cc907d39c0879eb67f0a39d779be7a85cbd52920b6f53a94da43099c58837034afa6a7be4b099bfcd79ad13999@35.238.106.101:443"
}
},
"meta": {
"hostname": "node-01.do-ams3.proxy.misc",
"timestamp": "2021-06-07T00:00:09.836740"
"eth.staging": {
"boot": {
"boot-01.ac-cn-hongkong-c.eth.staging": "enode://630b0342ca4e9552f50714b6c8e28d6955bc0fd14e7950f93bc3b2b8cc8c1f3b6d103df66f51a13d773b5db0f130661fb5c7b8fa21c48890c64c79b41a56a490@47.91.229.44:443",
"boot-01.do-ams3.eth.staging": "enode://f79fb3919f72ca560ad0434dcc387abfe41e0666201ebdada8ede0462454a13deb05cda15f287d2c4bd85da81f0eb25d0a486bbbc8df427b971ac51533bd00fe@174.138.107.239:443",
"boot-01.gc-us-central1-a.eth.staging": "enode://10a78c17929a7019ef4aa2249d7302f76ae8a06f40b2dc88b7b31ebff4a623fbb44b4a627acba296c1ced3775d91fbe18463c15097a6a36fdb2c804ff3fc5b35@35.238.97.234:443"
},
"mail": {
"mail-01.ac-cn-hongkong-c.eth.staging": "enode://b74859176c9751d314aeeffc26ec9f866a412752e7ddec91b19018a18e7cca8d637cfe2cedcb972f8eb64d816fbd5b4e89c7e8c7fd7df8a1329fa43db80b0bfe@47.52.90.156:443",
"mail-01.do-ams3.eth.staging": "enode://69f72baa7f1722d111a8c9c68c39a31430e9d567695f6108f31ccb6cd8f0adff4991e7fdca8fa770e75bc8a511a87d24690cbc80e008175f40c157d6f6788d48@206.189.240.16:443",
"mail-01.gc-us-central1-a.eth.staging": "enode://e4fc10c1f65c8aed83ac26bc1bfb21a45cc1a8550a58077c8d2de2a0e0cd18e40fd40f7e6f7d02dc6cd06982b014ce88d6e468725ffe2c138e958788d0002a7f@35.239.193.41:443"
},
"rendezvous": {
"boot-01.ac-cn-hongkong-c.eth.staging": "/ip4/47.91.229.44/tcp/30703/ethv4/16Uiu2HAmRnt2Eyoknh3auxh4fJwkRgqkH1gqrWGes8Pk1k3MV4xu",
"boot-01.do-ams3.eth.staging": "/ip4/174.138.107.239/tcp/30703/ethv4/16Uiu2HAm8UZXUHEPZrpJbcQ3yVFH6UtKrwsG6jH4ai72PsbLfVFb",
"boot-01.gc-us-central1-a.eth.staging": "/ip4/35.238.97.234/tcp/30703/ethv4/16Uiu2HAm6G9sDMkrB4Xa5EH3Zx2dysCxFgBTSRzghic3Z9tRFRNE"
},
"whisper": {
"node-01.ac-cn-hongkong-c.eth.staging": "enode://088cf5a93c576fae52f6f075178467b8ff98bacf72f59e88efb16dfba5b30f80a4db78f8e3cb3d87f2f6521746ef4a8768465ef2896c6af24fd77a425e95b6dd@47.52.226.137:443",
"node-01.do-ams3.eth.staging": "enode://914c0b30f27bab30c1dfd31dad7652a46fda9370542aee1b062498b1345ee0913614b8b9e3e84622e84a7203c5858ae1d9819f63aece13ee668e4f6668063989@167.99.19.148:443",
"node-01.gc-us-central1-a.eth.staging": "enode://d3878441652f010326889f28360e69f2d09d06540f934fada0e17b374ce5319de64279aba3c44a5bf807d9967c6d705b3b4c6b03fa70763240e2ee6af01a539e@35.192.0.86:443"
}
},
"eth.test": {
"boot": {
"boot-01.ac-cn-hongkong-c.eth.test": "enode://daae2e72820e86e942fa2a8aa7d6e9954d4043a753483d8bd338e16be82cf962392d5c0e1ae57c3d793c3d3dddd8fd58339262e4234dc966f953cd73b535f5fa@47.52.188.149:443",
"boot-01.do-ams3.eth.test": "enode://9e0988575eb7717c25dea72fd11c7b37767dc09c1a7686f7c2ec577d308d24b377ceb675de4317474a1a870e47882732967f4fa785b02ba95d669b31d464dec0@206.189.243.164:443",
"boot-01.gc-us-central1-a.eth.test": "enode://c1e5018887c863d64e431b69bf617561087825430e4401733f5ba77c70db14236df381fefb0ebe1ac42294b9e261bbe233dbdb83e32c586c66ae26c8de70cb4c@35.188.168.137:443"
},
"mail": {
"mail-01.ac-cn-hongkong-c.eth.test": "enode://619dbb5dda12e85bf0eb5db40fb3de625609043242737c0e975f7dfd659d85dc6d9a84f9461a728c5ab68c072fed38ca6a53917ca24b8e93cc27bdef3a1e79ac@47.52.188.196:443",
"mail-01.do-ams3.eth.test": "enode://e4865fe6c2a9c1a563a6447990d8e9ce672644ae3e08277ce38ec1f1b690eef6320c07a5d60c3b629f5d4494f93d6b86a745a0bf64ab295bbf6579017adc6ed8@206.189.243.161:443",
"mail-01.gc-us-central1-a.eth.test": "enode://707e57453acd3e488c44b9d0e17975371e2f8fb67525eae5baca9b9c8e06c86cde7c794a6c2e36203bf9f56cae8b0e50f3b33c4c2b694a7baeea1754464ce4e3@35.192.229.172:443"
},
"rendezvous": {
"boot-01.ac-cn-hongkong-c.eth.test": "/ip4/47.52.188.149/tcp/30703/ethv4/16Uiu2HAm9Vatqr4GfVCqnyeaPtCF3q8fz8kDDUgqXVfFG7ZfSA7w",
"boot-01.do-ams3.eth.test": "/ip4/206.189.243.164/tcp/30703/ethv4/16Uiu2HAmBCh5bgYr6V3fDuLqUzvtSAsFTQJCQ3TVHT8ta8bTu2Jm",
"boot-01.gc-us-central1-a.eth.test": "/ip4/35.188.168.137/tcp/30703/ethv4/16Uiu2HAm3MUqtGjmetyZ9L4SN2R8oHDWvACUcec25LjtDD5euiRH"
},
"whisper": {
"node-01.ac-cn-hongkong-c.eth.test": "enode://ad38f94030a846cc7005b7a1f3b6b01bf4ef59d34e8d3d6f4d12df23d14ba8656702a435d34cf4df3b412c0c1923df5adcce8461321a0d8ffb9435b26e572c2a@47.52.255.194:443",
"node-01.do-ams3.eth.test": "enode://1d193635e015918fb85bbaf774863d12f65d70c6977506187ef04420d74ec06c9e8f0dcb57ea042f85df87433dab17a1260ed8dde1bdf9d6d5d2de4b7bf8e993@206.189.243.163:443",
"node-01.gc-us-central1-a.eth.test": "enode://f593a27731bc0f8eb088e2d39222c2d59dfb9bf0b3950d7a828d51e8ab9e08fffbd9916a82fd993c1a080c57c2bd70ed6c36f489a969de697aff93088dbee1a9@35.194.31.108:443"
}
},
"status.prod": {
"waku": {
"node-01.ac-cn-hongkong-c.status.prod": "/dns4/node-01.ac-cn-hongkong-c.status.prod.statusim.net/tcp/30303/p2p/16Uiu2HAkvEZgh3KLwhLwXg95e5ojM8XykJ4Kxi2T7hk22rnA7pJC",
"node-01.do-ams3.status.prod": "/dns4/node-01.do-ams3.status.prod.statusim.net/tcp/30303/p2p/16Uiu2HAm6HZZr7aToTvEBPpiys4UxajCTU97zj5v7RNR2gbniy1D",
"node-01.gc-us-central1-a.status.prod": "/dns4/node-01.gc-us-central1-a.status.prod.statusim.net/tcp/30303/p2p/16Uiu2HAkwBp8T6G77kQXSNMnxgaMky1JeyML5yqoTHRM8dbeCBNb",
"node-02.ac-cn-hongkong-c.status.prod": "/dns4/node-02.ac-cn-hongkong-c.status.prod.statusim.net/tcp/30303/p2p/16Uiu2HAmFy8BrJhCEmCYrUfBdSNkrPw6VHExtv4rRp1DSBnCPgx8",
"node-02.do-ams3.status.prod": "/dns4/node-02.do-ams3.status.prod.statusim.net/tcp/30303/p2p/16Uiu2HAmSve7tR5YZugpskMv2dmJAsMUKmfWYEKRXNUxRaTCnsXV",
"node-02.gc-us-central1-a.status.prod": "/dns4/node-02.gc-us-central1-a.status.prod.statusim.net/tcp/30303/p2p/16Uiu2HAmDQugwDHM3YeUp86iGjrUvbdw3JPRgikC7YoGBsT2ymMg"
},
"waku-websocket": {
"node-01.ac-cn-hongkong-c.status.prod": "/dns4/node-01.ac-cn-hongkong-c.status.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvEZgh3KLwhLwXg95e5ojM8XykJ4Kxi2T7hk22rnA7pJC",
"node-01.do-ams3.status.prod": "/dns4/node-01.do-ams3.status.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAm6HZZr7aToTvEBPpiys4UxajCTU97zj5v7RNR2gbniy1D",
"node-01.gc-us-central1-a.status.prod": "/dns4/node-01.gc-us-central1-a.status.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAkwBp8T6G77kQXSNMnxgaMky1JeyML5yqoTHRM8dbeCBNb",
"node-02.ac-cn-hongkong-c.status.prod": "/dns4/node-02.ac-cn-hongkong-c.status.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmFy8BrJhCEmCYrUfBdSNkrPw6VHExtv4rRp1DSBnCPgx8",
"node-02.do-ams3.status.prod": "/dns4/node-02.do-ams3.status.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmSve7tR5YZugpskMv2dmJAsMUKmfWYEKRXNUxRaTCnsXV",
"node-02.gc-us-central1-a.status.prod": "/dns4/node-02.gc-us-central1-a.status.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmDQugwDHM3YeUp86iGjrUvbdw3JPRgikC7YoGBsT2ymMg"
},
"waku-nodes": ["enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@prod.nodes.status.im"]
},
"status.test": {
"waku": {
"node-01.ac-cn-hongkong-c.status.test": "/dns4/node-01.ac-cn-hongkong-c.status.test.statusim.net/tcp/30303/p2p/16Uiu2HAm2BjXxCp1sYFJQKpLLbPbwd5juxbsYofu3TsS3auvT9Yi",
"node-01.do-ams3.status.test": "/dns4/node-01.do-ams3.status.test.statusim.net/tcp/30303/p2p/16Uiu2HAkukebeXjTQ9QDBeNDWuGfbaSg79wkkhK4vPocLgR6QFDf",
"node-01.gc-us-central1-a.status.test": "/dns4/node-01.gc-us-central1-a.status.test.statusim.net/tcp/30303/p2p/16Uiu2HAmGDX3iAFox93PupVYaHa88kULGqMpJ7AEHGwj3jbMtt76"
},
"waku-websocket": {
"node-01.ac-cn-hongkong-c.status.test": "/dns4/node-01.ac-cn-hongkong-c.status.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAm2BjXxCp1sYFJQKpLLbPbwd5juxbsYofu3TsS3auvT9Yi",
"node-01.do-ams3.status.test": "/dns4/node-01.do-ams3.status.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkukebeXjTQ9QDBeNDWuGfbaSg79wkkhK4vPocLgR6QFDf",
"node-01.gc-us-central1-a.status.test": "/dns4/node-01.gc-us-central1-a.status.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmGDX3iAFox93PupVYaHa88kULGqMpJ7AEHGwj3jbMtt76"
},
"waku-nodes": ["enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.nodes.status.im"]
},
"wakuv2.prod": {
"waku": {
"node-01.ac-cn-hongkong-c.wakuv2.prod": "/ip4/8.210.222.231/tcp/30303/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr24iDQpSN5Qa992BCjjwgrD",
"node-01.do-ams3.wakuv2.prod": "/ip4/188.166.135.145/tcp/30303/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e",
"node-01.gc-us-central1-a.wakuv2.prod": "/ip4/34.121.100.108/tcp/30303/p2p/16Uiu2HAmVkKntsECaYfefR1V2yCR79CegLATuTPE6B9TxgxBiiiA"
},
"waku-websocket": {
"node-01.ac-cn-hongkong-c.wakuv2.prod": "/dns4/node-01.ac-cn-hongkong-c.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr24iDQpSN5Qa992BCjjwgrD",
"node-01.do-ams3.wakuv2.prod": "/dns4/node-01.do-ams3.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e",
"node-01.gc-us-central1-a.wakuv2.prod": "/dns4/node-01.gc-us-central1-a.wakuv2.prod.statusim.net/tcp/443/wss/p2p/16Uiu2HAmVkKntsECaYfefR1V2yCR79CegLATuTPE6B9TxgxBiiiA"
},
"waku-nodes": ["enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@prod.waku.nodes.status.im"]
},
"wakuv2.test": {
"waku": {
"node-01.ac-cn-hongkong-c.wakuv2.test": "/ip4/47.242.210.73/tcp/30303/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
"node-01.do-ams3.wakuv2.test": "/ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
"node-01.gc-us-central1-a.wakuv2.test": "/ip4/104.154.239.128/tcp/30303/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS"
},
"waku-websocket": {
"node-01.ac-cn-hongkong-c.wakuv2.test": "/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
"node-01.do-ams3.wakuv2.test": "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
"node-01.gc-us-central1-a.wakuv2.test": "/dns4/node-01.gc-us-central1-a.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS"
},
"waku-nodes": ["enrtree://AOGECG2SPND25EEFMAJ5WF3KSGJNSGV356DSTL2YVLLZWIV6SAYBM@test.waku.nodes.status.im"]
}
},
"meta": {
"hostname": "node-01.do-ams3.proxy.misc",
"timestamp": "2021-06-07T00:00:09.836740"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

+2 -2
View File
@@ -2,10 +2,10 @@
CHANGES=$(git diff --no-ext-diff --diff-filter=d --cached --unified=0 --no-prefix --minimal --exit-code src/quo src/quo2 | grep '^+' || echo '')
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt)')
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im)')
if test -n "$INVALID_CHANGES"; then
echo "re-frame dispatch/subscribe is not allowed in quo/quo2 components"
echo "re-frame dispatch/subscribe and status-im are not allowed in quo/quo2 components"
echo ''
echo "$INVALID_CHANGES"
exit 1
+16 -8
View File
@@ -64,15 +64,15 @@
{:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {:output-feature-set :es6
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
:warnings-as-errors false
:infer-externs :auto
:static-fns true
:fn-invoke-direct true
:optimizations :advanced
:js-options {:js-provider :closure}}}}
:warnings-as-errors false
:infer-externs :auto
:static-fns true
:fn-invoke-direct true
:optimizations :advanced
:js-options {:js-provider :closure}}}}
;; the tests are ran with node, react-native dependencies are mocked
;; by using node --require override.js, which uses the node-library
;; produced by the target :mocks below and redefines node require
@@ -82,6 +82,7 @@
:output-dir "target/test"
:optimizations :simple
:target :node-test
:ns-regexp "status-im.chat.models-test$"
:main status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl
:ui-driven true
@@ -106,4 +107,11 @@
:output-to "target/mocks/mocks.js"
:output-dir "target/mocks"
:compiler-options {:optimizations :simple
:source-map false}}}}
:source-map false}}
:component-test {:target :npm-module
:entries [quo2.core-spec]
:ns-regexp "-component-spec$"
:output-dir "component-spec"
:compiler-options {:warnings-as-errors false
:static-fns false
:infer-externs true}}}}
+186
View File
@@ -0,0 +1,186 @@
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
// Shell Worklets
// Home Stack States
const CLOSE_WITH_ANIMATION = 0;
const OPEN_WITH_ANIMATION = 1;
const CLOSE_WITHOUT_ANIMATION = 3;
const OPEN_WITHOUT_ANIMATION = 4;
// Derived Values
export function stackOpacity (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? 1 : 0;
}
);
}
export function stackPointer (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? "auto" : "none";
}
);
}
export function bottomTabIconColor (stackId, selectedStackId, homeStackState,
passThrough, selectedTabColor, defaultColor,
passThroughColor) {
return useDerivedValue(
function () {
'worklet'
var homeStackStateValue = homeStackState.value;
if (selectedStackId.value == stackId &&
(homeStackStateValue == OPEN_WITH_ANIMATION ||
homeStackStateValue == OPEN_WITHOUT_ANIMATION)){
return selectedTabColor;
}
else if (passThrough.value){
return passThroughColor;
}
else {
return defaultColor;
}
}
);
}
export function bottomTabsHeight(homeStackState, height, extendedHeight) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case OPEN_WITH_ANIMATION:
return withTiming(extendedHeight, defaultDurationAndEasing);
break;
case CLOSE_WITH_ANIMATION:
return withTiming(height, defaultDurationAndEasing);
break;
case OPEN_WITHOUT_ANIMATION:
return extendedHeight;
break;
case CLOSE_WITHOUT_ANIMATION:
return height;
break;
}
}
)
}
// Home Stack
const shellAnimationTime = 200;
const defaultDurationAndEasing = {
duration: shellAnimationTime,
easing: Easing.bezier(0, 0, 1, 1),
}
export function homeStackOpacity (homeStackState) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case OPEN_WITH_ANIMATION:
return withTiming(1, defaultDurationAndEasing);
break;
case CLOSE_WITH_ANIMATION:
return withTiming(0, defaultDurationAndEasing);
break;
case OPEN_WITHOUT_ANIMATION:
return 1;
break;
case CLOSE_WITHOUT_ANIMATION:
return 0;
break;
}
}
);
}
export function homeStackTop (homeStackState, top) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case OPEN_WITH_ANIMATION:
return withTiming(0, defaultDurationAndEasing);
break;
case CLOSE_WITH_ANIMATION:
return withTiming(top, defaultDurationAndEasing);
break;
case OPEN_WITHOUT_ANIMATION:
return 0;
break;
case CLOSE_WITHOUT_ANIMATION:
return top;
break;
}
}
);
}
export function homeStackLeft (selectedStackId, animateHomeStackLeft, homeStackState, left) {
return useDerivedValue(
function () {
'worklet'
if (animateHomeStackLeft.value) {
var leftValue = left[selectedStackId.value];
switch (homeStackState.value) {
case OPEN_WITH_ANIMATION:
return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, defaultDurationAndEasing))
break;
case CLOSE_WITH_ANIMATION:
return withTiming(leftValue, defaultDurationAndEasing);
break;
case OPEN_WITHOUT_ANIMATION:
return 0;
break;
case CLOSE_WITHOUT_ANIMATION:
return leftValue;
break;
}
} else {
return 0;
}
}
);
}
export function homeStackPointer (homeStackState) {
return useDerivedValue(
function () {
'worklet'
var homeStackStateValue = homeStackState.value;
return (homeStackStateValue == OPEN_WITH_ANIMATION ||
homeStackStateValue == OPEN_WITHOUT_ANIMATION) ? "auto" : "none";
}
);
}
export function homeStackScale (homeStackState, minimizeScale) {
return useDerivedValue(
function () {
'worklet'
switch (homeStackState.value) {
case OPEN_WITH_ANIMATION:
return withTiming(1, defaultDurationAndEasing);
break;
case CLOSE_WITH_ANIMATION:
return withTiming(minimizeScale, defaultDurationAndEasing);
break;
case OPEN_WITHOUT_ANIMATION:
return 1;
break;
case CLOSE_WITHOUT_ANIMATION:
return minimizeScale;
break;
}
}
);
}
-105
View File
@@ -1,5 +1,3 @@
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
// Generic Worklets
export function applyAnimationsToStyle(animations, style) {
@@ -29,106 +27,3 @@ export function applyAnimationsToStyle(animations, style) {
return Object.assign(animatedStyle, style);
};
};
// Switcher Worklets
export function stackOpacity (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? 1 : 0;
}
);
}
export function stackPointer (stackId, selectedStackId) {
return useDerivedValue(
function () {
'worklet'
return selectedStackId.value == stackId ? "auto" : "none";
}
);
}
export function bottomTabIconColor (stackId, selectedStackId, homeStackOpen,
passThrough, selectedTabColor, defaultColor,
passThroughColor) {
return useDerivedValue(
function () {
'worklet'
if (selectedStackId.value == stackId && homeStackOpen.value){
return selectedTabColor;
}
else if (passThrough.value){
return passThroughColor;
}
else {
return defaultColor;
}
}
);
}
// Home Stack
const shellAnimationTime = 200;
const defaultDurationAndEasing = {
duration: shellAnimationTime,
easing: Easing.bezier(0, 0, 1, 1),
}
export function homeStackOpacity (homeStackOpen) {
return useDerivedValue(
function () {
'worklet'
return withTiming(homeStackOpen.value ? 1 : 0, defaultDurationAndEasing);
}
);
}
export function homeStackTop (homeStackOpen, top) {
return useDerivedValue(
function () {
'worklet'
return withTiming(homeStackOpen.value ? 0 : top, defaultDurationAndEasing);
}
);
}
export function homeStackLeft (selectedStackId, animateHomeStackLeft, homeStackOpen, left) {
return useDerivedValue(
function () {
'worklet'
if (animateHomeStackLeft.value) {
var leftValue = left[selectedStackId.value];
if (homeStackOpen.value) {
return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, defaultDurationAndEasing))
} else {
return withTiming(leftValue, defaultDurationAndEasing);
}
} else {
return 0;
}
}
);
}
export function homeStackPointer (homeStackOpen) {
return useDerivedValue(
function () {
'worklet'
return homeStackOpen.value ? "auto" : "none";
}
);
}
export function homeStackScale (homeStackOpen, minimizeScale) {
return useDerivedValue(
function () {
'worklet'
return withTiming(homeStackOpen.value ? 1 : minimizeScale, defaultDurationAndEasing);
}
);
}
+3
View File
@@ -282,6 +282,8 @@
(def worklet-factory
#js {:applyAnimationsToStyle (fn [])})
(def shell-worklets #js {})
;; Update i18n_resources.cljs
(defn mock [module]
(case module
@@ -328,6 +330,7 @@
"@react-native-async-storage/async-storage" async-storage
"react-native-svg" react-native-svg
"../src/js/worklet_factory.js" worklet-factory
"../src/js/shell_worklets.js" shell-worklets
"./fleets.js" default-fleets
"./chats.js" default-chats
"@walletconnect/client" wallet-connect-client
+2 -2
View File
@@ -56,7 +56,7 @@
(defn button [{:keys [on-press disabled type theme before after
haptic-feedback haptic-type on-long-press on-press-start
accessibility-label loading border-radius style]
accessibility-label loading border-radius style test-ID]
:or {theme :main
type :primary
haptic-feedback true
@@ -92,7 +92,7 @@
{:on-press-start (fn []
(optional-haptic)
(on-press-start))}))
[rn/view {:style (merge (style-container type) style)}
[rn/view {:test-ID test-ID :style (merge (style-container type) style)}
(when before
[rn/view
[icons/icon before {:color icon-color}]])
+44
View File
@@ -0,0 +1,44 @@
const waitToNavigate = duration => new Promise(resolve => setTimeout(() => resolve(), duration));
const SUPER_SECRET_PASSWORD = 'password'
const loginToHomePage = async () => {
if (device.getPlatform() === 'ios') {
await device.setStatusBar({ time: '12:34', dataNetwork: 'wifi', wifiBars: '3', batteryState: 'charging', batteryLevel: '100' });
}
await device.reloadReactNative();
await element(by.id('terms-of-service')).tap();
await waitToNavigate(400);
await element(by.id('get-started')).tap();
await waitToNavigate(300);
await element(by.id('generate-keys')).tap();
await waitToNavigate(200);
await element(by.text('Next')).tap();
await waitToNavigate(700);
await element(by.text('Next')).tap();
await waitToNavigate(700);
await element(by.id('password-placeholder')).typeText(SUPER_SECRET_PASSWORD);
await element(by.id('confirm-password-placeholder')).typeText(SUPER_SECRET_PASSWORD);
await element(by.text('Next')).tap();
await waitToNavigate(200);
await element(by.id("browser-stack")).tap();
await waitToNavigate(400);
await element(by.text("Quo2.0 Preview")).tap();
await waitToNavigate(400);
}
describe('Default Renders', () => {
beforeAll(async () => loginToHomePage())
beforeEach(async () => {
});
afterEach(async () => {
await element(by.id("back-button")).tap();
await waitToNavigate(200);
});
it(`button page should match image render`, async () => {
await element(by.id(`quo2-:button`)).tap();
await waitToNavigate(200);
const res = await jestExpect(`button`).toMatchImageSnapshot();
})
});
+11 -13
View File
@@ -4,25 +4,23 @@
[react-native.core :as rn]))
(def sizes
{:icon {:small 12
:medium 16
:large 20}
:container {:small 20
{:icon {:small 12
:medium 16
:large 20}
:container {:small 20
:medium 32
:large 48}})
:large 48}})
;; TODO: this implementation does not support group display picture (can only display default group icon).
(defn group-avatar [_]
(fn [{:keys [color size override-theme]}]
(let [theme (or override-theme (if (colors/dark?) :dark :light))
container-size (get-in sizes [:container size])
(fn [{:keys [color size]}]
(let [container-size (get-in sizes [:container size])
icon-size (get-in sizes [:icon size])]
[rn/view {:width container-size
:height container-size
:align-items :center
:justify-content :center
:border-radius (/ container-size 2)
:background-color (if (= theme :light)
(colors/custom-color color 50)
(colors/custom-color color 60))}
[icon/icon :total-members {:size icon-size
:color colors/white-opa-70}]])))
:background-color (colors/custom-color-by-theme color 50 60)}
[icon/icon :i/group {:size icon-size
:color colors/white-opa-70}]])))
+7 -7
View File
@@ -122,20 +122,20 @@
first-initial-letter
initials)
"")]
[rn/view {:style {:width outer-dimensions
:height outer-dimensions
:border-radius outer-dimensions}}
[rn/view {:accessibility-label :user-avatar
: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
:no-color true}])
[icons/icon :i/identicon-ring {:size outer-dimensions
:no-color true}])
(if profile-picture
;; display image
[fast-image/fast-image {:source {:uri profile-picture}
:style (container-styling inner-dimensions outer-dimensions)}]
;; else display initials
[container inner-dimensions outer-dimensions
^{:key :icon-text}
[text/text {:weight :semi-bold
:size font-size
:style {:color colors/white-opa-70}}
+202 -176
View File
@@ -7,147 +7,149 @@
[quo2.components.icon :as quo2.icons]))
(def themes
{:light {:primary {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/primary-50
:pressed colors/primary-60
:disabled colors/primary-50}}
:secondary {:icon-color colors/primary-50
:label {:style {:color colors/primary-50}}
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-40
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label {:style {:color colors/neutral-100}}
:background-color {:default colors/neutral-10
:pressed colors/neutral-20
:disabled colors/neutral-10}}
:dark-grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label {:style {:color colors/neutral-100}}
:background-color {:default colors/neutral-20
:pressed colors/neutral-30
:disabled colors/neutral-20}}
:outline {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label {:style {:color colors/neutral-100}}
:border-color {:default colors/neutral-20
:pressed colors/neutral-40
:disabled colors/neutral-20}}
:ghost {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label {:style {:color colors/neutral-100}}
:background-color {:pressed colors/neutral-10}}
:danger {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/danger-50
:pressed colors/danger-60
:disabled colors/danger-50}}
:positive {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/success-50
:pressed colors/success-60
:disabled colors/success-50-opa-30}}
:photo-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label {:style {:color colors/neutral-100}}
:background-color {:default colors/white-opa-40
:pressed colors/white-opa-50
:disabled colors/white-opa-40}}
:blur-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label {:style {:color colors/neutral-100}}
:background-color {:default colors/neutral-80-opa-5
:pressed colors/neutral-80-opa-10
:disabled colors/neutral-80-opa-5}}
:blur-bg-outline {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label {:style {:color colors/neutral-100}}
:border-color {:default colors/neutral-80-opa-10
:pressed colors/neutral-80-opa-20
:disabled colors/neutral-80-opa-10}}
{:light {:primary {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/primary-50
:pressed colors/primary-60
:disabled colors/primary-50}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-40
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:default colors/neutral-10
:pressed colors/neutral-20
:disabled colors/neutral-10}}
:dark-grey {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:default colors/neutral-20
:pressed colors/neutral-30
:disabled colors/neutral-20}}
:outline {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:border-color {:default colors/neutral-20
:pressed colors/neutral-40
:disabled colors/neutral-20}}
:ghost {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:background-color {:pressed colors/neutral-10}}
:danger {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/danger-50
:pressed colors/danger-60
:disabled colors/danger-50}}
:positive {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/success-50
:pressed colors/success-60
:disabled colors/success-50-opa-30}}
:photo-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:background-color {:default colors/white-opa-40
:pressed colors/white-opa-50
:disabled colors/white-opa-40}}
:blur-bg {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:background-color {:default colors/neutral-80-opa-5
:pressed colors/neutral-80-opa-10
:disabled colors/neutral-80-opa-5}}
:blur-bg-outline {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
:border-color {:default colors/neutral-80-opa-10
:pressed colors/neutral-80-opa-20
:disabled colors/neutral-80-opa-10}}
:shell {:icon-color colors/white
:label {:style {:color colors/white}}
:label-color colors/white
:background-color {:default colors/neutral-95
:pressed colors/neutral-95
:disabled colors/neutral-95}}}
:dark {:primary {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/primary-60
:pressed colors/primary-50
:disabled colors/primary-60}}
:secondary {:icon-color colors/primary-50
:label {:style {:color colors/primary-50}}
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-30
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label {:style {:color colors/white}}
:background-color {:default colors/neutral-80
:pressed colors/neutral-60
:disabled colors/neutral-80}}
:dark-grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label {:style {:color colors/white}}
:background-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:outline {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label {:style {:color colors/white}}
:border-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:ghost {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label {:style {:color colors/white}}
:background-color {:pressed colors/neutral-80}}
:danger {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/danger-60
:pressed colors/danger-50
:disabled colors/danger-60}}
:positive {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/success-60
:pressed colors/success-50
:disabled colors/success-60-opa-30}}
:photo-bg {:icon-color colors/white
:icon-secondary-color colors/neutral-30
:label {:style {:color colors/white}}
:background-color {:default colors/neutral-80-opa-40
:pressed colors/neutral-80-opa-50
:disabled colors/neutral-80-opa-40}}
:blur-bg {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label {:style {:color colors/white}}
:background-color {:default colors/white-opa-5
:pressed colors/white-opa-10
:disabled colors/white-opa-5}}
:blur-bg-outline {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label {:style {:color colors/white}}
:border-color {:default colors/white-opa-10
:pressed colors/white-opa-20
:disabled colors/white-opa-5}}
:shell {:icon-color colors/white
:label {:style {:color colors/white}}
:background-color {:default colors/neutral-95}}}})
:dark {:primary {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/primary-60
:pressed colors/primary-50
:disabled colors/primary-60}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-30
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:default colors/neutral-80
:pressed colors/neutral-60
:disabled colors/neutral-80}}
:dark-grey {:icon-color colors/white
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:outline {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label-color colors/white
:border-color {:default colors/neutral-70
:pressed colors/neutral-60
:disabled colors/neutral-70}}
:ghost {:icon-color colors/neutral-40
:icon-secondary-color colors/neutral-40
:label-color colors/white
:background-color {:pressed colors/neutral-80}}
:danger {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/danger-60
:pressed colors/danger-50
:disabled colors/danger-60}}
:positive {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/success-60
:pressed colors/success-50
:disabled colors/success-60-opa-30}}
:photo-bg {:icon-color colors/white
:icon-secondary-color colors/neutral-30
:label-color colors/white
:background-color {:default colors/neutral-80-opa-40
:pressed colors/neutral-80-opa-50
:disabled colors/neutral-80-opa-40}}
:blur-bg {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label-color colors/white
:background-color {:default colors/white-opa-5
:pressed colors/white-opa-10
:disabled colors/white-opa-5}}
:blur-bg-outline {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label-color colors/white
:border-color {:default colors/white-opa-10
:pressed colors/white-opa-20
:disabled colors/white-opa-5}}
:shell {:icon-color colors/white
:label-color colors/white
:background-color {:default colors/neutral-95}}}})
(defn shape-style-container [type icon size]
{:border-radius (if (and icon (#{:primary :secondary :danger} type))
24
(case size
56 12
40 12
32 10
24 8))})
(defn style-container [type size disabled background-color border-color icon above width before after]
(merge {:height size
:align-items :center
:justify-content :center
:flex-direction (if above :column :row)
:border-radius (if (and icon (#{:primary :secondary :danger} type))
24
(case size
56 12
40 12
32 10
24 8))
:background-color background-color
:padding-horizontal (when-not (or icon before after)
(case size 56 16 40 16 32 12 24 8))
@@ -159,6 +161,7 @@
(case size 56 0 40 9 32 5 24 3))
:padding-bottom (when-not (or icon before after)
(case size 56 0 40 9 32 5 24 4))}
(shape-style-container type icon size)
(when width
{:width width})
(when icon
@@ -169,14 +172,19 @@
(when disabled
{:opacity 0.3})))
(defn community-themed? [type community-color]
(and (= type :community) (string? community-color)))
(defn button
"with label
[button opts \"label\"]
opts
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
:danger/:photo-bg/:blur-bg/:blur-bg-ouline/:shell
:danger/:photo-bg/:blur-bg/:blur-bg-ouline/:shell/:community
:size 40/32/24
:icon true/false
:community-color '#FFFFFF'
:community-text-color '#000000'
:before :icon-keyword
:after :icon-keyword}
@@ -184,20 +192,21 @@
[button {:icon true} :main-icons/close-circle]"
[_ _]
(let [pressed (reagent/atom false)]
(fn [{:keys [on-press disabled type size before after above width
(fn [{:keys [on-press disabled type size community-color community-text-color before after above width
override-theme override-background-color
on-long-press accessibility-label icon icon-no-color style]
on-long-press accessibility-label icon icon-no-color style test-ID]
:or {type :primary
size 40}}
children]
(let [{:keys [icon-color icon-secondary-color background-color label border-color]}
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color]}
(get-in themes [(or
override-theme
(theme/get-theme)) type])
state (cond disabled :disabled @pressed :pressed :else :default)
icon-size (when (= 24 size) 12)
icon-secondary-color (or icon-secondary-color icon-color)]
[rn/touchable-without-feedback (merge {:disabled disabled
[rn/touchable-without-feedback (merge {:test-ID test-ID
:disabled disabled
:accessibility-label accessibility-label}
(when on-press
{:on-press (fn []
@@ -211,48 +220,65 @@
(reset! pressed nil))})
[rn/view {:style (merge
(style-container
type
size
disabled
(or override-background-color (get background-color state))
(get border-color state)
icon
above
width
before
after)
(shape-style-container type icon size)
{:background-color
(if (= state :pressed)
(colors/theme-colors colors/neutral-100 colors/white)
:transparent)}
style)}
(when above
[rn/view
[quo2.icons/icon above {:container-style {:margin-bottom 2}
:color icon-secondary-color
:size icon-size}]])
(when before
[rn/view
[quo2.icons/icon before {:container-style {:margin-left (if (= size 40) 12 8)
:margin-right 4}
[rn/view {:style (merge
(style-container
type
size
disabled
(or override-background-color (get background-color state))
(get border-color state)
icon
above
width
before
after)
(when
(community-themed? type community-color)
(merge
{:background-color community-color}
(when (= state :pressed) {:opacity 0.9}))))}
(when above
[rn/view
[quo2.icons/icon above {:container-style {:margin-bottom 2}
:color icon-secondary-color
:size icon-size}]])
[rn/view
(cond
(or icon icon-no-color)
[quo2.icons/icon children {:color icon-color
:no-color icon-no-color
:size icon-size}]
(when before
[rn/view
[quo2.icons/icon before {:container-style {:margin-left (if (= size 40) 12 8)
:margin-right 4}
:color icon-secondary-color
:size icon-size}]])
[rn/view
(cond
(or icon icon-no-color)
[quo2.icons/icon children {:color icon-color
:no-color icon-no-color
:size icon-size}]
(string? children)
[text/text (merge {:size (when (#{56 24} size) :paragraph-2)
:weight :medium
:number-of-lines 1}
label)
children]
(string? children)
[text/text {:size (when (#{56 24} size) :paragraph-2)
:weight :medium
:number-of-lines 1
:style {:color (if
(and
(community-themed? type community-color)
(string? community-text-color))
community-text-color
label-color)}}
(vector? children)
children)]
(when after
[rn/view
[quo2.icons/icon after {:container-style {:margin-left 4
:margin-right (if (= size 40) 12 8)}
:color icon-secondary-color
:size icon-size}]])]]))))
children]
(vector? children)
children)]
(when after
[rn/view
[quo2.icons/icon after {:container-style {:margin-left 4
:margin-right (if (= size 40) 12 8)}
:color icon-secondary-color
:size icon-size}]])]]]))))
@@ -6,15 +6,11 @@
(defn community-card-view-item
[{:keys [name description locked
status tokens cover tags featured]} on-press]
status tokens cover tags width]} on-press]
[rn/touchable-opacity {:on-press on-press}
[rn/view {:style (merge (style/community-card 20)
{:margin-bottom 16}
(if featured
{:margin-right 12}
{:flex 1
:margin-horizontal 20}))}
[rn/view {:style {:height 230
[rn/view {:style (style/community-card 20)}
[rn/view {:style {:width width
:height 230
:border-radius 20}
:on-press on-press}
[rn/view
@@ -6,10 +6,49 @@
[quo2.components.counter.counter :as counter]
[quo2.components.icon :as icons]
[quo2.components.community.style :as style]
[react-native.fast-image :as fast-image]
[react-native.core :as rn]))
(defn communities-list-view-item [props {:keys [name locked? status notifications
tokens background-color]}]
(defn community-icon-view [community-icon]
[rn/view {:width 32
:height 32}
[fast-image/fast-image {:source {:uri community-icon}
:style {:height 32
:border-radius 16
:width 32}}]])
(defn notification-view [{:keys [muted?
unread-messages?
unread-mentions-count]}]
(cond
muted?
[icons/icon :i/muted {:container-style {:align-items :center
:justify-content :center}
:resize-mode :center
:size 20
:color (colors/theme-colors
colors/neutral-40
colors/neutral-50)}]
(pos? unread-mentions-count)
[counter/counter {:type :default} unread-mentions-count]
unread-messages?
[rn/view {:style {:width 8
:height 8
:border-radius 4
:background-color (colors/theme-colors
colors/neutral-40
colors/neutral-60)}}]))
(defn communities-list-view-item [props {:keys [name
locked?
status
muted?
unread-messages?
unread-mentions-count
community-icon
tokens
background-color]}]
[rn/view {:style (merge (style/community-card 16)
{:margin-bottom 12
:margin-horizontal 20})}
@@ -24,8 +63,8 @@
:padding-vertical 8
:background-color background-color}
[rn/view]
;;TODO new pure component based on quo2 should be implemented without status-im usage
;[communities.icon/community-icon-redesign community 32]]
(when community-icon
[community-icon-view community-icon])
[rn/view {:flex 1
:margin-horizontal 12}
[text/text {:weight :semi-bold
@@ -33,7 +72,7 @@
:accessibility-label :community-name-text
:number-of-lines 1
:ellipsize-mode :tail
:style {:color (when (= notifications :muted)
:style {:color (when muted?
(colors/theme-colors
colors/neutral-40
colors/neutral-60))}}
@@ -42,28 +81,18 @@
(if (= status :gated)
[community-view/permission-tag-container {:locked? locked?
:tokens tokens}]
(cond
(= notifications :unread-messages-count)
[rn/view {:style {:width 8
:height 8
:border-radius 4
:background-color (colors/theme-colors
colors/neutral-40
colors/neutral-60)}}]
[notification-view {:muted? muted?
:unread-mentions-count unread-mentions-count
:unread-messages? unread-messages?}])]]]])
(= notifications :unread-mentions-count)
[counter/counter {:type :default} 5]
(= notifications :muted)
[icons/icon :i/muted {:container-style {:align-items :center
:justify-content :center}
:resize-mode :center
:size 20
:color (colors/theme-colors
colors/neutral-40
colors/neutral-50)}]))]]]])
(defn communities-membership-list-item [props {:keys [name status tokens locked?]}]
(defn communities-membership-list-item [props {:keys [name
muted?
unread-messages?
unread-mentions-count
status
community-icon
tokens
locked?]}]
[rn/view {:margin-bottom 20}
[rn/touchable-highlight (merge {:underlay-color colors/primary-50-opa-5
:style {:border-radius 12}}
@@ -72,8 +101,9 @@
[rn/view {:flex-direction :row
:border-radius 16
:align-items :center}
;;TODO new pure component based on quo2 should be implemented without status-im usage
;[communities.icon/community-icon-redesign community 32]
(when community-icon
[community-icon-view community-icon])
[rn/view {:flex 1
:margin-left 12
:justify-content :center}
@@ -84,8 +114,12 @@
:weight :semi-bold
:size :paragraph-1}
name]]
(when (= status :gated)
[rn/view {:justify-content :center
:margin-right 12}
[rn/view {:justify-content :center
:margin-right 16}
(if (= status :gated)
[community-view/permission-tag-container {:locked? locked?
:tokens tokens}]])]]]])
:tokens tokens}]
[notification-view {:muted? muted?
:unread-mentions-count unread-mentions-count
:unread-messages? unread-messages?}])]]]]])
@@ -69,10 +69,12 @@
:style {:margin-top (if (= size :large) 8 2)}}
description])])
(defn permission-tag-container [{:keys [locked? tokens]}]
(defn permission-tag-container [{:keys [locked? tokens on-press]}]
[permission/tag {:background-color (colors/theme-colors
colors/neutral-10
colors/neutral-80)
:locked? locked?
:tokens tokens
:size 24}])
:size 24
:on-press on-press}])
@@ -0,0 +1,259 @@
(ns quo2.components.community.token-gating
(:require [quo.react-native :as rn]
[quo2.components.avatars.channel-avatar :as channel-avatar]
[quo2.components.buttons.button :as button]
[quo2.components.icon :as icon]
[quo2.components.info.information-box :as information-box]
[quo2.components.markdown.text :as text]
[quo2.components.tags.token-tag :as token-tag]
[quo2.foundations.colors :as colors]
[status-im.i18n.i18n :as i18n]
[status-im.ui.components.fast-image :as fast-image]))
(def ^:private token-tag-horizontal-spacing 7)
(def token-tag-vertical-spacing 5)
(def styles {:container {:flex 1
:padding-horizontal 20}
:header-container {:flex-direction :row
:align-items :center}
:header-spacing-community {:margin-bottom 16}
:header-spacing-channel {:margin-bottom 24}
:header-avatar {:margin-right 8}
:header-community-avatar-image {:width 32 :height 32}
:header-title-container {:flex 1
:flex-direction :row
:align-items :center}
:header-title-lock {:margin-left 6}
:header-info-button {:margin-left 8}
:token-requirement-text-spacing {:margin-vertical 8}
:token-requirement-list-spacing {:padding-vertical (- 8 token-tag-vertical-spacing)}
:token-row {:flex-direction :row
:flex-wrap :wrap
:align-items :center}
:token-row-container {:flex-direction :row
:align-items :center
:margin-horizontal (- token-tag-horizontal-spacing)}
:token-row-container-no-shift {:margin-left 0}
:token-row-or-text {:margin-right 3}
:token-tag-spacing {:margin-horizontal token-tag-horizontal-spacing
:margin-vertical token-tag-vertical-spacing}
:divider {:height 1
:margin-horizontal -20
:margin-top (- 12 token-tag-vertical-spacing)
:margin-bottom 8}
:membership-request-denied {:margin-top 13}
:enter-button {:margin-top 16}
:info-text {:margin-top 12
:text-align :center
:padding-horizontal 20}})
(defn multiple-token-requirements? [token-requirement-lists]
(when (vector? (first token-requirement-lists))
(> (count token-requirement-lists) 1)))
(defn is-token-requirement-met? [token-requirement-list]
(and (seq token-requirement-list)
(every?
(fn [token]
(get token :is-sufficient?))
token-requirement-list)))
(defn are-multiple-token-requirements-met? [token-requirement-lists]
(if (multiple-token-requirements? token-requirement-lists)
(some is-token-requirement-met? token-requirement-lists)
(is-token-requirement-met? token-requirement-lists)))
(defn token-requirement-list-row [tokens community-color]
[rn/view {:style (merge
(get styles :token-row)
(get styles :token-requirement-list-spacing))}
(map-indexed (fn [token-index token]
(let [{:keys [token-img-src token amount is-sufficient? is-purchasable?]} token]
^{:key token-index}
[rn/view {:style (get styles :token-tag-spacing)}
[token-tag/token-tag {:token token
:value amount
:size 24
:border-color community-color
:is-required is-sufficient?
:is-purchasable is-purchasable?
:token-img-src token-img-src}]]))
tokens)])
(defn token-requirement-list [props community-color]
(let [{:keys [gate token-requirements-changed? required-tokens-lost?]} props
[gate-type token-requirement-lists] gate
multiple-token-requirements? (multiple-token-requirements? token-requirement-lists)
is-sufficient? (are-multiple-token-requirements-met? token-requirement-lists)
you-must-hold-label (if (= gate-type :join)
(cond
token-requirements-changed? :t/you-must-now-hold
required-tokens-lost? :t/you-must-always-hold
:else :t/you-must-hold)
:t/you-must-hold)
message-label (cond
(= gate-type :join)
(cond
token-requirements-changed? :t/community-join-requirements-changed
required-tokens-lost? :t/community-join-requirements-tokens-lost
:else (if is-sufficient? :t/community-join-requirements-met :t/community-join-requirements-not-met))
(= gate-type :read)
(if is-sufficient?
:t/community-channel-read-requirements-met
:t/community-channel-read-requirements-not-met)
(= gate-type :write)
(if is-sufficient?
:t/community-channel-write-requirements-met
:t/community-channel-write-requirements-not-met))]
[rn/view
[rn/view {:style (get styles :token-requirement-text-spacing)}
[text/text {:weight :medium
:number-of-lines 1}
(i18n/label
message-label)]
[text/text {:size :paragraph-2
:number-of-lines 1}
(i18n/label
you-must-hold-label)]]
(if multiple-token-requirements?
(map-indexed
(fn [token-requirement-index tokens]
^{:key token-requirement-index}
[rn/view {:style (merge
(get styles :token-row-container)
(when-not (= token-requirement-index 0)
(get styles :token-row-container-no-shift)))}
(when-not (= token-requirement-index 0)
[text/text {:style (get styles :token-row-or-text)
:size :paragraph-2} "or"])
[token-requirement-list-row tokens community-color]])
token-requirement-lists)
[rn/view {:style (get styles :token-row-container)}
[token-requirement-list-row token-requirement-lists community-color]])]))
(defn is-community-locked? [community]
(not (are-multiple-token-requirements-met? (get-in community [:gates :join]))))
(defn is-channel-locked? [channel]
(not (are-multiple-token-requirements-met?
(or (get-in channel [:gates :read])
(get-in channel [:gates :write])))))
(defn token-gating
"[token-gating opts]
opts
{
:community {
:name string
:community-avatar-img-src string
:community-color string
:community-text-color string
:token-requirements-changed? boolean
:required-tokens-lost? boolean
}
:channel {
:name string
:emoji string
:emoji-background-color :string
:on-enter-channel callback
:membership-request-denied? boolean
}
}"
[_ _]
(fn [{:keys [community channel]}]
(let [type (if (some? community) :community :channel)
{:keys [name
emoji
emoji-background-color
on-enter-channel
community-avatar-img-src
community-color
community-text-color
membership-request-denied?
token-requirements-changed?
required-tokens-lost?
gates]} (if (= type :community) community channel)
locked? (if
(= type :community)
(is-community-locked? community)
(is-channel-locked? channel))]
[rn/view {:style (merge (get styles :container) {:background-color (colors/theme-colors colors/white colors/neutral-90)})}
[rn/view {:style (merge
(get styles :header-container)
(if
(= type :community)
(get styles :header-spacing-community)
(get styles :header-spacing-channel)))}
[rn/view {:style (get styles :header-avatar)}
(if (= type :community)
[fast-image/fast-image {:source community-avatar-img-src
:style (get styles :header-community-avatar-image)}]
[channel-avatar/channel-avatar {:big? true
:locked? locked?
:emoji emoji
:emoji-background-color emoji-background-color}])]
[rn/view {:style (get styles :header-title-container)}
[text/text {:weight :semi-bold
:number-of-lines 1
:size :heading-1
:style (get styles :header-text)} (if (= type :community) name (str "# " name))]
(when (= type :community)
[icon/icon (if locked?
:main-icons2/locked
:main-icons2/unlocked)
{:container-style (get styles :header-title-lock)
:color (colors/theme-colors
colors/neutral-50
colors/neutral-40)}])]
[button/button {:type :outline
:size 32
:icon true
:style (get styles :header-info-button)} :main-icons2/info]]
(map-indexed (fn [gate-index gate]
^{:key gate-index}
[:<>
(when-not (= gate-index 0)
[rn/view {:style (merge
(get styles :divider)
{:background-color (colors/theme-colors
colors/neutral-10
colors/neutral-80)})}])
[token-requirement-list {:gate gate :token-requirements-changed? token-requirements-changed? :required-tokens-lost? required-tokens-lost?} community-color]])
gates)
(when (= type :channel)
(if membership-request-denied?
[information-box/information-box {:type :error
:icon :main-icons2/untrustworthy
:no-icon-color? true
:style (get styles :membership-request-denied)}
(i18n/label
:t/membership-request-denied)]
[:<>
[button/button {:type :community
:community-color community-color
:community-text-color community-text-color
:style (get styles :enter-button)
:disabled locked?
:on-press on-enter-channel}
(str "# " (i18n/label
:t/enter-channel))]
[text/text
{:size :paragraph-2
:style (merge
(get styles :info-text)
{:color (colors/theme-colors
colors/neutral-50
colors/neutral-40)})}
(i18n/label
:t/community-enter-channel-info)]]))])))
+4 -2
View File
@@ -20,7 +20,7 @@
(defn counter
"type: default, secondary, grey, outline
value: integer"
[{:keys [type override-text-color override-bg-color style]} value]
[{:keys [type override-text-color override-bg-color style accessibility-label]} value]
(let [type (or type :default)
text-color (or override-text-color
(if (or
@@ -38,7 +38,9 @@
1 16
2 20
28)]
[rn/view {:style (cond-> (merge
[rn/view {:accessible true
:accessibility-label accessibility-label
:style (cond-> (merge
{:align-items :center
:justify-content :center
:border-radius 6
+61 -53
View File
@@ -6,69 +6,77 @@
(defn- get-icon-color [danger?]
(if danger?
(colors/theme-colors colors/danger-50 colors/danger-60)
colors/danger-50
(colors/theme-colors colors/neutral-50 colors/neutral-40)))
(defn divider []
[rn/view {:style {:border-top-width 1
:border-top-color (colors/theme-colors
colors/neutral-10 colors/neutral-90)
:margin-top 8
:margin-bottom 7
:align-items :center
:flex-direction :row}}])
(defn action [{:keys [icon
label
sub-label
right-icon
danger?
on-press] :as action-props}]
on-press
add-divider?] :as action-props}]
(when action-props
[rn/touchable-opacity {:on-press on-press}
[rn/view {:style
{:height (if sub-label 56 47)
:margin-horizontal 20
:flex-direction :row}}
[:<> {:key label}
(when add-divider? [divider])
[rn/touchable-highlight {:style {:border-radius 12
:height (if sub-label 58 50)
:margin-horizontal 8}
:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
:on-press on-press}
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:margin-right 12
:width 20}}
[icon/icon icon
{:color (get-icon-color danger?)
:size 20}]]
[rn/view
{:style
{:flex 1
:justify-content :center}}
[text/text
{:size :paragraph-1
:weight :medium
:style {:color
(when danger?
(colors/theme-colors colors/danger-50 colors/danger-60))}}
label]
(when sub-label
[text/text
{:size :paragraph-2
:style {:color
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
sub-label])]
(when right-icon
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:width 20}}
[icon/icon right-icon
{:color (get-icon-color danger?)
:size 20}]])]]))
{:height (if sub-label 58 50)
(defn divider []
[rn/view {:style {:border-top-width 1
:border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
:margin-top 8
:margin-bottom 7
:align-items :center
:flex-direction :row}}])
:margin-horizontal 12
:flex-direction :row}}
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:margin-right 12
:width 20}}
[icon/icon icon
{:color (get-icon-color danger?)
:size 20}]]
[rn/view
{:style
{:flex 1
:justify-content :center}}
[text/text
{:size :paragraph-1
:weight :medium
:style {:color
(when danger?
(colors/theme-colors colors/danger-50 colors/danger-60))}}
label]
(when sub-label
[text/text
{:size :paragraph-2
:style {:color
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
sub-label])]
(when right-icon
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:width 20}}
[icon/icon right-icon
{:color (get-icon-color danger?)
:size 20}]])]]]))
(defn action-drawer [sections]
[:<> {:style
{:flex 1}}
(interpose
[divider]
[:<>
(doall
(for [actions sections]
(map action actions)))])
(doall
(map action actions))))])
+8 -2
View File
@@ -4,9 +4,14 @@
(def icon-path "./resources/images/icons2/")
(defn combine-path [path el]
(if (System/getenv "COMPONENT_TEST")
(str "." path el "@2x.png")
(str "." path el ".png")))
(defn require-icon [size path]
(fn [el]
(let [s (str "." path el ".png")
(let [s (combine-path path el)
k (-> el
(cstr/replace "_" "-")
(cstr/replace " " "-")
@@ -30,4 +35,5 @@
(get-icons 12)
(get-icons 16)
(get-icons 20)
(get-icons 24)))
(get-icons 24)
(get-icons 32)))
+9 -7
View File
@@ -19,19 +19,21 @@
(defn info-message
"[info-message opts \"message\"]
opts
{:type :default/:success/:error
:size :default/:tiny
:icon :main-icons/info ;; info message icon
:text-color colors/white ;; text color override
:icon-color colors/white ;; icon color override"
[{:keys [type size icon text-color icon-color]} message]
{:type :default/:success/:error
:size :default/:tiny
:icon :main-icons/info ;; info message icon
:text-color colors/white ;; text color override
:icon-color colors/white ;; icon color override
:no-icon-color? false ;; disable tint color for icon"
[{:keys [type size icon text-color icon-color no-icon-color?]} message]
(let [weight (if (= size :default) :regular :medium)
size (if (= size :default) :paragraph-2 :label)
text-color (or text-color (get-color type))
icon-color (or icon-color text-color)]
[rn/view {:style {:flex-direction :row
:flex 1}}
[quo2.icons/icon icon {:color icon-color
[quo2.icons/icon icon {:color icon-color
:no-color no-icon-color?
:size 12
:container-style {:margin-top 3}}]
[text/text {:size size
@@ -49,11 +49,12 @@
:closed? true/false ;; information box's state
:id :information-box-id ;; unique id (required for closable? information box)
:icon :main-icons/info ;; information box icon
:no-icon-color? false ;; disable tint color for icon
:style style
:button-label \"PressMe\" ;; add action button with label
:on-button-press action ;; (required for information box with button-label)
:on-close on-close ;; (optional on-close call)"
[{:keys [type closable? closed? id icon style button-label on-button-press on-close]} message]
[{:keys [type closable? closed? id icon style button-label on-button-press on-close no-icon-color?]} message]
(let [background-color (get-color-by-type type :bg)
border-color (get-color-by-type type :border)
icon-color (get-color-by-type type :icon)
@@ -73,7 +74,8 @@
[info-message/info-message {:size :default
:icon icon
:text-color text-color
:icon-color icon-color} message]
:icon-color icon-color
:no-icon-color? no-icon-color?} message]
(when closable?
[rn/touchable-opacity
{:on-press on-close
+50 -49
View File
@@ -1,56 +1,57 @@
(ns quo2.components.list-items.channel
(:require [react-native.core :as rn]
[quo2.foundations.colors :as colors]
(:require [quo2.components.avatars.channel-avatar :as channel-avatar]
[quo2.components.counter.counter :as quo2.counter]
[quo2.components.icon :as quo2.icons]
[quo2.components.avatars.channel-avatar :as channel-avatar]
[quo2.components.markdown.text :as quo2.text]
[quo2.theme :as theme]))
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(defn list-item [{:keys [name locked? mentions-count unread-messages?
muted? is-active-channel? emoji channel-color]
muted? is-active-channel? emoji channel-color on-press]
:or {channel-color colors/primary-50}}]
[rn/view {:style (merge {:height 48
:display :flex
:border-radius 12
:flex-direction :row
:justify-content :space-between
:align-items :center
:width "100%"
:padding-left 12
:padding-right 12}
(when is-active-channel?
{:background-color (colors/theme-alpha channel-color 0.05 0.05)}))}
[rn/view {:display :flex
:flex-direction :row
:justify-content :flex-start
:align-items :center}
[channel-avatar/channel-avatar
{:big? true
:locked? locked?
:emoji-background-color (colors/theme-alpha channel-color 0.1 0.1)
:emoji emoji}]
[quo2.text/text
{:style (merge {:margin-left 12}
(when (and (not locked?) muted?)
{:color (if (theme/dark?) colors/neutral-60 colors/neutral-40)}))
:weight :medium :size :paragraph-1} (str "# " name)]]
[rn/view {:style {:height 20}}
(when (and (not locked?)
muted?)
[quo2.icons/icon :i/muted
{:size 20
:no-color true}])
(when (and (not locked?)
(not muted?)
(pos? (int mentions-count)))
[rn/view {:style {:margin-right 2
:margin-top 2}}
[quo2.counter/counter {:override-bg-color channel-color} mentions-count]])
(when (and (not locked?)
(not muted?)
(not (pos? (int mentions-count)))
unread-messages?)
[quo2.icons/icon :i/channel-notification
{:size 20
:no-color true}])]])
[rn/touchable-opacity {:on-press on-press}
[rn/view {:style (merge {:height 48
:display :flex
:border-radius 12
:flex-direction :row
:justify-content :space-between
:align-items :center
:width "100%"
:padding-left 12
:padding-right 12}
(when is-active-channel?
{:background-color (colors/theme-alpha channel-color 0.05 0.05)}))}
[rn/view {:display :flex
:flex-direction :row
:justify-content :flex-start
:align-items :center}
[channel-avatar/channel-avatar
{:big? true
:locked? locked?
:emoji-background-color (colors/theme-alpha channel-color 0.1 0.1)
:emoji emoji}]
[quo2.text/text
{:style (merge {:margin-left 12}
(when (and (not locked?) muted?)
{:color (if (theme/dark?) colors/neutral-60 colors/neutral-40)}))
:weight :medium :size :paragraph-1} (str "# " name)]]
[rn/view {:style {:height 20}}
(when (and (not locked?)
muted?)
[quo2.icons/icon :i/muted
{:size 20
:no-color true}])
(when (and (not locked?)
(not muted?)
(pos? (int mentions-count)))
[rn/view {:style {:margin-right 2
:margin-top 2}}
[quo2.counter/counter {:override-bg-color channel-color} mentions-count]])
(when (and (not locked?)
(not muted?)
(not (pos? (int mentions-count)))
unread-messages?)
[quo2.icons/icon :i/channel-notification
{:size 20
:no-color true}])]]])
@@ -0,0 +1,39 @@
(ns quo2.components.messages.author.style
(:require [quo2.foundations.colors :as colors]))
(def container
{:flex 1
:flex-wrap :wrap
:height 18
:flex-direction :row
:align-items :center})
(defn ens-text []
{:color (colors/theme-colors colors/neutral-100 colors/white)})
(defn nickname-text []
{:color (colors/theme-colors colors/neutral-100 colors/white)})
(def middle-dot-nickname
{:color colors/neutral-50
:margin-horizontal 4})
(def chat-key-text
{:color colors/neutral-50
:margin-left 8})
(def middle-dot-chat-key
{:color colors/neutral-50
:margin-left 4})
(defn profile-name-text [nickname?]
{:color (if nickname?
(colors/theme-colors colors/neutral-60 colors/neutral-40)
(colors/theme-colors colors/neutral-100 colors/white))})
(def icon-container
{:margin-left 4})
(defn time-text [ens?]
{:color colors/neutral-50
:margin-left (if ens? 8 4)})
@@ -0,0 +1,88 @@
(ns quo2.components.messages.author.view
(:require
[quo2.components.messages.author.style :as style]
[react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.icon :as icons]
[status-im.utils.utils :as utils]
[clojure.string :as string]))
(def middle-dot "·")
(defn display-name [{:keys [profile-name nickname ens-name text-style]}]
(let [ens? (-> ens-name string/blank? not)
nickname? (-> nickname string/blank? not)]
(if ens?
[text/text (merge {:weight :semi-bold
:size :paragraph-2
:style (style/ens-text)}
text-style)
ens-name]
[:<>
(if nickname?
[text/text (merge {:weight :semi-bold
:size :paragraph-2
:style (style/nickname-text)}
text-style)
nickname]
[text/text (merge {:weight :semi-bold
:size :paragraph-2
:style (style/profile-name-text nickname?)}
text-style)
profile-name])])))
(defn author [{:keys [profile-name nickname chat-key ens-name time-str contact? verified? untrustworthy?]}]
[:f>
(fn []
(let [ens? (-> ens-name string/blank? not)
nickname? (-> nickname string/blank? not)]
[rn/view {:style style/container}
(if ens?
[text/text {:weight :semi-bold
:size :paragraph-2
:style (style/ens-text)}
ens-name]
[:<>
(when nickname?
[:<>
[text/text {:weight :semi-bold
:size :paragraph-2
:style (style/nickname-text)}
nickname]
[text/text {:size :paragraph-2
:style style/middle-dot-nickname}
middle-dot]])
[text/text {:weight (if nickname? :medium :semi-bold)
:size :paragraph-2
:style (style/profile-name-text nickname?)}
profile-name]])
(when contact?
[icons/icon :main-icons2/contact
{:size 12
:no-color true
:container-style style/icon-container}])
(cond
verified?
[icons/icon :main-icons2/verified
{:size 12
:no-color true
:container-style style/icon-container}]
untrustworthy?
[icons/icon :main-icons2/untrustworthy
{:size 12
:no-color true
:container-style style/icon-container}])
(when-not ens?
[text/text {:monospace true
:size :paragraph-2
:style style/chat-key-text}
(utils/get-shortened-address chat-key)])
(when-not ens?
[text/text {:monospace true
:size :paragraph-2
:style style/middle-dot-chat-key}
middle-dot])
[text/text {:monospace true
:size :paragraph-2
:style (style/time-text ens?)}
time-str]]))])
@@ -6,7 +6,7 @@
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[utils :as utils]))
[utils.string :as utils]))
(def themes-landed {:pinned colors/primary-50-opa-5
:added colors/primary-50-opa-5
@@ -26,7 +26,7 @@
:icon-color-anim reanimated shared value
"
[{:keys [icon new-notifications? notification-indicator counter-label
on-press pass-through? icon-color-anim accessibility-label]}]
on-press pass-through? icon-color-anim accessibility-label test-ID]}]
[:f>
(fn []
(let [icon-animated-style (reanimated/apply-animations-to-style
@@ -40,7 +40,8 @@
:height 40
:border-radius 10})]
[rn/touchable-without-feedback
{:on-press on-press
{:test-ID test-ID
:on-press on-press
:on-press-in #(toggle-background-color background-color false pass-through?)
:on-press-out #(toggle-background-color background-color true pass-through?)
:accessibility-label accessibility-label}
@@ -14,31 +14,35 @@
:customization-color customization-color}]))
(defn floating-shell-button
"[floating-shell-button dynamic-buttons style]
dynamic-buttons
{:button-type {:on-press on-press :count count}}"
[dynamic-buttons style opacity-anim pointer-anim]
[:f>
(fn []
(let [original-style (merge {:flex-direction :row
:margin-horizontal 12} style)
animated-style (reanimated/apply-animations-to-style
{:opacity opacity-anim
:pointer-events pointer-anim}
original-style)]
[reanimated/view {:style animated-style}
;; Left Section
[rn/view {:style {:flex 1}}
[dynamic-button-view :search dynamic-buttons {:position :absolute
:right 8}]]
;; Mid Section (jump-to)
[dynamic-button-view :jump-to dynamic-buttons nil]
"[floating-shell-button dynamic-buttons style opacity-anim pointer-anim]
dynamic-buttons {:button-type {:on-press on-press :count count}}
style override style
opacity-anim reanimated value (optional)"
([dynamic-button style]
(floating-shell-button dynamic-button style nil))
([dynamic-buttons style opacity-anim]
[:f>
(fn []
(let [original-style (merge {:flex-direction :row
:margin-horizontal 12
:pointer-events :box-none} style)
animated-style (reanimated/apply-animations-to-style
(if opacity-anim
{:opacity opacity-anim} {})
original-style)]
[reanimated/view {:style animated-style}
;; Left Section
[rn/view {:style {:flex 1}}
[dynamic-button-view :search dynamic-buttons {:position :absolute
:right 8}]]
;; Mid Section (jump-to)
[dynamic-button-view :jump-to dynamic-buttons nil]
;; Right Section
[rn/view {:style {:flex 1}}
[rn/view {:style {:position :absolute
:flex-direction :row
:right 0}}
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))])
[rn/view {:style {:flex 1}}
[rn/view {:style {:position :absolute
:flex-direction :row
:right 0}}
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))]))
+101 -103
View File
@@ -3,7 +3,9 @@
[quo2.foundations.colors :as colors]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[clojure.string :as string]))
[clojure.string :as string]
[quo2.components.buttons.button :as button]
[quo2.components.avatars.user-avatar :as user-avatar]))
(def ^:private centrify-style
{:display :flex
@@ -12,12 +14,10 @@
(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
(merge {:size 20
:container-style {:width (if (big? size)
20
16)
@@ -28,34 +28,33 @@
{:color color}
{:no-color true})))
(defn render-left-section [{:keys [on-press icon
icon-color icon-background-color]}
put-middle-section-on-left?]
(defn left-section-view [{:keys [on-press icon accessibility-label type] :or {type :grey}}
put-middle-section-on-left?]
[rn/view {:style (merge
icon-styles
{:background-color icon-background-color
:width 32
:height 32}
{:accessibility-label accessibility-label}
(when put-middle-section-on-left? {:margin-right 5}))}
[rn/touchable-opacity {:on-press on-press}
[icons/icon icon (icon-props icon-color :big)]]])
[button/button {:on-press on-press :icon true :type type :size 32}
icon]])
(defn- mid-section-comp
[{:keys [description-user-icon horizontal-description? text-secondary-color align-mid? text-color icon main-text type description]}]
[rn/view {:style (assoc
centrify-style
:flex-direction :row
:margin-horizontal 2)}
[{:keys [description-img description-user-icon horizontal-description?
text-secondary-color align-mid? text-color icon main-text type 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 type))
(and description-user-icon
(and (or description-img description-user-icon)
(not icon)))
[rn/image {:source {:uri description-user-icon}
:style {:width 32
:height 32
:border-radius 32
:margin-right 8}}])
(if description-img
[rn/view {:margin-right 8}
[description-img]]
[rn/image {:source {:uri description-user-icon}
:style {:width 32
:height 32
:border-radius 32
:margin-right 8}}]))
[rn/view {:style {:flex-direction (if horizontal-description?
:row
:column)}}
@@ -73,76 +72,69 @@
horizontal-description? (assoc :margin-left 4 :margin-top 2))}
description])]])
(defn- render-mid-section
(defn- mid-section-view
[{:keys [horizontal-description? one-icon-align-left? type left-align?
main-text right-icon main-text-icon-color left-icon] :as 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)
main-text right-icon main-text-icon-color left-icon on-press avatar] :as 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)
component-instance [mid-section-comp (assoc 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 type
:text-only [text/text {:size :paragraph-1
:weight :semi-bold
:style {:color text-color}}
main-text]
:text-with-two-icons [rn/view {:style (assoc centrify-style :flex-direction :row)}
[icons/icon left-icon
(icon-props main-text-icon-color :big)]
[text/text {:size :paragraph-1
:weight :semi-bold
:style {:padding-horizontal 4
:color text-color}}
main-text]
[rn/touchable-opacity {:on-press on-press}
[rn/view {:style (merge
(if left-align?
align-left
centrify-style)
{:flex 1
:margin-left 4
:text-align-vertical :center})}
(case type
:text-only [text/text {:size :paragraph-1
:weight :semi-bold
:style {:color text-color}}
main-text]
:user-avatar [rn/view {:style (assoc centrify-style :flex-direction :row)}
[user-avatar/user-avatar avatar]
[text/text {:size :paragraph-1
:weight :semi-bold
:style {:padding-horizontal 4
:color text-color}}
main-text]]
:text-with-two-icons [rn/view {:style (assoc centrify-style :flex-direction :row)}
[icons/icon left-icon
(icon-props main-text-icon-color :big)]
[text/text {:size :paragraph-1
:weight :semi-bold
:style {:padding-horizontal 4
:color text-color}}
main-text]
[icons/icon right-icon
(icon-props 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 left-icon
(icon-props main-text-icon-color :big)])
component-instance]
[rn/view {:style {:flex-direction :row
:align-items :center}}
component-instance
(when horizontal-description?
[icons/icon left-icon
(icon-props main-text-icon-color :big)])])]
:text-with-description component-instance)]]))
[icons/icon right-icon
(icon-props 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 left-icon
(icon-props main-text-icon-color :big)])
component-instance]
[rn/view {:style {:flex-direction :row
:align-items :center}}
component-instance
(when horizontal-description?
[icons/icon left-icon
(icon-props main-text-icon-color :big)])])]
:text-with-description component-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- render-right-section [right-section-buttons]
[rn/view {:style (assoc
centrify-style
:flex-direction :row
:flex 1
:justify-content :flex-end)}
(defn- right-section-view [right-section-buttons]
[rn/view {:style (assoc centrify-style
:flex-direction :row
:flex 1
:justify-content :flex-end)}
(let [last-icon-index (-> right-section-buttons count dec)]
(map-indexed (fn [index {:keys [icon background-color icon-color on-press]}]
(map-indexed (fn [index {:keys [icon on-press type] :or {type :grey}}]
^{:key index}
[rn/touchable-opacity {:on-press on-press}
[right-section-icon
{:icon icon
:background-color background-color
:icon-color icon-color
:push-to-the-left? (not= index last-icon-index)}]])
[rn/view {:style {:margin-right (if (not= index last-icon-index) 8 0)}}
[button/button {:on-press on-press :icon true :type type :size 32}
icon]])
right-section-buttons))])
(defn page-nav
@@ -154,7 +146,7 @@
:page-nav-color color
:page-nav-background-uri image-uri
:mid-section
{:type one-of :text-only :text-with-two-icons :text-with-one-icon :text-with-description
{:type one-of :text-only :text-with-two-icons :text-with-one-icon :text-with-description :user-avatar
:icon icon
:main-text string
:left-icon icon
@@ -163,16 +155,19 @@
:description-color color
:description-icon icon
:description-user-icon icon
:description-img a render prop which will be used in place of :description-user-icon
:main-text-icon-color color
}
:left-section
{:on-press event
{:type button-type
:on-press event
:icon icon
:icon-color color
:icon-background-color color
}
:right-section-buttons vector of
{:on-press event
{:type button-type
:on-press event
:icon icon
:icon-color color
:icon-background-color color
@@ -189,32 +184,35 @@
mid-section-props
{:type (:type mid-section)
:horizontal-description? horizontal-description?
:description-img (:description-img mid-section)
:main-text (:main-text mid-section)
:main-text-icon-color (:main-text-icon-color mid-section)
:one-icon-align-left? one-icon-align-left?
:right-icon (:right-icon mid-section)
:icon (:icon mid-section)
:left-icon (:left-icon mid-section)}]
:left-icon (:left-icon mid-section)
:avatar (:avatar mid-section)}]
[rn/view {:style (cond-> {:display :flex
:flex-direction :row
;; iPhone 11 Pro's height in Figma divided by Component height 56/1125
:align-items :center
:padding-horizontal 20
:height 56
: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}}
(render-left-section left-section put-middle-section-on-left?)
[left-section-view left-section put-middle-section-on-left?]
(when put-middle-section-on-left?
[render-mid-section (assoc mid-section-props
:left-align? true
:description (:description mid-section)
:description-color (:description-color mid-section)
:description-icon (:description-icon mid-section)
:align-mid? align-mid?
:description-user-icon (:description-user-icon mid-section))])]
[mid-section-view (assoc mid-section-props
:left-align? true
:description (:description mid-section)
:description-color (:description-color mid-section)
:description-icon (:description-icon mid-section)
:align-mid? align-mid?
:description-user-icon (:description-user-icon mid-section))])]
(when-not put-middle-section-on-left?
[render-mid-section mid-section-props])
(render-right-section right-section-buttons)]))
[mid-section-view mid-section-props])
[right-section-view right-section-buttons]]))
@@ -1,98 +0,0 @@
(ns quo2.components.navigation.top-nav
(:require [react-native.core :as rn]
[quo2.foundations.colors :as colors]
[quo2.components.counter.counter :as counter]
[quo2.components.buttons.button :as quo2.button]
[quo2.components.avatars.user-avatar :as user-avatar]
[react-native.hole-view :as hole-view]))
(defn- get-button-common-props [type]
(let [default? (= type :default)
dark? (colors/dark?)]
{:icon true
:size 32
:style {:margin-left 12}
:type (if default?
(if dark? :grey :dark-grey)
type)
:override-background-color (when (and dark? default?)
colors/neutral-90)}))
(defn- base-button [icon on-press accessibility-label button-common-props]
[quo2.button/button
(merge
{:on-press on-press
:accessibility-label accessibility-label}
button-common-props)
icon])
(defn top-nav
"[top-nav opts]
opts
{:type :default/:blurred/:shell
:new-notifications? true/false
:notification-indicator :unread-dot/:counter
:open-profile fn
:open-search fn
:open-scanner fn
:show-qr fn
:open-activity-center fn
:style override-style
:avatar user-avatar
:counter-label number}
"
[{:keys [type new-notifications? notification-indicator open-profile open-search
open-scanner show-qr open-activity-center style avatar counter-label]}]
(let [button-common-props (get-button-common-props type)]
[rn/view {:style (merge
{:height 56}
style)}
;; Left Section
[rn/touchable-without-feedback {:on-press open-profile}
[rn/view {:style {:position :absolute
:left 20
:top 12}}
[user-avatar/user-avatar
(merge
{:ring? true
:status-indicator? true
:size :small}
avatar)]]]
;; Right Section
[rn/view {:style {:position :absolute
:right 20
:top 12
:flex-direction :row}}
[base-button :i/search open-search :open-search-button button-common-props]
[base-button :i/scan open-scanner :open-scanner-button button-common-props]
[base-button :i/qr-code show-qr :show-qr-button button-common-props]
[rn/view ;; Keep view instead of "[:<>" to make sure relative
;; position is calculated from this view instead of its parent
[hole-view/hole-view {:key new-notifications? ;; Key is required to force removal of holes
:holes (cond
(not new-notifications?) ;; No new notifications, remove holes
[]
(= notification-indicator :unread-dot)
[{:x 37 :y -3 :width 10 :height 10 :borderRadius 5}]
:else
[{:x 33 :y -7 :width 18 :height 18 :borderRadius 7}])}
[base-button :i/activity-center open-activity-center
:open-activity-center-button button-common-props]]
(when new-notifications?
(if (= notification-indicator :counter)
[counter/counter {:outline false
:override-text-color colors/white
:override-bg-color colors/primary-50
:style {:position :absolute
:left 34
:top -6}}
counter-label]
[rn/view {:style {:width 8
:height 8
:border-radius 4
:top -2
:left 38
:position :absolute
:background-color colors/primary-50}}]))]]]))
@@ -0,0 +1,76 @@
(ns quo2.components.notifications.activity-log.style
(:require [quo2.foundations.colors :as colors]))
(def container
{:flex-direction :row
:flex-grow 1
:align-items :flex-start
:padding-top 8
:padding-horizontal 12
:padding-bottom 12})
(def icon
{:height 32
:width 32
:border-radius 100
:margin-top 10
:border-width 1
:border-color colors/white-opa-5
:align-items :center
:justify-content :center})
(def message-title
{:color colors/white-opa-40
:margin-bottom 2})
(def message-body
{:color colors/white})
(def message-container
{:border-radius 12
:margin-top 12
:padding-horizontal 12
:padding-vertical 8
:background-color colors/white-opa-5})
(def buttons-container
{:margin-top 12
:flex-direction :row
:align-items :flex-start})
(def status
{:margin-top 12
:align-items :flex-start
:flex 1})
(defn title [replying?]
{:color colors/white
:flex-shrink 1
:max-width (when-not replying? "60%")})
(def timestamp
{:text-transform :none
:flex-grow 1
:margin-left 8
:color colors/neutral-40})
(def unread-dot
{:background-color colors/primary-50
:border-radius 4
:width 8
:height 8})
(def unread-dot-container
{:margin-left 8
:padding-horizontal 12
:padding-vertical 7})
(def context-container
{:flex-direction :row
:align-items :center
:justify-content :flex-start
:flex-wrap :wrap})
(def top-section-container
{:align-items :center
:flex-direction :row})
@@ -0,0 +1,178 @@
(ns quo2.components.notifications.activity-log.view
(:require [clojure.string :as string]
[quo.core :as quo]
[quo2.components.buttons.button :as button]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.tags.status-tags :as status-tags]
[quo2.foundations.colors :as colors]
[quo2.components.notifications.activity-log.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.i18n.i18n :as i18n]))
(def ^:private max-reply-length
280)
(defn- valid-reply?
[reply]
(<= (count reply) max-reply-length))
(defn- activity-reply-text-input
[reply-input on-update-reply]
[rn/view
[rn/view {:style {:margin-top 16
:margin-bottom 8
:flex-direction :row}}
[text/text {:weight :medium
:style {:flex-grow 1
:color colors/neutral-40}}
(i18n/label :t/your-answer)]
[text/text {:style {:flex-shrink 1
:color (if (valid-reply? @reply-input)
colors/neutral-40
colors/danger-60)}}
(str (count @reply-input) "/" max-reply-length)]]
[rn/view
;; TODO(@ilmotta): Replace with quo2 component when available.
;; https://github.com/status-im/status-mobile/issues/14364
[quo/text-input
{:on-change-text #(do (reset! reply-input %)
(when on-update-reply
(on-update-reply %)))
:auto-capitalize :none
:auto-focus true
:accessibility-label :identity-verification-reply-text-input
:placeholder (i18n/label :t/type-something)
:return-key-type :none
:multiline false
:auto-correct false}]]])
(defn- activity-icon
[icon]
[rn/view {:style style/icon}
[icon/icon icon {:color colors/white}]])
(defn- activity-context
[context replying?]
(let [first-line-offset (if replying? 4 0)
gap-between-lines 4]
(into [rn/view {:style (assoc style/context-container :margin-top first-line-offset)}]
(mapcat (fn [detail]
^{:key (hash detail)}
(if (string? detail)
(map (fn [s]
[rn/view {:style {:margin-right 4
:margin-top 0}}
[text/text {:size :paragraph-2}
s]])
(string/split detail #"\s+"))
[[rn/view {:margin-right 4
:margin-top gap-between-lines}
detail]]))
context))))
(defn- activity-message
[{:keys [title body]}]
[rn/view {:style style/message-container}
(when title
[text/text {:size :paragraph-2
:accessibility-label :activity-message-title
:style style/message-title}
title])
(if (string? body)
[text/text {:style style/message-body
:accessibility-label :activity-message-body
:size :paragraph-1}
body]
body)])
(defn- activity-buttons
[button-1 button-2 replying? reply-input]
(let [size (if replying? 40 24)
common-style (when replying?
{:padding-vertical 9
:flex-grow 1
:flex-basis 0})]
[rn/view style/buttons-container
(when button-1
[button/button (-> button-1
(assoc :size size)
(update :style merge common-style {:margin-right 8}))
(:label button-1)])
(when button-2
[button/button (-> button-2
(assoc :size size)
(assoc :disabled (and replying? (not (valid-reply? @reply-input))))
(update :style merge common-style))
(:label button-2)])]))
(defn- activity-status
[status]
[rn/view {:style style/status
:accessibility-label :activity-status}
[status-tags/status-tag {:size :small
:label (:label status)
:status status}]])
(defn- activity-title
[title replying?]
[text/text {:weight :semi-bold
:accessibility-label :activity-title
:style (style/title replying?)
:size (if replying? :heading-2 :paragraph-1)}
title])
(defn- activity-timestamp
[timestamp]
[text/text {:size :label
:accessibility-label :activity-timestamp
:style style/timestamp}
timestamp])
(defn- activity-unread-dot
[]
[rn/view {:accessibility-label :activity-unread-indicator
:style style/unread-dot-container}
[rn/view {:style style/unread-dot}]])
(defn- footer
[_]
(let [reply-input (reagent/atom "")]
(fn [{:keys [replying? on-update-reply status button-1 button-2]}]
[:<>
(when replying?
[activity-reply-text-input reply-input on-update-reply])
(cond (some? status)
[activity-status status]
(or button-1 button-2)
[activity-buttons button-1 button-2 replying? reply-input])])))
(defn view
[{:keys [icon
message
context
timestamp
title
replying?
unread?]
:as props}]
[rn/view {:accessibility-label :activity
:style style/container}
(when-not replying?
[activity-icon icon])
[rn/view {:style {:padding-left (when-not replying? 8)
:flex 1}}
[rn/view
[rn/view {:style style/top-section-container}
[activity-title title replying?]
(when-not replying?
[activity-timestamp timestamp])
(when (and unread? (not replying?))
[activity-unread-dot])]
(when context
[activity-context context replying?])]
(when message
[activity-message message])
[footer props]]])
@@ -1,157 +0,0 @@
(ns quo2.components.notifications.activity-logs
(:require [react-native.core :as rn]
[quo2.components.buttons.button :as button]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.tags.status-tags :as status-tags]
[quo2.foundations.colors :as colors]))
(defn- activity-icon
[icon]
[rn/view {:height 32
:width 32
:border-radius 100
:margin-top 10
:border-width 1
:border-color colors/white-opa-5
:flex-direction :column
:align-items :center
:justify-content :center}
[icon/icon icon {:color colors/white}]])
(defn- activity-unread-dot
[]
[rn/view {:margin-left 14
:margin-right 6
:background-color colors/primary-50
:width 8
:height 8
:border-radius 4}])
(defn- activity-context
[context]
(let [margin-top 4]
(into [rn/view {:flex 1
:flex-direction :row
:align-items :center
:flex-wrap :wrap
:margin-top (+ 4 (- margin-top))}]
(map-indexed (fn [index detail]
^{:key index}
[rn/view {:margin-right 4
:margin-top margin-top}
(if (string? detail)
[text/text {:size :paragraph-2}
detail]
detail)])
context))))
(defn- activity-message
[{:keys [title body]}]
[rn/view {:border-radius 12
:margin-top 12
:padding-horizontal 12
:padding-vertical 8
:background-color colors/white-opa-5
:flex 1
:flex-direction :column}
(when title
[text/text {:size :paragraph-2
:style {:color colors/white-opa-40}}
title])
(if (string? body)
[text/text {:style {:color colors/white}
:size :paragraph-1}
body]
body)])
(defn- activity-buttons
[button-1 button-2]
(let [size 24
common-style {:padding-top 3
:padding-right 8
:padding-bottom 4
:padding-left 8}]
[rn/view {:margin-top 12
:flex 1
:flex-direction :row
:align-items :flex-start}
(when button-1
[button/button (-> button-1
(assoc :size size)
(assoc-in [:style :margin-right] 8)
(update :style merge common-style))
(:label button-1)])
(when button-2
[button/button (-> button-2
(assoc :size size)
(update :style merge common-style))
(:label button-2)])]))
(defn- activity-status
[status]
[rn/view {:margin-top 12
:align-items :flex-start
:flex 1}
[status-tags/status-tag {:size :small
:label (:label status)
:status status}]])
(defn- activity-title
[title]
[text/text {:weight :semi-bold
:style {:color colors/white}
:size :paragraph-1}
title])
(defn- activity-timestamp
[timestamp]
[rn/view {:margin-left 8}
[text/text {:size :label
:style {:text-transform :none
:color colors/neutral-40}}
timestamp]])
(defn activity-log
[{:keys [button-1
button-2
icon
message
status
context
timestamp
title
unread?]}]
[rn/view {:flex-direction :row
:flex 1
:border-radius 16
:padding-top 8
:padding-horizontal 12
:padding-bottom 12
:background-color (when unread?
colors/primary-50-opa-10)}
[activity-icon icon]
[rn/view {:flex-direction :column
:padding-left 8
:flex 1}
[rn/view {:flex 1
:align-items :center
:flex-direction :row}
[rn/view {:flex 1
:align-items :center
:flex-direction :row}
[rn/view {:flex-shrink 1}
[activity-title title]]
[activity-timestamp timestamp]]
(when unread?
[activity-unread-dot])]
(when context
[activity-context context])
(when message
[activity-message message])
(cond
(some? status)
[activity-status status]
(or button-1 button-2)
[activity-buttons button-1 button-2])]])
@@ -10,6 +10,8 @@
:position :absolute
:right 22
:border-radius 6
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/primary-50 colors/primary-60)}
style)}
[rn/text {:style (merge typography/font-medium typography/label {:color colors/white :text-align :center})} count]]))
@@ -0,0 +1,14 @@
(ns quo2.components.selectors.--tests--.selectors-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.selectors.selectors :as selectors]
[reagent.core :as reagent]))
(defn render-toggle
([]
(rtl/render (reagent/as-element [selectors/toggle {:disabled? (:disabled? false)}]))))
(js/global.test "default render of toggle component"
(fn []
(render-toggle)
(-> (js/expect (rtl/screen.getByTestId "toggle-component"))
(.toBeTruthy))))
+2 -1
View File
@@ -133,7 +133,8 @@
:border-radius 20
:background-color (get-color @checked? disabled? blurred-background?)})
:accessibility-label (str "toggle-" (if @checked? "on" "off"))
:accessibility-role :checkbox}
:accessibility-role :checkbox
:testID "toggle-component"}
[rn/view {:style
{:margin-left (if @checked? 12 2)
:height 16
+20 -16
View File
@@ -3,7 +3,8 @@
[react-native.core :as rn]
[quo2.components.tabs.tab :as tab]
[reagent.core :as reagent]
[utils :as utils]
[utils.number :as utils.number]
[utils.collection :as utils.collection]
[quo2.foundations.colors :as colors]
[quo2.components.notifications.notification-dot :refer [notification-dot]]
[react-native.masked-view :as masked-view]
@@ -11,26 +12,29 @@
(def default-tab-size 32)
(defn indicator []
[rn/view {:position :absolute
:z-index 1
:right -2
:top -2
:width 10
:height 10
:border-radius 5
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
[notification-dot]])
(defn tabs [{:keys [default-active on-change style]}]
(let [active-tab-id (reagent/atom default-active)]
(fn [{:keys [data size] :or {size default-tab-size}}]
[rn/view (merge {:flex-direction :row} style)
(doall
(for [{:keys [label id new-info accessibility-label]} data]
(for [{:keys [label id notification-dot? accessibility-label]} data]
^{:key id}
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
(when new-info
[rn/view {:position :absolute
:z-index 1
:right -2
:top -2
:width 10
:height 10
:border-radius 5
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
[notification-dot]])
(when notification-dot?
[indicator])
[tab/tab
{:id id
:size size
@@ -50,7 +54,7 @@
;; Truncate to avoid unnecessary rendering.
(if (> fade-percentage 0.99)
0.99
(utils/naive-round fade-percentage 2))))
(utils.number/naive-round fade-percentage 2))))
(defn scrollable-tabs
"Just like the component `tabs`, displays horizontally scrollable tabs with
@@ -120,7 +124,7 @@
:scroll-on-press?
:size)
(when scroll-on-press?
{:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)})
{:initial-scroll-index (utils.collection/first-index #(= @active-tab-id (:id %)) data)})
{:ref #(reset! flat-list-ref %)
:extra-data (str @active-tab-id)
:horizontal true
+3 -2
View File
@@ -104,11 +104,12 @@
(defn tag
[_ _]
(fn [{:keys [locked tokens size background-color]
(fn [{:keys [locked tokens size background-color on-press]
:or {size 24}}]
[base-tag/base-tag {:background-color background-color
:size size
:type :permission}
:type :permission
:on-press on-press}
[rn/view {:flex-direction :row
:align-items :center
:justify-content :flex-end}
+19 -5
View File
@@ -28,12 +28,18 @@
quo2.components.messages.gap
quo2.components.messages.system-message
quo2.components.reactions.reaction
quo2.components.notifications.activity-logs
quo2.components.notifications.activity-log.view
quo2.components.notifications.info-count
quo2.components.notifications.notification-dot
quo2.components.tags.tags
quo2.components.tags.context-tags
quo2.components.tabs.tabs
quo2.components.tabs.account-selector))
quo2.components.tabs.account-selector
quo2.components.navigation.floating-shell-button
quo2.components.tags.status-tags
quo2.components.navigation.page-nav
quo2.components.selectors.disclaimer
quo2.components.selectors.selectors))
(def button quo2.components.buttons.button/button)
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
@@ -50,10 +56,17 @@
(def system-message quo2.components.messages.system-message/system-message)
(def reaction quo2.components.reactions.reaction/reaction)
(def tags quo2.components.tags.tags/tags)
(def user-avatar-tag quo2.components.tags.context-tags/user-avatar-tag)
(def context-tag quo2.components.tags.context-tags/context-tag)
(def group-avatar-tag quo2.components.tags.context-tags/group-avatar-tag)
(def tabs quo2.components.tabs.tabs/tabs)
(def scrollable-tabs quo2.components.tabs.tabs/scrollable-tabs)
(def account-selector quo2.components.tabs.account-selector/account-selector)
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
(def status-tag quo2.components.tags.status-tags/status-tag)
(def page-nav quo2.components.navigation.page-nav/page-nav)
(def disclaimer quo2.components.selectors.disclaimer/disclaimer)
(def checkbox quo2.components.selectors.selectors/checkbox)
;;;; AVATAR
(def account-avatar quo2.components.avatars.account-avatar/account-avatar)
(def channel-avatar quo2.components.avatars.channel-avatar/channel-avatar)
@@ -70,6 +83,7 @@
(def community-stats quo2.components.community.community-view/community-stats)
(def community-tags quo2.components.community.community-view/community-tags)
(def community-title quo2.components.community.community-view/community-title)
(def permission-tag-container quo2.components.community.community-view/permission-tag-container)
(def discover-card quo2.components.community.discover-card/discover-card)
;;;; DIVIDERS
@@ -82,6 +96,6 @@
(def preview-list quo2.components.list-items.preview-list/preview-list)
;;;; NOTIFICATIONS
(def activity-log quo2.components.notifications.activity-logs/activity-log)
(def activity-log quo2.components.notifications.activity-log.view/view)
(def info-count quo2.components.notifications.info-count/info-count)
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
+2
View File
@@ -0,0 +1,2 @@
(ns quo2.core-spec
(:require [quo2.components.selectors.--tests--.selectors-component-spec]))
+24 -2
View File
@@ -1,15 +1,19 @@
(ns react-native.core
(:require [reagent.core :as reagent]
["react-native" :as react-native]
[react-native.flat-list :as flat-list]))
["@react-native-community/blur" :as blur]
[react-native.flat-list :as flat-list]
[react-native.section-list :as section-list]
[react-native.platform :as platform]))
(def app-state ^js (.-AppState ^js react-native))
(def blur-view (reagent/adapt-react-class (.-BlurView blur)))
(def view (reagent/adapt-react-class (.-View ^js react-native)))
(def scroll-view (reagent/adapt-react-class (.-ScrollView ^js react-native)))
(def image (reagent/adapt-react-class (.-Image ^js react-native)))
(def text (reagent/adapt-react-class (.-Text ^js react-native)))
(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native)))
(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native)))
(def touchable-opacity (reagent/adapt-react-class (.-TouchableOpacity ^js react-native)))
(def touchable-highlight (reagent/adapt-react-class (.-TouchableHighlight ^js react-native)))
@@ -17,6 +21,8 @@
(def flat-list flat-list/flat-list)
(def section-list section-list/section-list)
(def activity-indicator (reagent/adapt-react-class (.-ActivityIndicator ^js react-native)))
(def modal (reagent/adapt-react-class (.-Modal ^js react-native)))
@@ -48,3 +54,19 @@
(defn get-window []
(js->clj (.get (.-Dimensions ^js react-native) "window") :keywordize-keys true))
(def status-bar (.-StatusBar ^js react-native))
(defn hw-back-add-listener [callback]
(.addEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
(defn hw-back-remove-listener [callback]
(.removeEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
(def keyboard-avoiding-view-class (reagent/adapt-react-class (.-KeyboardAvoidingView react-native)))
(defn keyboard-avoiding-view [props & children]
(into [keyboard-avoiding-view-class
(merge (when platform/ios? {:behavior :padding})
props)]
children))
+3
View File
@@ -27,6 +27,9 @@
(defn show-overlay [comp]
(.showOverlay Navigation (clj->js comp)))
(defn pop-to-root [tab]
(.popToRoot Navigation (clj->js tab)))
(defn dissmiss-overlay [comp]
(.catch (.dismissOverlay Navigation comp) #()))
+9 -1
View File
@@ -2,8 +2,9 @@
(:require ["react-native" :as rn]
[reagent.core :as reagent]
[clojure.string :as string]
["react-native-linear-gradient" :default LinearGradient]
["react-native-reanimated" :default reanimated
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring Easing Keyframe)]))
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe)]))
;; Animated Components
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
@@ -12,6 +13,8 @@
(def image (reagent/adapt-react-class (.-Image reanimated)))
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
(def linear-gradient (create-animated-component LinearGradient))
;; Hooks
(def use-shared-value useSharedValue)
(def use-animated-style useAnimatedStyle)
@@ -21,6 +24,7 @@
(def with-delay withDelay)
(def with-spring withSpring)
(def key-frame Keyframe)
(def with-repeat withRepeat)
;; Easings
(def bezier (.-bezier ^js Easing))
@@ -68,3 +72,7 @@
(defn animate-shared-value-with-delay [anim val duration easing delay]
(set-shared-value anim (with-delay delay (with-timing val (js-obj "duration" duration
"easing" (get easings easing))))))
(defn animate-shared-value-with-repeat [anim val duration easing number-of-repetitions reverse?]
(set-shared-value anim (with-repeat (with-timing val (js-obj "duration" duration
"easing" (get easings easing))) number-of-repetitions reverse?)))
+40
View File
@@ -0,0 +1,40 @@
(ns react-native.section-list
(:require [reagent.core :as reagent]
[react-native.flat-list :as flat-list]
["react-native" :as react-native]))
(def section-list-class (reagent/adapt-react-class (.-SectionList react-native)))
(def memo-wrap-render-fn
(memoize
(fn [f render-data]
(fn [^js data]
(reagent/as-element [f (.-item data) (.-index data) (.-separators data) render-data])))))
(defn- wrap-render-section-header-fn [f]
(fn [^js data]
(let [^js section (.-section data)]
(reagent/as-element [f {:title (.-title section)
:data (.-data section)}]))))
(defn- wrap-per-section-render-fn [props]
(update
(if-let [f (:render-fn props)]
(assoc (dissoc props :render-fn :render-data) :renderItem (memo-wrap-render-fn f (:render-data props)))
props)
:data to-array))
(defn section-list
"A wrapper for SectionList.
To render something on empty sections, use renderSectionFooter and conditionaly
render on empty data
See https://facebook.github.io/react-native/docs/sectionlist.html"
[{:keys [sections render-section-header-fn render-section-footer-fn style] :as props}]
[section-list-class
(merge (flat-list/base-list-props props)
props
(when render-section-footer-fn
{:renderSectionFooter (wrap-render-section-header-fn render-section-footer-fn)})
{:sections (clj->js (map wrap-per-section-render-fn sections))
:renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)
:style style})])
+113 -33
View File
@@ -6,6 +6,34 @@
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
(def defaults
{:filter-status :unread
:filter-type types/no-type
;; Choose the maximum number of notifications that *usually/safely* fit on
;; most screens, so that the UI doesn't have to needlessly render
;; notifications.
:notifications-per-page 8})
;;;; Navigation
(fx/defn open-activity-center
{:events [:activity-center/open]}
[_]
(rf/dispatch [:show-popover {:view :activity-center
:style {:margin 0}
:disable-touchable-overlay? true
:blur-view? true
:blur-view-props {:blur-amount 20
:blur-type :dark}}]))
;;;; Misc
(fx/defn process-notification-failure
{:events [:activity-center/process-notification-failure]}
[_ notification-id action error]
(log/warn (str "Failed to " action)
{:notification-id notification-id :error error}))
;;;; Notification reconciliation
(defn- update-notifications
@@ -18,8 +46,7 @@
~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)
remove-notification (fn [data]
(let [remove-notification (fn [data]
(remove #(= id (:id %)) data))
insert-and-sort (fn [data]
(->> notification
@@ -27,14 +54,17 @@
(sort-by (juxt :timestamp :id))
reverse))]
(as-> acc $
(update-in $ [type :read :data] remove-notification)
(update-in $ [type :all :data] remove-notification)
(update-in $ [types/no-type :all :data] remove-notification)
(update-in $ [type :unread :data] remove-notification)
(update-in $ [types/no-type :read :data] remove-notification)
(update-in $ [types/no-type :unread :data] remove-notification)
(if (or (:dismissed notification) (:accepted notification))
$
(-> $ (update-in [type filter-status :data] insert-and-sort)
(update-in [types/no-type filter-status :data] insert-and-sort))))))
(cond-> (-> $
(update-in [type :all :data] insert-and-sort)
(update-in [types/no-type :all :data] insert-and-sort))
(not read) (update-in [type :unread :data] insert-and-sort)
(not read) (update-in [types/no-type :unread :data] insert-and-sort))))))
db-notifications
new-notifications))
@@ -45,39 +75,91 @@
{:db (update-in db [:activity-center :notifications]
update-notifications new-notifications)}))
;;;; Contact verification
(fx/defn contact-verification-decline
{:events [:activity-center.contact-verification/decline]}
[_ contact-verification-id]
{::json-rpc/call [{:method "wakuext_declineContactVerificationRequest"
:params [contact-verification-id]
:on-success #(rf/dispatch [:activity-center.contact-verification/decline-success %])
:on-error #(rf/dispatch [:activity-center.contact-verification/decline-error contact-verification-id %])}]})
(fx/defn contact-verification-decline-success
{:events [:activity-center.contact-verification/decline-success]}
(fx/defn notifications-reconcile-from-response
{:events [:activity-center/reconcile-notifications-from-response]}
[cofx response]
(->> response
:activityCenterNotifications
(map data-store.activities/<-rpc)
(notifications-reconcile cofx)))
(fx/defn contact-verification-decline-error
{:events [:activity-center.contact-verification/decline-error]}
[_ contact-verification-id error]
(log/warn "Failed to decline contact verification"
{:contact-verification-id contact-verification-id
:error error})
nil)
;;;; Mark notifications as read
(defn- get-notification
[db notification-id]
(->> (get-in db [:activity-center
:notifications
(get-in db [:activity-center :filter :type])
(get-in db [:activity-center :filter :status])
:data])
(filter #(= notification-id (:id %)))
first))
(fx/defn mark-as-read
{:events [:activity-center.notifications/mark-as-read]}
[{:keys [db]} notification-id]
(when-let [notification (get-notification db notification-id)]
{::json-rpc/call [{:method "wakuext_markActivityCenterNotificationsRead"
:params [[notification-id]]
:on-success #(rf/dispatch [:activity-center.notifications/mark-as-read-success notification])
:on-error #(rf/dispatch [:activity-center/process-notification-failure
notification-id
:notification/mark-as-read
%])}]}))
(fx/defn mark-as-read-success
{:events [:activity-center.notifications/mark-as-read-success]}
[cofx notification]
(notifications-reconcile cofx [(assoc notification :read true)]))
;;;; Contact verification
(fx/defn contact-verification-decline
{:events [:activity-center.contact-verification/decline]}
[_ notification-id]
{::json-rpc/call [{:method "wakuext_declineContactVerificationRequest"
:params [notification-id]
:on-success #(rf/dispatch [:activity-center/reconcile-notifications-from-response %])
:on-error #(rf/dispatch [:activity-center/process-notification-failure
notification-id
:contact-verification/decline
%])}]})
(fx/defn contact-verification-reply
{:events [:activity-center.contact-verification/reply]}
[_ notification-id reply]
{::json-rpc/call [{:method "wakuext_acceptContactVerificationRequest"
:params [notification-id reply]
:on-success #(rf/dispatch [:activity-center/reconcile-notifications-from-response %])
:on-error #(rf/dispatch [:activity-center/process-notification-failure
notification-id
:contact-verification/reply
%])}]})
(fx/defn contact-verification-mark-as-trusted
{:events [:activity-center.contact-verification/mark-as-trusted]}
[_ notification-id]
{::json-rpc/call [{:method "wakuext_verifiedTrusted"
:params [{:id notification-id}]
:on-success #(rf/dispatch [:activity-center/reconcile-notifications-from-response %])
:on-error #(rf/dispatch [:activity-center/process-notification-failure
notification-id
:contact-verification/mark-as-trusted
%])}]})
(fx/defn contact-verification-mark-as-untrustworthy
{:events [:activity-center.contact-verification/mark-as-untrustworthy]}
[_ notification-id]
{::json-rpc/call [{:method "wakuext_verifiedUntrustworthy"
:params [{:id notification-id}]
:on-success #(rf/dispatch [:activity-center/reconcile-notifications-from-response %])
:on-error #(rf/dispatch [:activity-center/process-notification-failure
notification-id
:contact-verification/mark-as-untrustworthy
%])}]})
;;;; Notifications fetching and pagination
(def defaults
{:filter-status :unread
:filter-type types/no-type
:notifications-per-page 10})
(def start-or-end-cursor
"")
@@ -86,15 +168,13 @@
(and (some? cursor)
(not= cursor start-or-end-cursor)))
(def ^:const status-read 1)
(def ^:const status-unread 2)
(def ^:const status-all 3)
(defn status [filter-status]
(case filter-status
:read status-read
:unread status-unread
:all status-all
:all status-all
99))
(fx/defn notifications-fetch
+295 -269
View File
@@ -3,98 +3,228 @@
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
[status-im.activity-center.notification-types :as types]
[status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
status-im.events
[status-im.test-helpers :as h]
[status-im.utils.config :as config]))
[status-im2.setup.config :as config]))
(def notification-id "0x1")
(defn setup []
(h/register-helper-events)
(rf/dispatch [:setup/app-started]))
(defn test-log-on-failure
[{:keys [before-test notification-id event action]}]
(rf-test/run-test-sync
(setup)
(h/using-log-test-appender
(fn [logs]
(when before-test
(before-test))
(h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error))
(rf/dispatch event)
(is (= {:args [(str "Failed to " action)
{:notification-id notification-id
:error :fake-error}]
:level :warn}
(last @logs)))))))
;;;; Misc
(deftest mark-as-read-test
(testing "does nothing if the notification ID cannot be found in the app db"
(rf-test/run-test-sync
(setup)
(let [spy-queue (atom [])]
(h/spy-fx spy-queue ::json-rpc/call)
(let [notifications {types/one-to-one-chat
{:all {:cursor "" :data [{:id notification-id
:read false
:type types/one-to-one-chat}]}
:unread {:cursor "" :data []}}}]
(rf/dispatch [:test/assoc-in [:activity-center]
{:notifications notifications
:filter {:type types/one-to-one-chat
:status :all}}])
(rf/dispatch [:activity-center.notifications/mark-as-read "0x666"])
(is (= [] @spy-queue))
(is (= notifications (get-in (h/db) [:activity-center :notifications])))))))
(testing "marks notifications as read and updates app db"
(rf-test/run-test-sync
(setup)
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
notif-2 {:id "0x2" :read false :type types/one-to-one-chat}
notif-3 {:id "0x3" :read false :type types/one-to-one-chat}
new-notif-3 (assoc notif-3 :read true)
new-notif-2 (assoc notif-2 :read true)]
(h/stub-fx-with-callbacks ::json-rpc/call :on-success (constantly nil))
(rf/dispatch [:test/assoc-in [:activity-center]
{:notifications {types/one-to-one-chat
{:all {:cursor "" :data [notif-3 notif-2 notif-1]}
:unread {:cursor "" :data [notif-3 notif-2]}}}
:filter {:type types/one-to-one-chat
:status :unread}}])
(rf/dispatch [:activity-center.notifications/mark-as-read (:id notif-2)])
(is (= {types/one-to-one-chat
{:all {:cursor "" :data [notif-3 new-notif-2 notif-1]}
:unread {:cursor "" :data [notif-3]}}
types/no-type
{:all {:data [new-notif-2]}
:unread {:data []}}}
(get-in (h/db) [:activity-center :notifications])))
(rf/dispatch [:activity-center.notifications/mark-as-read (:id notif-3)])
(is (= {types/one-to-one-chat
{:all {:cursor "" :data [new-notif-3 new-notif-2 notif-1]}
:unread {:cursor "" :data []}}
types/no-type
{:all {:data [new-notif-3 new-notif-2]}
:unread {:data []}}}
(get-in (h/db) [:activity-center :notifications]))))))
(testing "logs on failure"
(test-log-on-failure
{:notification-id notification-id
:event [:activity-center.notifications/mark-as-read notification-id]
:action :notification/mark-as-read
:before-test (fn []
(rf/dispatch [:test/assoc-in [:activity-center]
{:notifications {types/one-to-one-chat
{:all {:cursor "" :data [{:id notification-id
:read false
:type types/one-to-one-chat}]}
:unread {:cursor "" :data []}}}
:filter {:type types/one-to-one-chat
:status :all}}]))})))
;;;; Contact verification
(def contact-verification-rpc-response
{:activityCenterNotifications
[{:accepted false
:author "0x04d03f"
:chatId "0x04d03f"
:contactVerificationStatus constants/contact-verification-status-pending
:dismissed false
:id notification-id
:message {}
:name "0x04d03f"
:read true
:timestamp 1666647286000
:type types/contact-verification}]})
(def contact-verification-expected-notification
{:accepted false
:author "0x04d03f"
:chat-id "0x04d03f"
:contact-verification-status constants/contact-verification-status-pending
:dismissed false
:id notification-id
:last-message nil
:message {:command-parameters nil
:content {:chat-id nil
:ens-name nil
:image nil
:line-count nil
:links nil
:parsed-text nil
:response-to nil
:rtl? nil
:sticker nil
:text nil}
:outgoing false
:outgoing-status nil
:quoted-message nil}
:name "0x04d03f"
:read true
:reply-message nil
:timestamp 1666647286000
:type types/contact-verification})
(defn test-contact-verification-event
[{:keys [event expected-rpc-call]}]
(rf-test/run-test-sync
(setup)
(let [spy-queue (atom [])]
(h/stub-fx-with-callbacks ::json-rpc/call :on-success (constantly contact-verification-rpc-response))
(h/spy-fx spy-queue ::json-rpc/call)
(rf/dispatch event)
(is (= {types/no-type
{:all {:data [contact-verification-expected-notification]}
:unread {:data []}}
types/contact-verification
{:all {:data [contact-verification-expected-notification]}
:unread {:data []}}}
(get-in (h/db) [:activity-center :notifications])))
(is (= expected-rpc-call
(-> @spy-queue
(get-in [0 :args 0])
(select-keys [:method :params])))))))
(deftest contact-verification-decline-test
(with-redefs [config/new-activity-center-enabled? true]
(testing "successfully declines and reconciles returned notification"
(rf-test/run-test-sync
(setup)
(let [spy-queue (atom [])
contact-verification-id 24
expected-notification {:accepted false
:author "0x04d03f"
:chat-id "0x04d03f"
:contact-verification-status 3
:dismissed false
:id 24
:last-message nil
:message {:command-parameters nil
:content {:chat-id nil
:ens-name nil
:image nil
:line-count nil
:links nil
:parsed-text nil
:response-to nil
:rtl? nil
:sticker nil
:text nil}
:outgoing false
:outgoing-status nil
:quoted-message nil}
:name "0x04d03f"
:read true
:reply-message nil
:timestamp 1666647286000
:type types/contact-verification}]
(h/stub-fx-with-callbacks
::json-rpc/call
:on-success (constantly {:activityCenterNotifications
[{:accepted false
:author "0x04d03f"
:chatId "0x04d03f"
:contactVerificationStatus 3
:dismissed false
:id contact-verification-id
:message {}
:name "0x04d03f"
:read true
:timestamp 1666647286000
:type types/contact-verification}]}))
(testing "declines notification and reconciles"
(test-contact-verification-event
{:event [:activity-center.contact-verification/decline notification-id]
:expected-rpc-call {:method "wakuext_declineContactVerificationRequest"
:params [notification-id]}}))
(testing "logs on failure"
(test-log-on-failure
{:notification-id notification-id
:event [:activity-center.contact-verification/decline notification-id]
:action :contact-verification/decline}))))
(h/spy-fx spy-queue ::json-rpc/call)
(deftest contact-verification-reply-test
(with-redefs [config/new-activity-center-enabled? true]
(testing "sends reply and reconciles"
(let [reply "any answer"]
(test-contact-verification-event
{:event [:activity-center.contact-verification/reply notification-id reply]
:expected-rpc-call {:method "wakuext_acceptContactVerificationRequest"
:params [notification-id reply]}})))
(testing "logs on failure"
(test-log-on-failure
{:notification-id notification-id
:event [:activity-center.contact-verification/reply notification-id "any answer"]
:action :contact-verification/reply}))))
(rf/dispatch [:activity-center.contact-verification/decline contact-verification-id])
(deftest contact-verification-mark-as-trusted-test
(with-redefs [config/new-activity-center-enabled? true]
(testing "marks notification as trusted and reconciles"
(test-contact-verification-event
{:event [:activity-center.contact-verification/mark-as-trusted notification-id]
:expected-rpc-call {:method "wakuext_verifiedTrusted"
:params [{:id notification-id}]}}))
(testing "logs on failure"
(test-log-on-failure
{:notification-id notification-id
:event [:activity-center.contact-verification/mark-as-trusted notification-id]
:action :contact-verification/mark-as-trusted}))))
(is (= {:method "wakuext_declineContactVerificationRequest"
:params [contact-verification-id]}
(-> @spy-queue
(get-in [0 :args 0])
(select-keys [:method :params]))))
(is (= {types/no-type
{:read {:data [expected-notification]}
:unread {:data []}}
types/contact-verification
{:read {:data [expected-notification]}
:unread {:data []}}}
(get-in (h/db) [:activity-center :notifications]))))))
(testing "logs failure"
(rf-test/run-test-sync
(setup)
(let [contact-verification-id 666]
(h/using-log-test-appender
(fn [logs]
(h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error))
(rf/dispatch [:activity-center.contact-verification/decline contact-verification-id])
(is (= {:args ["Failed to decline contact verification"
{:contact-verification-id contact-verification-id
:error :fake-error}]
:level :warn}
(last @logs))))))))))
(deftest contact-verification-mark-as-untrustworthy-test
(with-redefs [config/new-activity-center-enabled? true]
(testing "marks notification as untrustworthy and reconciles"
(test-contact-verification-event
{:event [:activity-center.contact-verification/mark-as-untrustworthy notification-id]
:expected-rpc-call {:method "wakuext_verifiedUntrustworthy"
:params [{:id notification-id}]}}))
(testing "logs on failure"
(test-log-on-failure
{:notification-id notification-id
:event [:activity-center.contact-verification/mark-as-untrustworthy notification-id]
:action :contact-verification/mark-as-untrustworthy}))))
;;;; Notification reconciliation
@@ -104,12 +234,12 @@
(rf-test/run-test-sync
(setup)
(let [notifications {types/one-to-one-chat
{:read {:cursor ""
{:all {:cursor ""
:data [{:id "0x1"
:read true
:type types/one-to-one-chat}
{:id "0x2"
:read true
:read false
:type types/one-to-one-chat}]}
:unread {:cursor ""
:data [{:id "0x3"
@@ -129,216 +259,112 @@
(testing "removes dismissed or accepted notifications"
(rf-test/run-test-sync
(setup)
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
{types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x1" :read true :type types/one-to-one-chat}
{:id "0x2" :read true :type types/one-to-one-chat}]}
:unread {:cursor ""
:data [{:id "0x3" :read false :type types/one-to-one-chat}]}}
types/private-group-chat
{:unread {:cursor ""
:data [{:id "0x4" :read false :type types/private-group-chat}
{:id "0x6" :read false :type types/private-group-chat}]}}}])
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
notif-2 {:id "0x2" :read false :type types/one-to-one-chat}
notif-3 {:id "0x3" :read false :type types/one-to-one-chat}
notif-4 {:id "0x4" :read false :type types/private-group-chat}
notif-5 {:id "0x5" :read true :type types/private-group-chat}
notif-6 {:id "0x6" :read false :type types/private-group-chat}]
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
{types/one-to-one-chat
{:all {:cursor "" :data [notif-1 notif-2]}
:unread {:cursor "" :data [notif-3]}}
types/private-group-chat
{:unread {:cursor "" :data [notif-4 notif-6]}}}])
(rf/dispatch [:activity-center.notifications/reconcile
[{:id "0x1"
:read true
:type types/one-to-one-chat
:dismissed true}
{:id "0x3"
:read false
:type types/one-to-one-chat
:accepted true}
{:id "0x4"
:read false
:type types/private-group-chat
:dismissed true}
{:id "0x5"
:read false
:type types/private-group-chat
:accepted true}]])
(rf/dispatch [:activity-center.notifications/reconcile
[(assoc notif-1 :dismissed true)
(assoc notif-3 :accepted true)
(assoc notif-4 :dismissed true)
notif-5]])
(is (= {types/no-type
{:read {:data []}
:unread {:data []}}
types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x2"
:read true
:type types/one-to-one-chat}]}
:unread {:cursor ""
:data []}}
types/private-group-chat
{:read {:data []}
:unread {:cursor ""
:data [{:id "0x6"
:read false
:type types/private-group-chat}]}}}
(get-in (h/db) [:activity-center :notifications])))))
(is (= {types/no-type
{:all {:data [notif-5]}
:unread {:data []}}
types/one-to-one-chat
{:all {:cursor "" :data [notif-2]}
:unread {:cursor "" :data []}}
types/private-group-chat
{:all {:data [notif-5]}
:unread {:cursor "" :data [notif-6]}}}
(get-in (h/db) [:activity-center :notifications]))))))
(testing "replaces old notifications with newly arrived ones"
(rf-test/run-test-sync
(setup)
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
{types/no-type
{:read {:cursor ""
:data [{:id "0x1"
:read true
:type types/one-to-one-chat}]}
:unread {:cursor ""
:data [{:id "0x4"
:read false
:type types/private-group-chat}
{:id "0x6"
:read false
:type types/private-group-chat}]}}
types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x1"
:read true
:type types/one-to-one-chat}]}}
types/private-group-chat
{:unread {:cursor ""
:data [{:id "0x4"
:read false
:type types/private-group-chat}
{:id "0x6"
:read false
:type types/private-group-chat}]}}}])
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
notif-4 {:id "0x4" :read false :type types/private-group-chat}
notif-6 {:id "0x6" :read false :type types/private-group-chat}
new-notif-1 (assoc notif-1 :last-message {})
new-notif-4 (assoc notif-4 :author "0xabc")]
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
{types/no-type
{:all {:cursor "" :data [notif-1]}
:unread {:cursor "" :data [notif-4 notif-6]}}
types/one-to-one-chat
{:all {:cursor "" :data [notif-1]}}
types/private-group-chat
{:unread {:cursor "" :data [notif-4 notif-6]}}}])
(rf/dispatch [:activity-center.notifications/reconcile
[{:id "0x1"
:read true
:type types/one-to-one-chat
:last-message {}}
{:id "0x4"
:read false
:type types/private-group-chat
:author "0xabc"}
{:id "0x6"
:read false
:type types/private-group-chat}]])
(rf/dispatch [:activity-center.notifications/reconcile [new-notif-1 new-notif-4 notif-6]])
(is (= {types/no-type
{:read {:cursor ""
:data [{:id "0x1"
:read true
:type types/one-to-one-chat
:last-message {}}]}
:unread {:cursor ""
:data [{:id "0x6"
:read false
:type types/private-group-chat}
{:id "0x4"
:read false
:type types/private-group-chat
:author "0xabc"}]}}
types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x1"
:read true
:type types/one-to-one-chat
:last-message {}}]}
:unread {:data []}}
types/private-group-chat
{:read {:data []}
:unread {:cursor ""
:data [{:id "0x6"
:read false
:type types/private-group-chat}
{:id "0x4"
:read false
:type types/private-group-chat
:author "0xabc"}]}}}
(get-in (h/db) [:activity-center :notifications])))))
(is (= {types/no-type
{:all {:cursor "" :data [notif-6 new-notif-4 new-notif-1]}
:unread {:cursor "" :data [notif-6 new-notif-4]}}
types/one-to-one-chat
{:all {:cursor "" :data [new-notif-1]}
:unread {:data []}}
types/private-group-chat
{:all {:data [notif-6 new-notif-4]}
:unread {:cursor "" :data [notif-6 new-notif-4]}}}
(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]
{types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x1"
:read true
:type types/one-to-one-chat}]}}}])
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat}
new-notif-1 (assoc notif-1 :read false)]
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
{types/one-to-one-chat
{:all {:cursor "" :data [notif-1]}}}])
(rf/dispatch [:activity-center.notifications/reconcile
[{:id "0x1"
:read false
:type types/one-to-one-chat}]])
(rf/dispatch [:activity-center.notifications/reconcile [new-notif-1]])
(is (= {types/no-type
{:read {:data []}
:unread {:data [{:id "0x1"
:read false
:type types/one-to-one-chat}]}}
(is (= {types/no-type
{:all {:data [new-notif-1]}
:unread {:data [new-notif-1]}}
types/one-to-one-chat
{:read {:cursor ""
:data []}
:unread {:data [{:id "0x1"
:read false
:type types/one-to-one-chat}]}}}
(get-in (h/db) [:activity-center :notifications])))))
types/one-to-one-chat
{:all {:cursor "" :data [new-notif-1]}
:unread {:data [new-notif-1]}}}
(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]
{types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x1" :read true :type types/one-to-one-chat :timestamp 1}
{:id "0x2" :read true :type types/one-to-one-chat :timestamp 1}]}
:unread {:cursor ""
:data [{:id "0x3" :read false :type types/one-to-one-chat :timestamp 50}
{:id "0x4" :read false :type types/one-to-one-chat :timestamp 100}
{:id "0x5" :read false :type types/one-to-one-chat :timestamp 100}]}}}])
(let [notif-1 {:id "0x1" :read true :type types/one-to-one-chat :timestamp 1}
notif-2 {:id "0x2" :read true :type types/one-to-one-chat :timestamp 1}
notif-3 {:id "0x3" :read false :type types/one-to-one-chat :timestamp 50}
notif-4 {:id "0x4" :read false :type types/one-to-one-chat :timestamp 100}
notif-5 {:id "0x5" :read false :type types/one-to-one-chat :timestamp 100}
new-notif-1 (assoc notif-1 :last-message {})
new-notif-4 (assoc notif-4 :last-message {})]
(rf/dispatch [:test/assoc-in [:activity-center :notifications]
{types/one-to-one-chat
{:all {:cursor "" :data [notif-1 notif-2]}
:unread {:cursor "" :data [notif-3 notif-4 notif-5]}}}])
(rf/dispatch [:activity-center.notifications/reconcile
[{:id "0x1" :read true :type types/one-to-one-chat :timestamp 1 :last-message {}}
{:id "0x4" :read false :type types/one-to-one-chat :timestamp 100 :last-message {}}]])
(rf/dispatch [:activity-center.notifications/reconcile [new-notif-1 new-notif-4]])
(is (= {types/no-type
{:read {:data [{:id "0x1"
:read true
:type types/one-to-one-chat
:timestamp 1
:last-message {}}]}
:unread {:data [{:id "0x4"
:read false
:type types/one-to-one-chat
:timestamp 100
:last-message {}}]}}
types/one-to-one-chat
{:read {:cursor ""
:data [{:id "0x2"
:read true
:type types/one-to-one-chat
:timestamp 1}
{:id "0x1"
:read true
:type types/one-to-one-chat
:timestamp 1
:last-message {}}]}
:unread {:cursor ""
:data [{:id "0x5"
:read false
:type types/one-to-one-chat
:timestamp 100}
{:id "0x4"
:read false
:type types/one-to-one-chat
:timestamp 100
:last-message {}}
{:id "0x3"
:read false
:type types/one-to-one-chat
:timestamp 50}]}}}
(get-in (h/db) [:activity-center :notifications])))))))
(is (= {types/no-type
{:all {:data [new-notif-4 new-notif-1]}
:unread {:data [new-notif-4]}}
types/one-to-one-chat
{:all {:cursor "" :data [new-notif-4 notif-2 new-notif-1]}
:unread {:cursor "" :data [notif-5 new-notif-4 notif-3]}}}
(get-in (h/db) [:activity-center :notifications]))))))))
;;;; Notifications fetching and pagination
@@ -456,12 +482,12 @@
(let [spy-queue (atom [])]
(h/spy-fx spy-queue ::json-rpc/call)
(rf/dispatch [:test/assoc-in [:activity-center :filter :status]
:read])
:all])
(rf/dispatch [:test/assoc-in [:activity-center :filter :type]
types/one-to-one-chat])
(rf/dispatch [:test/assoc-in [:activity-center :notifications types/one-to-one-chat :read :cursor]
(rf/dispatch [:test/assoc-in [:activity-center :notifications types/one-to-one-chat :all :cursor]
"10"])
(rf/dispatch [:test/assoc-in [:activity-center :notifications types/one-to-one-chat :read :loading?]
(rf/dispatch [:test/assoc-in [:activity-center :notifications types/one-to-one-chat :all :loading?]
true])
(rf/dispatch [:activity-center.notifications/fetch-next-page])
@@ -6,7 +6,7 @@
(def ^:const mention 3)
(def ^:const reply 4)
(def ^:const contact-request 5)
(def ^:const contact-verification 6)
(def ^:const contact-verification 10)
;; TODO: Remove this constant once the old Notification Center code is removed.
;; Its value clashes with the new constant `-contact-verification`
+1 -1
View File
@@ -22,7 +22,7 @@
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.browser.webview-ref :as webview-ref]
["eth-phishing-detect" :as eth-phishing-detect]
[status-im.utils.debounce :as debounce]
[utils.debounce :as debounce]
[status-im.browser.eip3085 :as eip3085]
[status-im.browser.eip3326 :as eip3326]))
+10 -4
View File
@@ -265,12 +265,18 @@
(fx/defn navigate-to-chat-nav2
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
{:events [:chat.ui/navigate-to-chat-nav2]}
[{db :db :as cofx} chat-id from-switcher?]
[{db :db :as cofx} chat-id from-shell?]
(fx/merge cofx
{:db (assoc db :current-chat-id chat-id)}
(offload-messages chat-id)
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
(when-not (= (:view-id db) :community)
(navigation/pop-to-root-tab :shell-stack))
(close-chat)
(force-close-chat chat-id)
(fn [{:keys [db]}]
{:db (assoc db :current-chat-id chat-id)})
(preload-chat-data chat-id)
(navigation/navigate-to-nav2 :chat chat-id nil from-switcher?)))
#(when (group-chat? cofx chat-id)
(loading/load-chat % chat-id))))
(fx/defn handle-clear-history-response
{:events [::history-cleared]}
+78 -66
View File
@@ -20,19 +20,19 @@
(defn- resize-and-call [uri cb]
(react/image-get-size
uri
(fn [width height]
(let [resize? (> (max width height) maximum-image-size-px)]
(image-processing/resize
uri
(if resize? maximum-image-size-px width)
(if resize? maximum-image-size-px height)
60
(fn [^js resized-image]
(let [path (.-path resized-image)
path (if (string/starts-with? path "file") path (str "file://" path))]
(cb path)))
#(log/error "could not resize image" %))))))
uri
(fn [width height]
(let [resize? (> (max width height) maximum-image-size-px)]
(image-processing/resize
uri
(if resize? maximum-image-size-px width)
(if resize? maximum-image-size-px height)
60
(fn [^js resized-image]
(let [path (.-path resized-image)
path (if (string/starts-with? path "file") path (str "file://" path))]
(cb path)))
#(log/error "could not resize image" %))))))
(defn result->id [^js result]
(if platform/ios?
@@ -43,7 +43,7 @@
(defn download-image-http [base64-uri on-success]
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?
:path temp-image-url}))
:path temp-image-url}))
(.fetch "GET" base64-uri)
(.then #(on-success (.path %)))
(.catch #(log/error "could not save image"))))
@@ -51,62 +51,64 @@
(defn save-to-gallery [path] (.save CameraRoll path))
(re-frame/reg-fx
::save-image-to-gallery
(fn [base64-uri]
(if platform/ios?
(-> (download-image-http base64-uri save-to-gallery)
(.catch #(utils/show-popup (i18n/label :t/error)
(i18n/label :t/external-storage-denied))))
(permissions/request-permissions
{:permissions [:write-external-storage]
:on-allowed #(download-image-http base64-uri save-to-gallery)
:on-denied (fn []
(utils/set-timeout
#(utils/show-popup (i18n/label :t/error)
(i18n/label :t/external-storage-denied))
50))}))))
::save-image-to-gallery
(fn [base64-uri]
(if platform/ios?
(-> (download-image-http base64-uri save-to-gallery)
(.catch #(utils/show-popup (i18n/label :t/error)
(i18n/label :t/external-storage-denied))))
(permissions/request-permissions
{:permissions [:write-external-storage]
:on-allowed #(download-image-http base64-uri save-to-gallery)
:on-denied (fn []
(utils/set-timeout
#(utils/show-popup (i18n/label :t/error)
(i18n/label :t/external-storage-denied))
50))}))))
(re-frame/reg-fx
::chat-open-image-picker-camera
(fn [current-chat-id]
(react/show-image-picker-camera
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)]) {})))
::chat-open-image-picker-camera
(fn [current-chat-id]
(react/show-image-picker-camera
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)]) {})))
(re-frame/reg-fx
::chat-open-image-picker
(fn [chat-id]
(react/show-image-picker
(fn [^js images]
;; NOTE(Ferossgp): Because we can't highlight the already selected images inside
;; gallery, we just clean previous state and set all newly picked images
(when (and platform/ios? (pos? (count images)))
(re-frame/dispatch [:chat.ui/clear-sending-images chat-id]))
(doseq [^js result (if platform/ios?
(take config/max-images-batch images)
[images])]
(resize-and-call (.-path result)
#(re-frame/dispatch [:chat.ui/image-selected chat-id (result->id result) %]))))
;; NOTE(Ferossgp): On android you cannot set max limit on images, when a user
;; selects too many images the app crashes.
{:media-type "photo"
:multiple platform/ios?})))
::chat-open-image-picker
(fn [chat-id]
(react/show-image-picker
(fn [^js images]
;; NOTE(Ferossgp): Because we can't highlight the already selected images inside
;; gallery, we just clean previous state and set all newly picked images
(when (and platform/ios? (pos? (count images)))
(re-frame/dispatch [:chat.ui/clear-sending-images chat-id]))
(doseq [^js result (if platform/ios?
(take config/max-images-batch images)
[images])]
(resize-and-call (.-path result)
#(re-frame/dispatch [:chat.ui/image-selected chat-id (result->id result) %]))))
;; NOTE(Ferossgp): On android you cannot set max limit on images, when a user
;; selects too many images the app crashes.
{:media-type "photo"
:multiple platform/ios?})))
(re-frame/reg-fx
::image-selected
(fn [[uri chat-id]]
(resize-and-call
uri
#(re-frame/dispatch [:chat.ui/image-selected chat-id uri %]))))
::image-selected
(fn [[uri chat-id]]
(resize-and-call
uri
#(re-frame/dispatch [:chat.ui/image-selected chat-id uri %]))))
(re-frame/reg-fx
::camera-roll-get-photos
(fn [num]
(permissions/request-permissions
{:permissions [:read-external-storage]
:on-allowed (fn []
(-> (.getPhotos CameraRoll #js {:first num :assetType "Photos" :groupTypes "All"})
(.then #(re-frame/dispatch [:on-camera-roll-get-photos (:edges (types/js->clj %))]))
(.catch #(log/warn "could not get cameraroll photos"))))})))
::camera-roll-get-photos
(fn [[num end-cursor]]
(permissions/request-permissions
{:permissions [:read-external-storage]
:on-allowed (fn []
(-> (if end-cursor
(.getPhotos CameraRoll #js {:first num :after end-cursor :assetType "Photos" :groupTypes "All"})
(.getPhotos CameraRoll #js {:first num :assetType "Photos" :groupTypes "All"}))
(.then #(re-frame/dispatch [:on-camera-roll-get-photos (:edges (types/js->clj %)) (:page_info (types/js->clj %)) end-cursor]))
(.catch #(log/warn "could not get camera roll photos"))))})))
(fx/defn image-captured
{:events [:chat.ui/image-captured]}
@@ -119,13 +121,23 @@
(fx/defn camera-roll-get-photos
{:events [:chat.ui/camera-roll-get-photos]}
[_ num]
{::camera-roll-get-photos num})
[_ num end-cursor]
{::camera-roll-get-photos [num end-cursor]})
(fx/defn camera-roll-loading-more
{:events [:chat.ui/camera-roll-loading-more]}
[{:keys [db]} is-loading]
{:db (assoc db :camera-roll-loading-more is-loading)})
(fx/defn on-camera-roll-get-photos
{:events [:on-camera-roll-get-photos]}
[{db :db} photos]
{:db (assoc db :camera-roll-photos (mapv #(get-in % [:node :image :uri]) photos))})
[{:keys [db] :as cofx} photos page-info end-cursor]
(let [photos_x (when end-cursor (:camera-roll-photos db))]
{:db (-> db
(assoc :camera-roll-photos (concat photos_x (map #(get-in % [:node :image :uri]) photos)))
(assoc :camera-roll-end-cursor (:end_cursor page-info))
(assoc :camera-roll-has-next-page (:has_next_page page-info))
(assoc :camera-roll-loading-more false))}))
(fx/defn clear-sending-images
{:events [:chat.ui/clear-sending-images]}
+1
View File
@@ -126,6 +126,7 @@
text (get-in message [:content :text])]
{:dispatch [:chat.ui.input/set-chat-input-text text current-chat-id]
:set-input-text [current-chat-id text]
:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
message)
+8 -1
View File
@@ -1,7 +1,8 @@
(ns status-im.chat.models-test
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.clocks :as utils.clocks]
[status-im.chat.models :as chat]))
[status-im.chat.models :as chat]
[status-im.chat.models.images :as images]))
(deftest clear-history-test
(let [chat-id "1"
@@ -91,3 +92,9 @@
(testing "Pagination info should be reset on navigation"
(let [res (chat/navigate-to-chat-nav2 {:db db} chat-id false)]
(is (nil? (get-in res [:db :pagination-info chat-id :all-loaded?])))))))
(deftest camera-roll-loading-more
(let [cofx {:db {:camera-roll-loading-more false}}]
(is (= true (images/camera-roll-loading-more cofx true)))))
+223 -180
View File
@@ -26,12 +26,12 @@
(def featured
[{:name "Status"
:id constants/status-community-id}])
:id constants/status-community-id}])
(defn <-request-to-join-community-rpc [r]
(clojure.set/rename-keys r {:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
:publicKey :public-key
:chatId :chat-id}))
(defn <-requests-to-join-community-rpc [requests]
(reduce (fn [acc r]
@@ -60,11 +60,12 @@
(defn <-rpc [c]
(-> c
(clojure.set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?})
(clojure.set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :categories <-categories-rpc)))
@@ -125,67 +126,67 @@
(fx/defn import-community
{:events [::import]}
[cofx community-key]
{::json-rpc/call [{:method "wakuext_importCommunity"
:params [community-key]
{::json-rpc/call [{:method "wakuext_importCommunity"
:params [community-key]
:js-response true
:on-success #(re-frame/dispatch [::community-imported %])
:on-error #(do
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
:on-success #(re-frame/dispatch [::community-imported %])
:on-error #(do
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
(fx/defn join
{:events [::join]}
{:events [:communities/join]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_joinCommunity"
:params [community-id]
{::json-rpc/call [{:method "wakuext_joinCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::joined %])
:on-error #(do
(log/error "failed to join community" community-id %)
(re-frame/dispatch [::failed-to-join %]))}]})
:on-success #(re-frame/dispatch [::joined %])
:on-error #(do
(log/error "failed to join community" community-id %)
(re-frame/dispatch [::failed-to-join %]))}]})
(fx/defn request-to-join
{:events [::request-to-join]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id}]
{::json-rpc/call [{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id}]
:js-response true
:on-success #(re-frame/dispatch [::requested-to-join %])
:on-error #(do
(log/error "failed to request to join community" community-id %)
(re-frame/dispatch [::failed-to-request-to-join %]))}]})
:on-success #(re-frame/dispatch [::requested-to-join %])
:on-error #(do
(log/error "failed to request to join community" community-id %)
(re-frame/dispatch [::failed-to-request-to-join %]))}]})
(fx/defn leave
{:events [::leave]}
[{:keys [db] :as cofx} community-id]
{:events [:communities/leave]}
[{:keys [db]} community-id]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::left %])
:on-error #(do
(log/error "failed to leave community" community-id %)
(re-frame/dispatch [::failed-to-leave %]))}]}))
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::left %])
:on-error #(do
(log/error "failed to leave community" community-id %)
(re-frame/dispatch [::failed-to-leave %]))}]}))
(fx/defn fetch [_]
{::json-rpc/call [{:method "wakuext_communities"
:params []
{::json-rpc/call [{:method "wakuext_communities"
:params []
:on-success #(re-frame/dispatch [::fetched %])
:on-error #(do
(log/error "failed to fetch communities" %)
(re-frame/dispatch [::failed-to-fetch %]))}]})
:on-error #(do
(log/error "failed to fetch communities" %)
(re-frame/dispatch [::failed-to-fetch %]))}]})
(fx/defn chat-created
{:events [::chat-created]}
[_ community-id user-pk]
{::json-rpc/call [{:method "wakuext_sendChatMessage"
:params [{:chatId user-pk
:text "Upgrade here to see an invitation to community"
:communityId community-id
:contentType constants/content-type-community}]
{::json-rpc/call [{:method "wakuext_sendChatMessage"
:params [{:chatId user-pk
:text "Upgrade here to see an invitation to community"
:communityId community-id
:contentType constants/content-type-community}]
:js-response true
:on-success
#(re-frame/dispatch [:transport/message-sent %])
@@ -196,56 +197,56 @@
{:events [::invite-people-confirmation-pressed]}
[cofx user-pk contacts]
(let [community-id (fetch-community-id-input cofx)
pks (if (seq user-pk)
(conj contacts user-pk)
contacts)]
pks (if (seq user-pk)
(conj contacts user-pk)
contacts)]
(when (seq pks)
{::json-rpc/call [{:method "wakuext_inviteUsersToCommunity"
:params [{:communityId community-id
:users pks}]
{::json-rpc/call [{:method "wakuext_inviteUsersToCommunity"
:params [{:communityId community-id
:users pks}]
:js-response true
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
(fx/defn share-community
{:events [::share-community-confirmation-pressed]}
[cofx user-pk contacts]
(let [community-id (fetch-community-id-input cofx)
pks (if (seq user-pk)
(conj contacts user-pk)
contacts)]
pks (if (seq user-pk)
(conj contacts user-pk)
contacts)]
(when (seq pks)
{::json-rpc/call [{:method "wakuext_shareCommunity"
:params [{:communityId community-id
:users pks}]
{::json-rpc/call [{:method "wakuext_shareCommunity"
:params [{:communityId community-id
:users pks}]
:js-response true
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-share-community %]))}]})))
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-share-community %]))}]})))
(fx/defn create
{:events [::create-confirmation-pressed]}
[{:keys [db]}]
(let [{:keys [name description membership image]} (get db :communities/create)]
(let [params {:name name
(let [params {:name name
:description description
:membership membership
:color (rand-nth colors/chat-colors)
:image (string/replace-first (str image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size}]
:membership membership
:color (rand-nth colors/chat-colors)
:image (string/replace-first (str image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size}]
{::json-rpc/call [{:method "wakuext_createCommunity"
:params [params]
{::json-rpc/call [{:method "wakuext_createCommunity"
:params [params]
:js-response true
:on-success #(re-frame/dispatch [::community-created %])
:on-error #(do
(log/error "failed to create community" %)
(re-frame/dispatch [::failed-to-create-community %]))}]})))
:on-success #(re-frame/dispatch [::community-created %])
:on-error #(do
(log/error "failed to create community" %)
(re-frame/dispatch [::failed-to-create-community %]))}]})))
(fx/defn edit
{:events [::edit-confirmation-pressed]}
@@ -253,15 +254,15 @@
(let [{:keys [id name description membership new-image color]} (get db :communities/create)]
{::json-rpc/call [{:method "wakuext_editCommunity"
:params [{:communityID id
:name name
:name name
:description description
:color color
:image (string/replace-first (str new-image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size
:membership membership}]
:color color
:image (string/replace-first (str new-image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size
:membership membership}]
:on-success #(re-frame/dispatch [::community-edited %])
:on-error #(do
(log/error "failed to edit community" %)
@@ -272,18 +273,18 @@
[{:keys [db] :as cofx}]
(let [community-id (fetch-community-id-input cofx)
{:keys [name description color emoji]} (get db :communities/create-channel)]
{::json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:permissions {:access constants/community-channel-access-no-membership}}]
{::json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:permissions {:access constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-created %])
:on-error #(do
(log/error "failed to create community channel" %)
(re-frame/dispatch [::failed-to-create-community-channel %]))}]}))
:on-success #(re-frame/dispatch [::community-channel-created %])
:on-error #(do
(log/error "failed to create community channel" %)
(re-frame/dispatch [::failed-to-create-community-channel %]))}]}))
(def community-chat-id-length 68)
@@ -295,21 +296,21 @@
[{:keys [db] :as cofx}]
(let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
(get db :communities/create-channel)]
{::json-rpc/call [{:method "wakuext_editCommunityChat"
:params [community-id
edit-channel-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:category_id category-id
:position position
:permissions {:access constants/community-channel-access-no-membership}}]
{::json-rpc/call [{:method "wakuext_editCommunityChat"
:params [community-id
edit-channel-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:category_id category-id
:position position
:permissions {:access constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-edited %])
:on-error #(do
(log/error "failed to edit community channel" %)
(re-frame/dispatch [::failed-to-edit-community-channel %]))}]}))
:on-success #(re-frame/dispatch [::community-channel-edited %])
:on-error #(do
(log/error "failed to edit community channel" %)
(re-frame/dispatch [::failed-to-edit-community-channel %]))}]}))
(defn require-membership? [permissions]
(not= constants/community-no-membership-access (:access permissions)))
@@ -325,7 +326,7 @@
{:db (assoc db :communities/create-channel {})})
(fx/defn invite-people-pressed
{:events [::invite-people-pressed]}
{:events [:communities/invite-people-pressed]}
[cofx id]
(fx/merge cofx
(reset-community-id-input id)
@@ -333,7 +334,7 @@
(navigation/open-modal :invite-people-community {:invite? true})))
(fx/defn share-community-pressed
{:events [::share-community-pressed]}
{:events [:communities/share-community-pressed]}
[cofx id]
(fx/merge cofx
(reset-community-id-input id)
@@ -461,12 +462,12 @@
(fx/defn member-ban
{:events [::member-ban]}
[cofx community-id public-key]
{::json-rpc/call [{:method "wakuext_banUserFromCommunity"
:params [{:communityId community-id
:user public-key}]
{::json-rpc/call [{:method "wakuext_banUserFromCommunity"
:params [{:communityId community-id
:user public-key}]
:js-response true
:on-success #(re-frame/dispatch [::member-banned %])
:on-error #(log/error "failed to ban user from community" community-id public-key %)}]})
:on-success #(re-frame/dispatch [::member-banned %])
:on-error #(log/error "failed to ban user from community" community-id public-key %)}]})
(fx/defn member-kicked
{:events [::member-kicked]}
@@ -478,11 +479,11 @@
(fx/defn member-kick
{:events [::member-kick]}
[cofx community-id public-key]
{::json-rpc/call [{:method "wakuext_removeUserFromCommunity"
:params [community-id public-key]
{::json-rpc/call [{:method "wakuext_removeUserFromCommunity"
:params [community-id public-key]
:js-response true
:on-success #(re-frame/dispatch [::member-kicked %])
:on-error #(log/error "failed to remove user from community" community-id public-key %)}]})
:on-success #(re-frame/dispatch [::member-kicked %])
:on-error #(log/error "failed to remove user from community" community-id public-key %)}]})
(fx/defn delete-community
{:events [::delete-community]}
@@ -522,88 +523,88 @@
(fx/defn accept-request-to-join-pressed
{:events [:communities.ui/accept-request-to-join-pressed]}
[cofx community-id request-id]
{::json-rpc/call [{:method "wakuext_acceptRequestToJoinCommunity"
:params [{:id request-id}]
{::json-rpc/call [{:method "wakuext_acceptRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id %])
:on-error #(log/error "failed to accept requests-to-join" community-id request-id %)}]})
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id %])
:on-error #(log/error "failed to accept requests-to-join" community-id request-id %)}]})
(fx/defn decline-request-to-join-pressed
{:events [:communities.ui/decline-request-to-join-pressed]}
[cofx community-id request-id]
{::json-rpc/call [{:method "wakuext_declineRequestToJoinCommunity"
:params [{:id request-id}]
{::json-rpc/call [{:method "wakuext_declineRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id %])
:on-error #(log/error "failed to decline requests-to-join" community-id request-id)}]})
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id %])
:on-error #(log/error "failed to decline requests-to-join" community-id request-id)}]})
(fx/defn switch-communities-enabled
{:events [:multiaccounts.ui/switch-communities-enabled]}
[{:keys [db]} enabled?]
{::async-storage/set! {:communities-enabled? enabled?}
:db (assoc db :communities/enabled? enabled?)})
:db (assoc db :communities/enabled? enabled?)})
(fx/defn create-category
{:events [::create-category-confirmation-pressed]}
[_ community-id category-title chat-ids]
{::json-rpc/call [{:method "wakuext_createCommunityCategory"
:params [{:communityId community-id
:categoryName category-title
:chatIds (map #(string/replace % community-id "") chat-ids)}]
{::json-rpc/call [{:method "wakuext_createCommunityCategory"
:params [{:communityId community-id
:categoryName category-title
:chatIds (map #(string/replace % community-id "") chat-ids)}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to create community category" %)}]})
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to create community category" %)}]})
(fx/defn remove-chat-from-category
{:events [:remove-chat-from-community-category]}
[{:keys [db]} community-id id categoryID]
(let [category (get-in db [:communities community-id :categories categoryID])
(let [category (get-in db [:communities community-id :categories categoryID])
category-chats (map :id (filter #(and (= (:categoryID %) categoryID) (not= id (:id %)))
(vals (get-in db [:communities community-id :chats]))))]
{::json-rpc/call [{:method "wakuext_editCommunityCategory"
:params [{:communityId community-id
:categoryId categoryID
:categoryName (:name category)
:chatIds category-chats}]
{::json-rpc/call [{:method "wakuext_editCommunityCategory"
:params [{:communityId community-id
:categoryId categoryID
:categoryName (:name category)
:chatIds category-chats}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove chat from community" %)}]}))
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove chat from community" %)}]}))
(fx/defn delete-community-chat
{:events [:delete-community-chat]}
[_ community-id chat-id]
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
:params [community-id chat-id]
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
:params [community-id chat-id]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community chat" %)}]})
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community chat" %)}]})
(fx/defn delete-category
{:events [:delete-community-category]}
[_ community-id category-id]
{::json-rpc/call [{:method "wakuext_deleteCommunityCategory"
:params [{:communityId community-id
:categoryId category-id}]
{::json-rpc/call [{:method "wakuext_deleteCommunityCategory"
:params [{:communityId community-id
:categoryId category-id}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community category" %)}]})
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community category" %)}]})
(fx/defn change-category
{:events [::change-category-confirmation-pressed]}
[cofx community-id category-id {:keys [id position categoryID]}]
(if (not (string/blank? category-id))
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId id
:position position}]
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId id
:position position}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to change community category" %)}]}
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to change community category" %)}]}
(fx/merge cofx
(navigation/navigate-back)
(remove-chat-from-category community-id id categoryID))))
@@ -611,22 +612,22 @@
(fx/defn reorder-category-chat
{:events [::reorder-community-category-chat]}
[_ community-id category-id chat-id new-position]
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId chat-id
:position new-position}]
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId chat-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category chat" %)}]})
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category chat" %)}]})
(fx/defn reorder-category
{:events [::reorder-community-category]}
[_ community-id category-id new-position]
{::json-rpc/call [{:method "wakuext_reorderCommunityCategories"
:params [{:communityId community-id
:categoryId category-id
:position new-position}]
{::json-rpc/call [{:method "wakuext_reorderCommunityCategories"
:params [{:communityId community-id
:categoryId category-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category" %)}]})
@@ -672,3 +673,45 @@
{::async-storage/get {:keys keys
:cb #(re-frame/dispatch
[::category-states-loaded community-id hashes %])}}))
(fx/defn navigate-to-community
{:events [:communities/navigate-to-community]}
[cofx community-id]
(fx/merge cofx
(navigation/pop-to-root-tab :shell-stack)
(navigation/navigate-to-nav2 :community community-id true)))
(fx/defn member-role-updated
{:events [:community.member/role-updated]}
[cofx response-js]
(fx/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response-js)))
(fx/defn add-role-to-member
{:events [:community.member/add-role]}
[cofx community-id public-key role-id]
{::json-rpc/call [{:method "wakuext_addRoleToMember"
:params [{:communityId community-id
:user public-key
:role role-id}]
:on-success #(re-frame/dispatch [:community.member/role-updated %])
:on-error #(log/error "failed to add role to member"
{:error %
:community-id community-id
:public-key public-key
:role-id role-id})}]})
(fx/defn remove-role-from-member
{:events [:community.member/remove-role]}
[_ community-id public-key role-id]
{::json-rpc/call [{:method "wakuext_removeRoleFromMember"
:params [{:communityId community-id
:user public-key
:role role-id}]}
:on-success #(re-frame/dispatch [:community.member/role-updated %])
:on-error #(log/error "failed to remove role from member"
{:error %
:community-id community-id
:public-key public-key
:role-id role-id})]})
+11 -6
View File
@@ -21,12 +21,13 @@
(def ^:const contact-request-state-received 3)
(def ^:const contact-request-state-dismissed 4)
(def ^:const contact-verification-state-unknown 0)
(def ^:const contact-verification-state-pending 1)
(def ^:const contact-verification-state-accepted 2)
(def ^:const contact-verification-state-declined 3)
(def ^:const contact-verification-state-cancelled 4)
(def ^:const contact-verification-state-trusted 5)
(def ^:const contact-verification-status-unknown 0)
(def ^:const contact-verification-status-pending 1)
(def ^:const contact-verification-status-accepted 2)
(def ^:const contact-verification-status-declined 3)
(def ^:const contact-verification-status-cancelled 4)
(def ^:const contact-verification-status-trusted 5)
(def ^:const contact-verification-status-untrustworthy 6)
(def ^:const emoji-reaction-love 1)
(def ^:const emoji-reaction-thumbs-up 2)
@@ -197,3 +198,7 @@
(def ^:const sticker-pack-status-owned 3)
(def ^:const delete-message-for-me-undo-time-limit-ms 4000)
(def ^:const community-member-role-all 1)
(def ^:const community-member-role-manage-users 2)
(def ^:const community-member-role-moderator 3)
+5
View File
@@ -151,3 +151,8 @@
:mutual-contact-enabled?
enabled?
nil))
(fx/defn set-search-query
{:events [:contacts/set-search-query]}
[{:keys [db] :as cofx} value]
{:db (assoc db :contacts/search-query value)})
+1 -1
View File
@@ -4,7 +4,7 @@
[status-im.constants :as constants]
[status-im.activity-center.notification-types :as notification-types]
[status-im.data-store.messages :as messages]
[status-im.utils.config :as config]))
[status-im2.setup.config :as config]))
(defn- rpc->type [{:keys [type name] :as chat}]
(case type
@@ -3,7 +3,7 @@
[status-im.constants :as constants]
[status-im.activity-center.notification-types :as notification-types]
[status-im.data-store.activities :as store]
[status-im.utils.config :as config]))
[status-im2.setup.config :as config]))
(def chat-id
"0x04c66155")
@@ -13,7 +13,7 @@
(def raw-notification
{:chatId chat-id
:contactVerificationStatus constants/contact-verification-state-pending
:contactVerificationStatus constants/contact-verification-status-pending
:lastMessage {}
:name chat-name
:replyMessage {}})
@@ -23,7 +23,7 @@
(testing "renames keys"
(is (= {:name chat-name
:chat-id chat-id
:contact-verification-status constants/contact-verification-state-pending}
:contact-verification-status constants/contact-verification-status-pending}
(-> raw-notification
store/<-rpc
(dissoc :last-message :message :reply-message)))))
+9 -5
View File
@@ -27,7 +27,6 @@
status-im.mailserver.constants
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.biometric.core :as biometric]
[status-im.multiaccounts.core :as multiaccounts]
status-im.multiaccounts.login.core
status-im.multiaccounts.logout.core
status-im.multiaccounts.update.core
@@ -46,6 +45,7 @@
status-im.ui.screens.privacy-and-security-settings.events
[status-im.utils.dimensions :as dimensions]
[status-im.utils.fx :as fx]
status-im.utils.logging.core
[status-im.utils.universal-links.core :as universal-links]
[status-im.utils.utils :as utils]
status-im.visibility-status-updates.core
@@ -56,7 +56,10 @@
status-im.wallet.custom-tokens.core
status-im.wallet-connect.core
status-im.wallet-connect-legacy.core
status-im.network.net-info))
status-im.network.net-info
status-im.visibility-status-popover.core
status-im2.contexts.shell.events
[status-im.multiaccounts.model :as multiaccounts.model]))
(re-frame/reg-fx
:dismiss-keyboard
@@ -110,9 +113,10 @@
(fx/defn system-theme-mode-changed
{:events [:system-theme-mode-changed]}
[_ theme]
{::multiaccounts/switch-theme (if (= :dark theme) 2 1)
:dispatch [:reload-new-ui]})
[cofx _]
(when (multiaccounts.model/logged-in? cofx)
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])
:dispatch [:reload-new-ui]}))
(def authentication-options
{:reason (i18n/label :t/biometric-auth-reason-login)})
+38 -38
View File
@@ -21,89 +21,89 @@
{:events [:chat-removed]}
[cofx response]
(fx/merge cofx
{:db (dissoc (:db cofx) :current-chat-id)
{:db (dissoc (:db cofx) :current-chat-id)
:dispatch-n [[:sanitize-messages-and-process-response response]
[:pop-to-root-tab :chat-stack]]}
(notification-center/get-activity-center-notifications-count)))
(fx/defn handle-chat-update
{:events [:chat-updated]}
[_ response]
[_ response do-not-navigate?]
{:dispatch-n [[:sanitize-messages-and-process-response response]
[:navigate-chat-updated (.-id (aget (.-chats response) 0))]]})
(when-not do-not-navigate? [:navigate-chat-updated (.-id (aget (.-chats response) 0))])]})
(fx/defn remove-member
"Format group update message and sign membership"
{:events [:group-chats.ui/remove-member-pressed]}
[_ chat-id member]
{::json-rpc/call [{:method "wakuext_removeMemberFromGroupChat"
:params [nil chat-id member]
[_ chat-id member do-not-navigate?]
{::json-rpc/call [{:method "wakuext_removeMemberFromGroupChat"
:params [nil chat-id member]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
:on-success #(re-frame/dispatch [:chat-updated % do-not-navigate?])}]})
(fx/defn join-chat
{:events [:group-chats.ui/join-pressed]}
[_ chat-id]
{::json-rpc/call [{:method "wakuext_confirmJoiningGroup"
:params [chat-id]
{::json-rpc/call [{:method "wakuext_confirmJoiningGroup"
:params [chat-id]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn create
{:events [:group-chats.ui/create-pressed]
{:events [:group-chats.ui/create-pressed]
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
[{:keys [db] :as cofx} group-name]
(let [selected-contacts (:group/selected-contacts db)]
{::json-rpc/call [{:method "wakuext_createGroupChatWithMembers"
:params [nil group-name (into [] selected-contacts)]
{::json-rpc/call [{:method "wakuext_createGroupChatWithMembers"
:params [nil group-name (into [] selected-contacts)]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
(fx/defn create-from-link
[cofx {:keys [chat-id invitation-admin chat-name]}]
(if (get-in cofx [:db :chats chat-id])
{:dispatch-n [[:accept-all-activity-center-notifications-from-chat chat-id]
[:chat.ui/navigate-to-chat chat-id]]}
{::json-rpc/call [{:method "wakuext_createGroupChatFromInvitation"
:params [chat-name chat-id invitation-admin]
{::json-rpc/call [{:method "wakuext_createGroupChatFromInvitation"
:params [chat-name chat-id invitation-admin]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
(fx/defn make-admin
{:events [:group-chats.ui/make-admin-pressed]}
[_ chat-id member]
{::json-rpc/call [{:method "wakuext_addAdminsToGroupChat"
:params [nil chat-id [member]]
{::json-rpc/call [{:method "wakuext_addAdminsToGroupChat"
:params [nil chat-id [member]]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn add-members
"Add members to a group chat"
{:events [:group-chats.ui/add-members-pressed]}
[{{:keys [current-chat-id selected-participants]} :db :as cofx}]
{::json-rpc/call [{:method "wakuext_addMembersToGroupChat"
:params [nil current-chat-id selected-participants]
{::json-rpc/call [{:method "wakuext_addMembersToGroupChat"
:params [nil current-chat-id selected-participants]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn add-members-from-invitation
"Add members to a group chat"
{:events [:group-chats.ui/add-members-from-invitation]}
[{{:keys [current-chat-id] :as db} :db :as cofx} id participant]
{:db (assoc-in db [:group-chat/invitations id :state] constants/invitation-state-approved)
::json-rpc/call [{:method "wakuext_addMembersToGroupChat"
:params [nil current-chat-id [participant]]
::json-rpc/call [{:method "wakuext_addMembersToGroupChat"
:params [nil current-chat-id [participant]]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn leave
"Leave chat"
{:events [:group-chats.ui/leave-chat-confirmed]}
[{:keys [db] :as cofx} chat-id]
{::json-rpc/call [{:method "wakuext_leaveGroupChat"
:params [nil chat-id true]
{::json-rpc/call [{:method "wakuext_leaveGroupChat"
:params [nil chat-id true]
:js-response true
:on-success #(re-frame/dispatch [:chat-removed %])}]})
:on-success #(re-frame/dispatch [:chat-removed %])}]})
(fx/defn remove
"Remove chat"
@@ -125,10 +125,10 @@
[{:keys [db] :as cofx} chat-id new-name]
(when (valid-name? new-name)
{:db (assoc-in db [:chats chat-id :name] new-name)
::json-rpc/call [{:method "wakuext_changeGroupChatName"
:params [nil chat-id new-name]
::json-rpc/call [{:method "wakuext_changeGroupChatName"
:params [nil chat-id new-name]
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
(fx/defn membership-retry
{:events [:group-chats.ui/membership-retry]}
@@ -147,19 +147,19 @@
(let [{:keys [invitation-admin]} (get chats current-chat-id)
message (get-in db [:chat/memberships current-chat-id :message])]
{:db (assoc-in db [:chat/memberships current-chat-id] nil)
::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest"
:params [nil current-chat-id invitation-admin message]
::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest"
:params [nil current-chat-id invitation-admin message]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}))
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}))
(fx/defn send-group-chat-membership-rejection
"Send group chat membership rejection"
{:events [:send-group-chat-membership-rejection]}
[cofx invitation-id]
{::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRejection"
:params [nil invitation-id]
{::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRejection"
:params [nil invitation-id]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
(fx/defn handle-invitations
[{db :db} invitations]
+10 -7
View File
@@ -5,8 +5,11 @@
;;TODO (14/11/22 flexsurfer) this namespace has been moved to the status-im2 namespace, we keep this only for old (status 1.0) code,
;; can be removed with old code later
(def get-keyword
(if js/global.__TEST__ str keyword))
(def default-device-language
(keyword (.-language react-native-languages)))
(get-keyword (.-language react-native-languages)))
(def languages #{:ar :bn :de :el :en :es :es_419 :es_AR :fil :fr :hi :id :in :it :ja :ko :ms :nl :pl :pt :pt_BR :ru :tr :vi :zh :zh_Hant :zh_TW})
@@ -16,17 +19,17 @@
(defn valid-language [lang]
(if (contains? languages lang)
(keyword lang)
(get-keyword lang)
(let [parts (string/split (name lang) #"[\-\_]")
short-lang (keyword (str (first parts) "_" (second parts)))
shortest-lang (keyword (first parts))]
short-lang (get-keyword (str (first parts) "_" (second parts)))
shortest-lang (get-keyword (first parts))]
(if (and (> (count parts) 2) (contains? languages short-lang))
short-lang
(when (contains? languages shortest-lang)
shortest-lang)))))
(defn require-translation [lang-key]
(when-let [lang (valid-language (keyword lang-key))]
(when-let [lang (valid-language (get-keyword lang-key))]
(case lang
:ar (js/require "../translations/ar.json")
:bn (js/require "../translations/bn.json")
@@ -63,10 +66,10 @@
(assoc default-device-language
(require-translation (-> (name default-device-language)
(string/replace "-" "_")
keyword)))))
get-keyword)))))
(defn load-language [lang]
(when-let [lang-key (valid-language (keyword lang))]
(when-let [lang-key (valid-language (get-keyword lang))]
(when-not (contains? @loaded-languages lang-key)
(aset (.-translations i18n-js)
lang
+2 -2
View File
@@ -162,7 +162,7 @@
{::blank-preview-flag-changed private?}))
(re-frame/reg-fx
::switch-theme
:multiaccounts.ui/switch-theme
(fn [theme-id]
(let [theme (if (or (= 2 theme-id) (and (= 0 theme-id) (utils.theme/dark-mode?)))
:dark
@@ -173,7 +173,7 @@
{:events [:multiaccounts.ui/appearance-switched]}
[cofx theme]
(fx/merge cofx
{::switch-theme theme}
{:multiaccounts.ui/switch-theme theme}
(multiaccounts.update/multiaccount-update :appearance theme {})))
(fx/defn switch-profile-picture-show-to
+2 -1
View File
@@ -336,7 +336,7 @@
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
(fx/defn initialize-appearance [cofx]
{::multiaccounts/switch-theme (get-in cofx [:db :multiaccount :appearance])})
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])})
(fx/defn get-group-chat-invitations [_]
{::json-rpc/call
@@ -392,6 +392,7 @@
(get-node-config)
(communities/fetch)
(logging/set-log-level (:log-level multiaccount))
(notifications-center/get-activity-center-notifications)
(notifications-center/get-activity-center-notifications-count))))
(re-frame/reg-fx
+2 -2
View File
@@ -17,12 +17,12 @@
{:init-root-fx :progress
:chat.ui/clear-inputs nil
:chat.ui/clear-inputs-old nil
:new-ui/reset-bottom-tabs nil
:shell/reset-bottom-tabs nil
:hide-popover nil
::logout nil
::multiaccounts/webview-debug-changed false
:keychain/clear-user-password key-uid
::init/open-multiaccounts #(re-frame/dispatch [::init/initialize-multiaccounts % {:logout? logout?}])}
:setup/open-multiaccounts #(re-frame/dispatch [:setup/initialize-multiaccounts % {:logout? logout?}])}
(keychain/save-auth-method key-uid auth-method)
(wallet/clear-timeouts)
(init/initialize-app-db))))
+444
View File
@@ -0,0 +1,444 @@
(ns status-im.navigation.core
(:require
["react-native" :as rn]
["react-native-gesture-handler" :refer (gestureHandlerRootHOC)]
["react-native-navigation" :refer (Navigation)]
[clojure.set :as clojure.set]
[quo.components.text-input :as quo.text-input]
[quo.design-system.colors :as quo.colors]
[re-frame.core :as re-frame]
[status-im.multiaccounts.login.core :as login-core]
[status-im.navigation.roots :as roots]
[status-im.navigation.state :as state]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[status-im.ui.screens.views :as views]
[status-im.utils.fx :as fx]
[status-im.utils.platform :as platform]
[taoensso.encore :as enc]
[taoensso.timbre :as log]))
(def debug? ^boolean js/goog.DEBUG)
(def splash-screen (-> rn .-NativeModules .-SplashScreen))
(defonce set-navigation-default-options
(.setDefaultOptions Navigation (clj->js {:layout {:orientation "portrait"}})))
;; REGISTER COMPONENT (LAZY)
(defn reg-comp [key]
(log/debug "reg-comp" key)
(if-let [comp (get views/components (keyword key))]
(.registerComponent Navigation key (fn [] (views/component comp)))
(let [screen (views/screen key)]
(.registerComponent Navigation key (fn [] (gestureHandlerRootHOC screen)) (fn [] screen)))))
(defonce rset-lazy-reg
(.setLazyComponentRegistrator Navigation reg-comp))
(defn dismiss-all-modals []
(log/debug "dissmiss-all-modals")
(when @state/curr-modal
(reset! state/curr-modal false)
(reset! state/dissmissing true)
(doseq [modal @state/modals]
(.dismissModal Navigation (name modal)))
(reset! state/modals [])))
;; PUSH SCREEN
(defn navigate [comp]
(log/debug "NAVIGATE" comp)
(let [{:keys [options]} (get views/screens comp)]
(.push Navigation
(name @state/root-comp-id)
(clj->js {:component {:id comp
:name comp
:options (merge options
(roots/status-bar-options)
(roots/merge-top-bar (roots/topbar-options) options))}}))
;;if we push the screen from modal, we want to dismiss all modals
(dismiss-all-modals)))
;; OPEN MODAL
(defn update-modal-topbar-options [options]
(log/debug "update-modal-topbar-options" options)
(merge options
(roots/merge-top-bar {:elevation 0
:noBorder true
:title {:color quo.colors/black}
:background {:color quo.colors/white}
:leftButtonColor quo.colors/black
:leftButtons {:id "dismiss-modal"
:icon (icons/icon-source :main-icons/close)}}
options)))
(defn open-modal [comp]
(log/debug "open-modal" comp)
(let [{:keys [options]} (get views/screens comp)]
(if @state/dissmissing
(reset! state/dissmissing comp)
(do
(reset! state/curr-modal true)
(swap! state/modals conj comp)
(.showModal Navigation
(clj->js {:stack {:children
[{:component
{:name comp
:id comp
:options (update-modal-topbar-options
(merge (roots/status-bar-options)
(roots/default-root)
options))}}]}}))))))
(re-frame/reg-fx :open-modal-fx open-modal)
;; DISSMISS MODAL
(defn dissmissModal []
(log/debug "dissmissModal")
(reset! state/dissmissing true)
(.dismissModal Navigation (name (last @state/modals))))
(defonce register-nav-button-reg
(.registerNavigationButtonPressedListener
(.events Navigation)
(fn [^js evn]
(let [id (.-buttonId evn)]
(if (= "dismiss-modal" id)
(do
(when-let [event (get-in views/screens [(last @state/modals) :on-dissmiss])]
(re-frame/dispatch event))
(dissmissModal))
(when-let [handler (get-in views/screens [(keyword id) :right-handler])]
(handler)))))))
(defn set-view-id [view-id]
(log/debug "set-view-id" view-id)
(when-let [{:keys [on-focus]} (get views/screens view-id)]
(re-frame/dispatch [:set-view-id view-id])
(re-frame/dispatch [:screens/on-will-focus view-id])
(when on-focus
(re-frame/dispatch on-focus))))
(defonce register-modal-reg
(.registerModalDismissedListener
(.events Navigation)
(fn [_]
(if (> (count @state/modals) 1)
(let [new-modals (butlast @state/modals)]
(reset! state/modals (vec new-modals))
(set-view-id (last new-modals)))
(do
(reset! state/modals [])
(reset! state/curr-modal false)
(set-view-id @state/pushed-screen-id)))
(let [comp @state/dissmissing]
(reset! state/dissmissing false)
(when (keyword? comp)
(open-modal comp))))))
;; SCREEN DID APPEAR
(defonce screen-appear-reg
(.registerComponentDidAppearListener
(.events Navigation)
(fn [^js evn]
(let [view-id (keyword (.-componentName evn))]
(log/debug "screen-appear-reg" view-id)
(when (get views/screens view-id)
(when (and (not= view-id :bottom-sheet)
(not= view-id :popover)
(not= view-id :visibility-status-popover))
(set-view-id view-id)
(when-not @state/curr-modal
(reset! state/pushed-screen-id view-id))))))))
;; SCREEN DID DISAPPEAR
(defonce screen-disappear-reg
(.registerComponentDidDisappearListener
(.events Navigation)
(fn [^js evn]
(let [view-id (keyword (.-componentName evn))]
(when-not (#{"popover" "bottom-sheet" "signing-sheet" "visibility-status-popover" "wallet-connect-sheet" "wallet-connect-success-sheet" "wallet-connect-app-management-sheet"}
(.-componentName evn))
(re-frame/dispatch [::view-disappeared view-id])
(doseq [[_ {:keys [ref value]}] @quo.text-input/text-input-refs]
(.setNativeProps ^js ref (clj->js {:text value})))
(doseq [[^js text-input default-value] @react/text-input-refs]
(.setNativeProps text-input (clj->js {:text default-value}))))))))
;; SET ROOT
(re-frame/reg-fx
:init-root-fx
(fn [new-root-id]
(log/debug :init-root-fx new-root-id)
(reset! state/root-comp-id new-root-id)
(reset! state/root-id @state/root-comp-id)
(.setRoot Navigation (clj->js (get (roots/roots) new-root-id)))))
(re-frame/reg-fx
:init-root-with-component-fx
(fn [[new-root-id new-root-comp-id]]
(log/debug :init-root-with-component-fx new-root-id new-root-comp-id)
(reset! state/root-comp-id new-root-comp-id)
(reset! state/root-id @state/root-comp-id)
(.setRoot Navigation (clj->js (get (roots/roots) new-root-id)))))
(fx/defn set-multiaccount-root
{:events [::set-multiaccount-root]}
[{:keys [db]}]
(log/debug :set-multiaccounts-root)
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
keycard-account? (boolean (get-in db [:multiaccounts/multiaccounts
key-uid
:keycard-pairing]))]
{:init-root-fx (if keycard-account? :multiaccounts-keycard :multiaccounts)}))
(defonce rset-app-launched
(.registerAppLaunchedListener (.events Navigation)
(fn []
(reset! state/curr-modal false)
(reset! state/dissmissing false)
(if (or (= @state/root-id :multiaccounts)
(= @state/root-id :multiaccounts-keycard))
(re-frame/dispatch-sync [::set-multiaccount-root])
(when @state/root-id
(reset! state/root-comp-id @state/root-id)
(.setRoot Navigation (clj->js (get (roots/roots) @state/root-id)))
(re-frame/dispatch [::login-core/check-last-chat])))
(.hide ^js splash-screen))))
(defn get-screen-component [comp]
(log/debug :get-screen-component comp)
(let [{:keys [options]} (get views/screens comp)]
{:component {:id comp
:name comp
:options (merge options
(roots/status-bar-options)
(roots/merge-top-bar (roots/topbar-options) options))}}))
;; SET STACK ROOT
(re-frame/reg-fx
:set-stack-root-fx
(fn [[stack comp]]
(log/debug :set-stack-root-fx stack comp)
(.setStackRoot Navigation
(name stack)
(clj->js (if (vector? comp)
(mapv get-screen-component comp)
(get-screen-component comp))))))
;; BOTTOM TABS
(def tab-root-ids {0 :chat-stack
1 :browser-stack
2 :wallet-stack
3 :status-stack
4 :profile-stack})
(def tab-key-idx {:chat 0
:browser 1
:wallet 2
:status 3
:profile 4})
(re-frame/reg-fx
:change-tab-fx
(fn [tab]
(log/debug :change-tab-fx)
(reset! state/root-comp-id (get tab-root-ids (get tab-key-idx tab)))
(.mergeOptions Navigation "tabs-stack" (clj->js {:bottomTabs {:currentTabIndex (get tab-key-idx tab)}}))
;;when we change tab we want to dismiss all modals
(dismiss-all-modals)))
;issue on ios https://github.com/wix/react-native-navigation/issues/7146
(re-frame/reg-fx
:change-tab-count-fx
(fn [[tab cnt]]
(log/debug :change-tab-count-fx tab cnt)
(.mergeOptions Navigation
(name (get tab-root-ids (get tab-key-idx tab)))
(clj->js {:bottomTab (cond
(or (pos? cnt) (pos? (:other cnt)))
(if (and (= :chat tab) platform/ios?)
{:dotIndicator {:visible true}}
{:badge (str (or (:other cnt) cnt)) :dotIndicator {:visible false}})
(pos? (:public cnt))
(if platform/ios?
{:dotIndicator {:visible true}}
{:badge nil :dotIndicator {:visible true}})
:else
(if (and (= :chat tab) platform/ios?)
{:dotIndicator {:visible false}}
{:dotIndicator {:visible false} :badge ""}))}))))
(re-frame/reg-fx
:pop-to-root-tab-fx
(fn [comp]
(log/debug :pop-to-root-tab-fx comp)
(dismiss-all-modals)
(.popToRoot Navigation (name comp))))
(defonce register-bottom-tab-reg
(.registerBottomTabSelectedListener
(.events Navigation)
(fn [^js evn]
(let [selected-tab-index (.-selectedTabIndex evn)
comp (get tab-root-ids selected-tab-index)
tab-key (get (clojure.set/map-invert tab-key-idx) selected-tab-index)]
(re-frame/dispatch [:set :current-tab tab-key])
(when (= @state/root-comp-id comp)
(when (= :chat tab-key)
(re-frame/dispatch [:close-chat]))
(when platform/android?
(.popToRoot Navigation (name comp))))
(reset! state/root-comp-id comp)))))
;; OVERLAY (Popover and bottom sheets)
(defn dissmiss-overlay [comp]
(.catch (.dismissOverlay Navigation comp) #()))
(defn show-overlay [comp]
(dissmiss-overlay comp)
(.showOverlay Navigation
(clj->js
{:component {:name comp
:id comp
:options (merge (cond-> (roots/status-bar-options)
(and platform/android? (not (quo.colors/dark?)))
(assoc-in [:statusBar :backgroundColor] "#99999A"))
{:layout {:componentBackgroundColor (if platform/android?
(:backdrop @quo.colors/theme)
"transparent")}
:overlay {:interceptTouchOutside true}})}})))
;; POPOVER
(defonce popover-reg
(.registerComponent Navigation
"popover"
(fn [] (gestureHandlerRootHOC views/popover-comp))
(fn [] views/popover-comp)))
(re-frame/reg-fx :show-popover (fn [] (show-overlay "popover")))
(re-frame/reg-fx :hide-popover (fn [] (dissmiss-overlay "popover")))
;; VISIBILITY STATUS POPOVER
(defonce visibility-status-popover-reg
(.registerComponent Navigation
"visibility-status-popover"
(fn [] (gestureHandlerRootHOC views/visibility-status-popover-comp))
(fn [] views/visibility-status-popover-comp)))
(re-frame/reg-fx :show-visibility-status-popover
(fn [] (show-overlay "visibility-status-popover")))
(re-frame/reg-fx :hide-visibility-status-popover
(fn [] (dissmiss-overlay "visibility-status-popover")))
;; BOTTOM SHEETS
(defonce bottom-sheet-reg
(.registerComponent Navigation
"bottom-sheet"
(fn [] (gestureHandlerRootHOC views/sheet-comp))
(fn [] views/sheet-comp)))
(re-frame/reg-fx :show-bottom-sheet (fn [] (show-overlay "bottom-sheet")))
(re-frame/reg-fx :hide-bottom-sheet (fn [] (dissmiss-overlay "bottom-sheet")))
;; WALLET CONNECT
(defonce wallet-connect-sheet-reg
(.registerComponent Navigation
"wallet-connect-sheet"
(fn [] (gestureHandlerRootHOC views/wallet-connect-comp))
(fn [] views/wallet-connect-comp)))
(defonce wallet-connect-success-sheet-reg
(.registerComponent Navigation
"wallet-connect-success-sheet"
(fn [] (gestureHandlerRootHOC views/wallet-connect-success-comp))
(fn [] views/wallet-connect-success-comp)))
(defonce wallet-connect-app-management-sheet-reg
(.registerComponent Navigation
"wallet-connect-app-management-sheet"
(fn [] (gestureHandlerRootHOC views/wallet-connect-app-management-comp))
(fn [] views/wallet-connect-app-management-comp)))
(re-frame/reg-fx :show-wallet-connect-sheet (fn [] (show-overlay "wallet-connect-sheet")))
(re-frame/reg-fx :hide-wallet-connect-sheet (fn [] (dissmiss-overlay "wallet-connect-sheet")))
(re-frame/reg-fx :show-wallet-connect-success-sheet (fn [] (show-overlay "wallet-connect-success-sheet")))
(re-frame/reg-fx :hide-wallet-connect-success-sheet (fn [] (dissmiss-overlay "wallet-connect-success-sheet")))
(re-frame/reg-fx :show-wallet-connect-app-management-sheet (fn [] (show-overlay "wallet-connect-app-management-sheet")))
(re-frame/reg-fx :hide-wallet-connect-app-management-sheet (fn [] (dissmiss-overlay "wallet-connect-app-management-sheet")))
;; SIGNING
(defonce signing-sheet-reg
(.registerComponent Navigation
"signing-sheet"
(fn [] (gestureHandlerRootHOC views/signing-comp))
(fn [] views/signing-comp)))
(re-frame/reg-fx :show-signing-sheet (fn [] (show-overlay "signing-sheet")))
(re-frame/reg-fx :hide-signing-sheet (fn [] (dissmiss-overlay "signing-sheet")))
;; Select account
;; TODO why is this not a regular bottom sheet ?
(defonce select-acc-sheet-reg
(.registerComponent Navigation
"select-acc-sheet"
(fn [] (gestureHandlerRootHOC views/select-acc-comp))
(fn [] views/select-acc-comp)))
(re-frame/reg-fx :show-select-acc-sheet (fn [] (show-overlay "select-acc-sheet")))
(re-frame/reg-fx :hide-select-acc-sheet (fn [] (dissmiss-overlay "select-acc-sheet")))
;; NAVIGATION
(re-frame/reg-fx
:navigate-to-fx
(fn [key]
(log/debug :navigate-to-fx key)
(navigate key)))
(re-frame/reg-fx
:navigate-back-fx
(fn []
(log/debug :navigate-back-fx)
(if @state/curr-modal
(dissmissModal)
(.pop Navigation (name @state/root-comp-id)))))
(re-frame/reg-fx
:navigate-replace-fx
(fn [view-id]
(log/debug :navigate-replace-fx view-id)
(.pop Navigation (name @state/root-comp-id))
(navigate view-id)))
(def community-screens '(:community-management
:community-members
:community-requests-to-join
:create-community-channel
:community-emoji-thumbnail-picker
:create-community-category
:community-edit-chats
:community-edit
:community-reorder-categories))
;; change view-id if it is still same after component is disappeared
;; https://github.com/wix/react-native-navigation/issues/5744#issuecomment-563226820
(fx/defn view-disappeared
{:events [::view-disappeared]}
[{:keys [db]} view-id]
(when (= view-id (:view-id db))
{:db (assoc db :view-id (cond
(= view-id :community-emoji-thumbnail-picker)
:create-community-channel
(some #(= view-id %) community-screens)
:community
:else
:home))
:dispatch-n (enc/conj-when []
(and (= view-id :chat) [:chat.ui/sync-all-deleted-for-me-messages]))}))
+19 -20
View File
@@ -43,7 +43,7 @@
"returns discovery v5 topic derived from genesis of the provided network"
[network]
(let [les-discovery-identifier "LES2@"
hash-prefix (get-network-genesis-hash-prefix network)]
hash-prefix (get-network-genesis-hash-prefix network)]
(when hash-prefix
(str les-discovery-identifier hash-prefix))))
@@ -92,13 +92,13 @@
(defn- get-multiaccount-node-config
[{:keys [multiaccount :networks/networks :networks/current-network]
:as db}]
(let [wakuv2-config (get multiaccount :wakuv2-config {})
current-fleet-key (current-fleet-key db)
current-fleet (get-current-fleet db)
wakuv2-enabled (boolean (:waku current-fleet))
wakuv2-nodes (into (vals (:waku current-fleet)) (vals (get wakuv2-config :CustomNodes)))
rendezvous-nodes (pick-nodes 3 (vals (:rendezvous current-fleet)))
:as db}]
(let [wakuv2-config (get multiaccount :wakuv2-config {})
current-fleet-key (current-fleet-key db)
current-fleet (get-current-fleet db)
wakuv2-enabled (boolean (:waku current-fleet))
waku-nodes (:waku-nodes current-fleet)
rendezvous-nodes (pick-nodes 3 (vals (:rendezvous current-fleet)))
{:keys [installation-id log-level
waku-bloom-filter-mode
custom-bootnodes custom-bootnodes-enabled?]} multiaccount
@@ -111,10 +111,10 @@
(get-login-node-config)
current-fleet
(assoc :NoDiscovery wakuv2-enabled
:Rendezvous (if wakuv2-enabled false (boolean (seq rendezvous-nodes)))
:ClusterConfig {:Enabled true
:Fleet (name current-fleet-key)
(assoc :NoDiscovery wakuv2-enabled
:Rendezvous (if wakuv2-enabled false (boolean (seq rendezvous-nodes)))
:ClusterConfig {:Enabled true
:Fleet (name current-fleet-key)
:BootNodes
(if wakuv2-enabled [] (pick-nodes 4 (vals (:boot current-fleet))))
:TrustedMailServers
@@ -124,9 +124,8 @@
(into (pick-nodes 2
(vals (:whisper current-fleet)))
(vals (:static current-fleet))))
:RelayNodes wakuv2-nodes
:StoreNodes wakuv2-nodes
:RendezvousNodes (if wakuv2-enabled [] rendezvous-nodes)})
:RendezvousNodes (if wakuv2-enabled [] rendezvous-nodes)
:WakuNodes (or waku-nodes [])})
:always
(assoc :LocalNotificationsConfig {:Enabled true}
@@ -135,10 +134,10 @@
:MailserversConfig {:Enabled true}
:EnableNTPSync true
:WakuConfig
{:Enabled true
{:Enabled true
:BloomFilterMode waku-bloom-filter-mode
:LightClient true
:MinimumPoW 0.000001}
:LightClient true
:MinimumPoW 0.000001}
:WakuV2Config (assoc wakuv2-config :Enabled wakuv2-enabled :Host "0.0.0.0")
:ShhextConfig
{:BackupDisabledDataDir (utils.platform/no-backup-directory)
@@ -174,8 +173,8 @@
app-db"
{:events [::save-new-config]}
[{:keys [db]} config {:keys [on-success]}]
{::json-rpc/call [{:method "settings_saveSetting"
:params [:node-config config]
{::json-rpc/call [{:method "settings_saveSetting"
:params [:node-config config]
:on-success on-success}]})
(fx/defn prepare-new-config
@@ -47,7 +47,6 @@
:collectible-dark (js/require "../resources/images/ui/collectible-dark.png")
:hand-wave (js/require "../resources/images/ui/hand-wave.png")
:graph (js/require "../resources/images/ui/graph.png")
:switcher (js/require "../resources/images/ui/switcher.png")
:discover (js/require "../resources/images/ui/discover.png")
:community-cover (js/require "../resources/images/ui/community-cover.png")
:lifestyle (js/require "../resources/images/ui/lifestyle.png")
-114
View File
@@ -1,114 +0,0 @@
(ns status-im.switcher.animation
(:require [re-frame.core :as re-frame]
[react-native.reanimated :as reanimated]
[quo2.foundations.colors :as colors]
[status-im.async-storage.core :as async-storage]
[status-im.switcher.constants :as constants]))
;;;; Bottom Tabs & Home Stack Animations
(def selected-stack-id (atom nil))
(def home-stack-open? (atom false))
(def pass-through? (atom false))
(def bottom-nav-tab-width 90)
(defn selected-stack-id-loaded [stack-id]
(reset! selected-stack-id stack-id)
(reset! home-stack-open? (some? stack-id)))
(defn calculate-home-stack-position []
(let [{:keys [width height]} (constants/dimensions)
minimize-scale (/ bottom-nav-tab-width width)
empty-space-half-scale (/ (- 1 minimize-scale) 2)
left-margin (/ (- width (* 4 bottom-nav-tab-width)) 2)
left-empty-space (* empty-space-half-scale width)
top-empty-space (* empty-space-half-scale
(- height (constants/bottom-tabs-container-height)))]
{:left (reduce
(fn [acc stack-id]
(assoc acc stack-id (+ (- left-margin left-empty-space)
(* (.indexOf constants/stacks-ids stack-id)
bottom-nav-tab-width))))
{:none 0} constants/stacks-ids)
:top (+ top-empty-space (constants/bottom-tabs-container-height))
:scale minimize-scale}))
(defn get-shared-values []
(let [selected-stack-id-sv (reanimated/use-shared-value
;; passing keywords or nil is not working with reanimated
(name (or @selected-stack-id :communities-stack)))
pass-through-sv (reanimated/use-shared-value @pass-through?)
home-stack-open-sv (reanimated/use-shared-value @home-stack-open?)
animate-home-stack-left (reanimated/use-shared-value (not @home-stack-open?))
home-stack-position (calculate-home-stack-position)]
(reduce
(fn [acc id]
(let [tabs-icon-color-keyword (get constants/tabs-icon-color-keywords id)
stack-opacity-keyword (get constants/stacks-opacity-keywords id)
stack-pointer-keyword (get constants/stacks-pointer-keywords id)]
(assoc
acc
stack-opacity-keyword (.stackOpacity
^js reanimated/worklet-factory
(name id) selected-stack-id-sv)
stack-pointer-keyword (.stackPointer
^js reanimated/worklet-factory
(name id) selected-stack-id-sv)
tabs-icon-color-keyword (.bottomTabIconColor
^js reanimated/worklet-factory
(name id) selected-stack-id-sv home-stack-open-sv
pass-through-sv colors/white colors/neutral-50
colors/white-opa-40))))
{:selected-stack-id selected-stack-id-sv
:pass-through? pass-through-sv
:home-stack-open? home-stack-open-sv
:animate-home-stack-left animate-home-stack-left
:home-stack-left (.homeStackLeft
^js reanimated/worklet-factory
selected-stack-id-sv animate-home-stack-left home-stack-open-sv
(clj->js (:left home-stack-position)))
:home-stack-top (.homeStackTop
^js reanimated/worklet-factory
home-stack-open-sv (:top home-stack-position))
:home-stack-opacity (.homeStackOpacity
^js reanimated/worklet-factory home-stack-open-sv)
:home-stack-pointer (.homeStackPointer
^js reanimated/worklet-factory home-stack-open-sv)
:home-stack-scale (.homeStackScale
^js reanimated/worklet-factory home-stack-open-sv
(:scale home-stack-position))}
constants/stacks-ids)))
;; Animation
(defn open-home-stack [shared-values stack-id]
(reanimated/set-shared-value (:selected-stack-id shared-values) (name stack-id))
(reanimated/set-shared-value (:home-stack-open? shared-values) true)
(when-not (colors/dark?)
(js/setTimeout
#(re-frame/dispatch [:change-root-status-bar-style :dark])
constants/shell-animation-time))
(reset! home-stack-open? true)
(reset! selected-stack-id stack-id)
(async-storage/set-item! :selected-stack-id stack-id))
(defn change-tab [shared-values stack-id]
(reanimated/set-shared-value (:animate-home-stack-left shared-values) false)
(reanimated/set-shared-value (:selected-stack-id shared-values) (name stack-id))
(reset! selected-stack-id stack-id)
(async-storage/set-item! :selected-stack-id stack-id))
(defn bottom-tab-on-press [shared-values stack-id]
(if @home-stack-open?
(change-tab shared-values stack-id)
(open-home-stack shared-values stack-id)))
(defn close-home-stack [shared-values]
(reanimated/set-shared-value (:animate-home-stack-left shared-values) true)
(reanimated/set-shared-value (:home-stack-open? shared-values) false)
(when-not (colors/dark?)
(re-frame/dispatch [:change-root-status-bar-style :light]))
(reset! home-stack-open? false)
(reset! selected-stack-id nil)
(async-storage/set-item! :selected-stack-id nil))
-55
View File
@@ -1,55 +0,0 @@
(ns status-im.switcher.bottom-tabs
(:require [quo.react-native :as rn]
[reagent.core :as reagent]
[re-frame.core :as re-frame]
[status-im.switcher.styles :as styles]
[status-im.switcher.constants :as constants]
[status-im.switcher.animation :as animation]
[quo2.components.navigation.bottom-nav-tab :as bottom-nav-tab]))
;; Reagent atoms used for lazily loading home screen tabs
(def load-communities-tab? (reagent/atom false))
(def load-chats-tab? (reagent/atom false))
(def load-wallet-tab? (reagent/atom false))
(def load-browser-tab? (reagent/atom false))
(defn load-selected-stack [stack-id]
(case stack-id
:communities-stack (reset! load-communities-tab? true)
:chats-stack (reset! load-chats-tab? true)
:wallet-stack (reset! load-wallet-tab? true)
:browser-stack (reset! load-browser-tab? true)
""))
(re-frame/reg-fx
:new-ui/reset-bottom-tabs
(fn []
(let [selected-stack-id @animation/selected-stack-id]
(reset! load-communities-tab? (= selected-stack-id :communities-stack))
(reset! load-chats-tab? (= selected-stack-id :chats-stack))
(reset! load-wallet-tab? (= selected-stack-id :wallet-stack))
(reset! load-browser-tab? (= selected-stack-id :browser-stack)))))
(defn bottom-tab-on-press [shared-values stack-id]
(when-not (= stack-id @animation/selected-stack-id)
(let [stack-load-delay (if @animation/home-stack-open? 0 constants/shell-animation-time)]
(animation/bottom-tab-on-press shared-values stack-id)
(js/setTimeout #(load-selected-stack stack-id) stack-load-delay))))
(defn bottom-tab [icon stack-id shared-values]
[bottom-nav-tab/bottom-nav-tab
{:icon icon
:icon-color-anim (get
shared-values
(get constants/tabs-icon-color-keywords stack-id))
:on-press #(bottom-tab-on-press shared-values stack-id)
:accessibility-label (str (name stack-id) "-tab")}])
(defn bottom-tabs [shared-values]
(load-selected-stack @animation/selected-stack-id)
[rn/view {:style (styles/bottom-tabs-container false)}
[rn/view {:style (styles/bottom-tabs)}
[bottom-tab :i/communities :communities-stack shared-values]
[bottom-tab :i/messages :chats-stack shared-values]
[bottom-tab :i/wallet :wallet-stack shared-values]
[bottom-tab :i/browser :browser-stack shared-values]]])

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