Compare commits
71
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66a69e5eaa | ||
|
|
afef011ac8 | ||
|
|
c76346f108 | ||
|
|
e4fb664fa5 | ||
|
|
c54830dd5b | ||
|
|
408f461ee8 | ||
|
|
183a78ae84 | ||
|
|
7529032c06 | ||
|
|
57069027c5 | ||
|
|
a27facbca4 | ||
|
|
fd133576b7 | ||
|
|
dcd06424f8 | ||
|
|
b4b403c5bb | ||
|
|
8fd2c75944 | ||
|
|
4e1efb512c | ||
|
|
efcf8b51a8 | ||
|
|
3d4dd1d59e | ||
|
|
a2d0121c08 | ||
|
|
5ecd471e59 | ||
|
|
a021f0a9bd | ||
|
|
541de5ac5f | ||
|
|
9ad254867e | ||
|
|
34d8c1621d | ||
|
|
124e23ed50 | ||
|
|
8e634aeb24 | ||
|
|
6ef0cfc2ca | ||
|
|
7b7cfe08dc | ||
|
|
598b985c72 | ||
|
|
fba363d9ea | ||
|
|
51541f7f0a | ||
|
|
1e37765197 | ||
|
|
90913500b4 | ||
|
|
6d74d0396e | ||
|
|
fd24a80904 | ||
|
|
ab53450ba8 | ||
|
|
813d96df10 | ||
|
|
6363756c09 | ||
|
|
5854a473f0 | ||
|
|
c2f0060a47 | ||
|
|
0fdb599d93 | ||
|
|
ef5153f138 | ||
|
|
463e8a5eec | ||
|
|
40e6c44b99 | ||
|
|
fc801213ef | ||
|
|
9e5b8b5f9c | ||
|
|
772efa90d4 | ||
|
|
8fb42d2503 | ||
|
|
2295b01bc9 | ||
|
|
2ee7db9370 | ||
|
|
27407b9cbb | ||
|
|
01a881523f | ||
|
|
3b5afb5d60 | ||
|
|
e5cee4b640 | ||
|
|
7948582e46 | ||
|
|
6c5242b3e0 | ||
|
|
60d6a5c3cc | ||
|
|
049822b5bb | ||
|
|
02c7460a24 | ||
|
|
10c6bf7156 | ||
|
|
d0d7310e82 | ||
|
|
219dd7cb46 | ||
|
|
9da0559b15 | ||
|
|
aa7db8b883 | ||
|
|
a06c5fdc02 | ||
|
|
2a515a82ce | ||
|
|
69294b196f | ||
|
|
58606dc87c | ||
|
|
bccf0f8d11 | ||
|
|
aab62dd19e | ||
|
|
fa9645d6dd | ||
|
|
614b03d701 |
@@ -34,4 +34,3 @@ STICKERS_TEST_ENABLED=1
|
||||
LOCAL_PAIRING_ENABLED=1
|
||||
TEST_STATEOFUS=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
FLAG_NEW_CONTACT_UI_ENABLED=0
|
||||
|
||||
@@ -375,25 +375,25 @@ test-contract: export SHADOW_NS_REGEXP := ^tests\.contract-test.*$$
|
||||
test-contract: ##@test Run contract tests
|
||||
test-contract: _test-clojure
|
||||
|
||||
android-test: jsbundle
|
||||
android-test: export TARGET := android
|
||||
android-test:
|
||||
test-android: jsbundle
|
||||
test-android: export TARGET := android
|
||||
test-android: ##@test Android Gradle test
|
||||
cd android && ./gradlew test
|
||||
|
||||
component-test-watch: export TARGET := clojure
|
||||
component-test-watch: export COMPONENT_TEST := true
|
||||
component-test-watch: export BABEL_ENV := test
|
||||
component-test-watch: export JEST_USE_SILENT_REPORTER := false
|
||||
component-test-watch: ##@ Watch tests and re-run no changes to cljs files
|
||||
test-component-watch: export TARGET := clojure
|
||||
test-component-watch: export COMPONENT_TEST := true
|
||||
test-component-watch: export BABEL_ENV := test
|
||||
test-component-watch: export JEST_USE_SILENT_REPORTER := false
|
||||
test-component-watch: ##@ Watch tests and re-run no changes to cljs files
|
||||
@scripts/check-metro-shadow-process.sh
|
||||
rm -rf ./component-spec
|
||||
nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js --testEnvironment node ' -e cljs
|
||||
|
||||
component-test: export TARGET := clojure
|
||||
component-test: export COMPONENT_TEST := true
|
||||
component-test: export BABEL_ENV := test
|
||||
component-test: export JEST_USE_SILENT_REPORTER := false
|
||||
component-test: ##@test Run component tests once in NodeJS
|
||||
test-component: export TARGET := clojure
|
||||
test-component: export COMPONENT_TEST := true
|
||||
test-component: export BABEL_ENV := test
|
||||
test-component: export JEST_USE_SILENT_REPORTER := false
|
||||
test-component: ##@test Run component tests once in NodeJS
|
||||
@scripts/check-metro-shadow-process.sh
|
||||
rm -rf ./component-spec
|
||||
yarn shadow-cljs compile component-test && \
|
||||
|
||||
+3
-6
@@ -1,9 +1,6 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
"@babel/preset-env"
|
||||
// 'module:metro-react-native-babel-preset'
|
||||
],
|
||||
/*plugins: ['react-native-reanimated/plugin', '@babel/plugin-transform-named-capturing-groups-regex'],
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
plugins: ['react-native-reanimated/plugin', '@babel/plugin-transform-named-capturing-groups-regex'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
@@ -18,5 +15,5 @@ module.exports = {
|
||||
],
|
||||
],
|
||||
},
|
||||
},*/
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -34,10 +34,10 @@ pipeline {
|
||||
}
|
||||
|
||||
environment {
|
||||
LANG = "en_US.UTF-8"
|
||||
LC_ALL = "en_US.UTF-8"
|
||||
LANGUAGE = "en_US.UTF-8"
|
||||
TARGET = "android${utils.isE2EBuild() ? "-e2e" : ""}"
|
||||
LANG = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
PLATFORM = "android${utils.isE2EBuild() ? "-e2e" : ""}"
|
||||
BUILD_ENV = 'prod'
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
triggers {
|
||||
// Nightly at 2am
|
||||
cron 'H 2 * * *'
|
||||
// Nightly at 0am
|
||||
cron 'H 0 * * *'
|
||||
}
|
||||
|
||||
parameters {
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -34,10 +34,10 @@ pipeline {
|
||||
}
|
||||
|
||||
environment {
|
||||
LANG = "en_US.UTF-8"
|
||||
LC_ALL = "en_US.UTF-8"
|
||||
LANGUAGE = "en_US.UTF-8"
|
||||
TARGET = 'ios'
|
||||
LANG = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
PLATFORM = 'ios'
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
BUNDLE_PATH = "${HOME}/.bundle"
|
||||
|
||||
+34
-41
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -29,61 +29,47 @@ pipeline {
|
||||
description: 'Specify build type. Values: pr / e2e / nightly / release',
|
||||
defaultValue: 'pr',
|
||||
)
|
||||
booleanParam(
|
||||
name: 'RUN_CONTRACT_TESTS',
|
||||
description: 'Whether to run optional and slow contract tests.',
|
||||
defaultValue: false,
|
||||
)
|
||||
}
|
||||
|
||||
environment {
|
||||
LANG = "en_US.UTF-8"
|
||||
LC_ALL = "en_US.UTF-8"
|
||||
LANGUAGE = "en_US.UTF-8"
|
||||
TARGET = 'tests'
|
||||
LANG = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
PLATFORM = 'tests'
|
||||
BUILD_ENV = 'prod'
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
LOG_FILE = utils.pkgFilename(ext: 'log', arch: 'tests')
|
||||
CLJ_LINTER_PRINT_WARNINGS = 'true'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checks') {
|
||||
stage('Test') {
|
||||
parallel {
|
||||
stage('Lint') {
|
||||
steps {
|
||||
sh """#!/bin/bash
|
||||
set -eo pipefail
|
||||
make lint CLJ_LINTER_PRINT_WARNINGS=true 2>&1 | tee ${LOG_FILE}
|
||||
"""
|
||||
}
|
||||
steps { make('lint') }
|
||||
}
|
||||
stage('Unit Tests') {
|
||||
steps {
|
||||
sh """#!/bin/bash
|
||||
set -eo pipefail
|
||||
make test-unit 2>&1 | tee -a ${LOG_FILE}
|
||||
"""
|
||||
}
|
||||
stage('Unit') {
|
||||
steps { make('test-unit') }
|
||||
}
|
||||
stage('Component') {
|
||||
steps { make('test-component') }
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Contract Tests') {
|
||||
steps {
|
||||
sh """#!/bin/bash
|
||||
set -eo pipefail
|
||||
make test-contract 2>&1 | tee -a ${LOG_FILE}
|
||||
"""
|
||||
}
|
||||
}
|
||||
stage('Integration Tests') {
|
||||
steps {
|
||||
sh """#!/bin/bash
|
||||
set -eo pipefail
|
||||
make test-integration 2>&1 | tee -a ${LOG_FILE}
|
||||
"""
|
||||
}
|
||||
}
|
||||
stage('Component Tests') {
|
||||
steps {
|
||||
sh """#!/bin/bash
|
||||
set -eo pipefail
|
||||
make component-test 2>&1 | tee -a ${LOG_FILE}
|
||||
"""
|
||||
stage('Heavy Test') {
|
||||
parallel {
|
||||
stage('Contract') {
|
||||
when { expression { params.RUN_CONTRACT_TESTS } }
|
||||
steps { make('test-contract') }
|
||||
}
|
||||
stage('Integration') {
|
||||
steps { make('test-integration') }
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Upload') {
|
||||
@@ -100,3 +86,10 @@ pipeline {
|
||||
always { sh 'make purge' }
|
||||
}
|
||||
}
|
||||
|
||||
def make(target) {
|
||||
sh """#!/bin/bash
|
||||
set -eo pipefail
|
||||
make ${target} 2>&1 | tee -a ${LOG_FILE}
|
||||
"""
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
environment {
|
||||
LANG = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
TARGET = 'ios'
|
||||
LANG = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
PLATFORM = 'ios'
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
/* avoid writing to r/o /nix */
|
||||
GEM_HOME = '~/.rubygems'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
environment {
|
||||
LANG = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
TARGET = 'ios'
|
||||
LANG = 'en_US.UTF-8'
|
||||
LANGUAGE = 'en_US.UTF-8'
|
||||
LC_ALL = 'en_US.UTF-8'
|
||||
PLATFORM = 'ios'
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
/* avoid writing to r/o /nix */
|
||||
GEM_HOME = '~/.rubygems'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env groovy
|
||||
library 'status-jenkins-lib@v1.8.7'
|
||||
library 'status-jenkins-lib@v1.8.12'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
|
||||
@@ -16,10 +16,10 @@ Both of these links are showing it for React-Testing-Library (not Native) howeve
|
||||
## Running the tests
|
||||
To run these tests there are two methods.
|
||||
|
||||
`make component-test`
|
||||
`make test-component`
|
||||
setups and runs the test suite once.
|
||||
|
||||
`make component-test-watch`
|
||||
`make test-component-watch`
|
||||
setups and runs the test suite and watches for code changes will then retrigger the test suite.
|
||||
|
||||
## Writing Tests
|
||||
@@ -38,7 +38,7 @@ There is a file of utility functions defined in "src/test_helpers/component.cljs
|
||||
## Configuration
|
||||
Status Mobile has a bespoke tech stack, as such there is more complexities to configuring the tests.
|
||||
|
||||
### Shadow-CLJS
|
||||
### Shadow-CLJS
|
||||
the configuration for compiling our tests are defined in the "shadow-cljs.edn" file.
|
||||
The three main parts of this are
|
||||
`:target :npm-module`
|
||||
@@ -47,9 +47,9 @@ Needed for the configuration we are using
|
||||
a vector of entry points for the test files.
|
||||
and the `ns-regexp` to specify what tests to find. Since we have multiple forms of tests we decided that "component-spec" is the least likely to detect the wrong file type.
|
||||
|
||||
It's worth knowing that our tests are compiled to JS and then run in the temporary folder `component-tests`.
|
||||
It's worth knowing that our tests are compiled to JS and then run in the temporary folder `component-tests`.
|
||||
|
||||
### Jest
|
||||
There is also further configuration for Jest in "test/jest". There is a jest config file which has some mostly standard configuration pieces, where the tests live, what environment variables are set etc. This is documented by Jest here: https://jestjs.io/docs/configuration
|
||||
|
||||
There is also a setup file which is used to set some global and default values. Additionally this file is used to mock some of the react native (among other) dependencies
|
||||
There is also a setup file which is used to set some global and default values. Additionally this file is used to mock some of the react native (among other) dependencies.
|
||||
|
||||
+2
-2
@@ -54,13 +54,13 @@ Here I'm showing a terminal-only experience using Tmux (left pane Emacs, right p
|
||||
To run tests:
|
||||
|
||||
```
|
||||
make component-test
|
||||
make test-component
|
||||
```
|
||||
|
||||
Also test watcher can be launched. It will re-run the entire test suite when any file is modified
|
||||
|
||||
```
|
||||
make component-test-watch
|
||||
make test-component-watch
|
||||
```
|
||||
|
||||
Check [component tests doc](./component-tests-overview.md) for more.
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
"@babel/helper-builder-react-jsx": "^7.20.0",
|
||||
"@babel/plugin-transform-block-scoping": "^7.20.0",
|
||||
"@babel/preset-env": "^7.20.0",
|
||||
"@babel/preset-es2015": "^7.0.0-beta.53",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/register": "7.0.0",
|
||||
"@jest/globals": "^25.1.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Increment a version string using Semantic Versioning (SemVer) terminology.
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
;; To match the folder created by Nix build of JSBundle.
|
||||
:output-dir "result"
|
||||
:init-fn status-im.core/init
|
||||
:build-hooks [(status-im.setup.build-hooks.worklets/transform-output)]
|
||||
;; When false, the Shadow-CLJS watcher won't automatically refresh
|
||||
;; the target files (a.k.a hot reload). When false, you can manually
|
||||
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { withTiming, runOnJS } from 'react-native-reanimated';
|
||||
import { useAnimatedReaction, withTiming, runOnJS } from 'react-native-reanimated';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callback) {
|
||||
return function (event) {
|
||||
@@ -12,3 +13,21 @@ export function messagesListOnScroll(distanceFromListTop, chatListScrollY, callb
|
||||
runOnJS(callback)(layoutHeight, newDistance);
|
||||
};
|
||||
}
|
||||
|
||||
export function useMessagesScrolledToThreshold(distanceFromListTop, threshold) {
|
||||
const [scrolledToThreshold, setScrolledToThreshold] = useState(false);
|
||||
|
||||
useAnimatedReaction(
|
||||
function () {
|
||||
return distanceFromListTop.value <= threshold;
|
||||
},
|
||||
function (current) {
|
||||
if (current !== scrolledToThreshold) {
|
||||
runOnJS(setScrolledToThreshold)(current);
|
||||
}
|
||||
},
|
||||
[scrolledToThreshold],
|
||||
);
|
||||
|
||||
return scrolledToThreshold;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@ export function navigationHeaderPosition(distanceFromListTop, isAllLoaded, topBa
|
||||
});
|
||||
}
|
||||
|
||||
export function navigationButtonsCompleteOpacity(isCalculationComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationComplete.value ? withTiming(1) : 0;
|
||||
});
|
||||
}
|
||||
|
||||
export function interpolateNavigationViewOpacity(props) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.common.universal-links :as links]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.events :as chat.events]
|
||||
@@ -654,12 +655,11 @@
|
||||
stored-bookmarks)]
|
||||
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
|
||||
|
||||
(rf/defn initialize-browser
|
||||
[_]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_getBrowsers"
|
||||
:on-success #(re-frame/dispatch [::initialize-browsers %])}
|
||||
{:method "browsers_getBookmarks"
|
||||
:on-success #(re-frame/dispatch [::initialize-bookmarks %])}
|
||||
{:method "permissions_getDappPermissions"
|
||||
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
|
||||
(re-frame/reg-fx :browser/initialize-browser
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_getBrowsers"
|
||||
:on-success [::initialize-browsers]})
|
||||
(json-rpc/call {:method "browsers_getBookmarks"
|
||||
:on-success [::initialize-bookmarks]})
|
||||
(json-rpc/call {:method "permissions_getDappPermissions"
|
||||
:on-success [::initialize-dapp-permissions]})))
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[legacy.status-im.chat.models.loading :as chat.loading]
|
||||
[legacy.status-im.data-store.messages :as data-store.messages]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message]
|
||||
[status-im.contexts.chat.messenger.messages.list.events :as message-list]
|
||||
@@ -135,9 +134,7 @@
|
||||
message-id (:messageId removed-message)]
|
||||
(data-store.messages/mark-messages-seen chat-id
|
||||
[message-id]
|
||||
#(re-frame/dispatch
|
||||
[:chat/decrease-unviewed-count
|
||||
chat-id %3]))))
|
||||
nil)))
|
||||
removed-messages)
|
||||
remove-messages-fx (fn [{:keys [db]}]
|
||||
{:dispatch [:activity-center.notifications/fetch-unread-count]})]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
legacy.status-im.communities.e2e
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.contexts.shell.activity-center.events :as activity-center]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -84,13 +83,12 @@
|
||||
(navigation/navigate-back)
|
||||
(handle-response response-js)))
|
||||
|
||||
(rf/defn member-banned
|
||||
{:events [::member-banned]}
|
||||
[cofx response-js]
|
||||
(rf/merge cofx
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
(handle-response response-js)
|
||||
(activity-center/notifications-fetch-unread-count)))
|
||||
(re-frame/reg-event-fx ::member-banned
|
||||
(fn [{:keys [db]} [response-js]]
|
||||
{:db (assoc db :bottom-sheet/show? false)
|
||||
:fx [[:dismiss-bottom-sheet-overlay-old]
|
||||
[:sanitize-messages-and-process-response response-js]
|
||||
[:activity-center.notifications/fetch-unread-count]]}))
|
||||
|
||||
(rf/defn member-ban
|
||||
{:events [::member-ban]}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.contexts.chat.contacts.events :as contacts-store]
|
||||
[status-im.contexts.chat.messenger.messages.list.events :as message-list]
|
||||
[status-im.contexts.shell.activity-center.events :as activity-center]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -45,21 +44,23 @@
|
||||
(apply
|
||||
rf/merge
|
||||
cofx
|
||||
{:db (->
|
||||
db
|
||||
(update :chats dissoc public-key)
|
||||
(update :chats-home-list disj public-key)
|
||||
(assoc-in [:contacts/contacts public-key
|
||||
:added?]
|
||||
false))
|
||||
:dispatch [:shell/close-switcher-card public-key]
|
||||
:effects/push-notifications-clear-message-notifications [public-key]}
|
||||
(activity-center/notifications-fetch-unread-count)
|
||||
{:db (->
|
||||
db
|
||||
(update :chats dissoc public-key)
|
||||
(update :chats-home-list disj public-key)
|
||||
(assoc-in [:contacts/contacts public-key
|
||||
:added?]
|
||||
false))
|
||||
:fx [[:activity-center.notifications/fetch-unread-count]
|
||||
[:effects/push-notifications-clear-message-notifications [public-key]]
|
||||
[:dispatch [:shell/close-switcher-card public-key]]]}
|
||||
fxs)))
|
||||
|
||||
(rf/defn block-contact
|
||||
{:events [:contact.ui/block-contact-confirmed]}
|
||||
[{:keys [db] :as cofx} public-key]
|
||||
[{:keys [db] :as cofx} public-key
|
||||
{:keys [handle-navigation?]
|
||||
:or {handle-navigation? true}}]
|
||||
(let [contact (-> (contact.db/public-key->contact
|
||||
(:contacts/contacts db)
|
||||
public-key)
|
||||
@@ -76,9 +77,10 @@
|
||||
(re-frame/dispatch [:sanitize-messages-and-process-response block-contact])
|
||||
(re-frame/dispatch [:hide-popover])))
|
||||
;; reset navigation to avoid going back to non existing one to one chat
|
||||
(if from-one-to-one-chat?
|
||||
(navigation/pop-to-root :shell-stack)
|
||||
(navigation/navigate-back)))))
|
||||
(when handle-navigation?
|
||||
(if from-one-to-one-chat?
|
||||
(navigation/pop-to-root :shell-stack)
|
||||
(navigation/navigate-back))))))
|
||||
|
||||
(rf/defn contact-unblocked
|
||||
{:events [:contacts/unblocked]}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
:line-count nil
|
||||
:links nil
|
||||
:text nil}
|
||||
:bridge-message nil
|
||||
:outgoing false}
|
||||
:message nil
|
||||
:reply-message {:quoted-message nil
|
||||
@@ -61,6 +62,7 @@
|
||||
:line-count nil
|
||||
:links nil
|
||||
:text nil}
|
||||
:bridge-message nil
|
||||
:outgoing false}}
|
||||
(-> raw-notification
|
||||
store/<-rpc
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
(ns legacy.status-im.data-store.chats
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.data-store.messages :as messages]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn rpc->type
|
||||
[{:keys [chat-type name] :as chat}]
|
||||
@@ -58,69 +60,80 @@
|
||||
:admins #{}
|
||||
:members-joined #{})))
|
||||
|
||||
(defn <-color
|
||||
[value]
|
||||
(if (and (some? value)
|
||||
(string/starts-with? value "#"))
|
||||
value
|
||||
(keyword value)))
|
||||
|
||||
(defn <-rpc
|
||||
[chat]
|
||||
(-> chat
|
||||
(set/rename-keys {:id :chat-id
|
||||
:communityId :community-id
|
||||
:syncedFrom :synced-from
|
||||
:syncedTo :synced-to
|
||||
:membershipUpdateEvents :membership-update-events
|
||||
:deletedAtClockValue :deleted-at-clock-value
|
||||
:chatType :chat-type
|
||||
:unviewedMessagesCount :unviewed-messages-count
|
||||
:unviewedMentionsCount :unviewed-mentions-count
|
||||
:lastMessage :last-message
|
||||
:lastClockValue :last-clock-value
|
||||
:invitationAdmin :invitation-admin
|
||||
:profile :profile-public-key
|
||||
:muteTill :muted-till})
|
||||
(set/rename-keys {:id :chat-id
|
||||
:communityId :community-id
|
||||
:syncedFrom :synced-from
|
||||
:syncedTo :synced-to
|
||||
:membershipUpdateEvents :membership-update-events
|
||||
:deletedAtClockValue :deleted-at-clock-value
|
||||
:chatType :chat-type
|
||||
:unviewedMessagesCount :unviewed-messages-count
|
||||
:unviewedMentionsCount :unviewed-mentions-count
|
||||
:lastMessage :last-message
|
||||
:lastClockValue :last-clock-value
|
||||
:invitationAdmin :invitation-admin
|
||||
:profile :profile-public-key
|
||||
:muteTill :muted-till
|
||||
:hideIfPermissionsNotMet :hide-if-permissions-not-met?})
|
||||
rpc->type
|
||||
unmarshal-members
|
||||
(update :last-message #(when % (messages/<-rpc %)))
|
||||
(update :color <-color)
|
||||
(dissoc :members)))
|
||||
|
||||
(defn <-rpc-js
|
||||
[^js chat]
|
||||
(-> {:name (.-name chat)
|
||||
:description (.-description chat)
|
||||
:color (.-color chat)
|
||||
:emoji (.-emoji chat)
|
||||
:timestamp (.-timestamp chat)
|
||||
:alias (.-alias chat)
|
||||
:muted (.-muted chat)
|
||||
:joined (.-joined chat)
|
||||
:muted-till (.-muteTill chat)
|
||||
:chat-id (.-id chat)
|
||||
:community-id (.-communityId chat)
|
||||
:synced-from (.-syncedFrom chat)
|
||||
:synced-to (.-syncedTo chat)
|
||||
:deleted-at-clock-value (.-deletedAtClockValue chat)
|
||||
:chat-type (.-chatType chat)
|
||||
:unviewed-messages-count (.-unviewedMessagesCount chat)
|
||||
:unviewed-mentions-count (.-unviewedMentionsCount chat)
|
||||
:last-message {:content {:text (.-text chat)
|
||||
:parsed-text (types/js->clj (.-parsedText chat))
|
||||
:response-to (.-responseTo chat)}
|
||||
:content-type (.-contentType chat)
|
||||
:community-id (.-contentCommunityId chat)
|
||||
:outgoing (boolean (.-outgoingStatus chat))
|
||||
:album-images-count (.-albumImagesCount chat)
|
||||
:from (.-from chat)
|
||||
:deleted? (.-deleted chat)
|
||||
:deleted-for-me? (.-deletedForMe chat)}
|
||||
:last-clock-value (.-lastClockValue chat)
|
||||
:profile-public-key (.-profile chat)
|
||||
:highlight (.-highlight chat)
|
||||
:active (.-active chat)
|
||||
:members (types/js->clj (.-members chat))}
|
||||
(-> {:name (.-name chat)
|
||||
:description (.-description chat)
|
||||
:color (<-color (.-color chat))
|
||||
:emoji (.-emoji chat)
|
||||
:timestamp (.-timestamp chat)
|
||||
:alias (.-alias chat)
|
||||
:muted (.-muted chat)
|
||||
:joined (.-joined chat)
|
||||
:muted-till (.-muteTill chat)
|
||||
:chat-id (.-id chat)
|
||||
:community-id (.-communityId chat)
|
||||
:synced-from (.-syncedFrom chat)
|
||||
:synced-to (.-syncedTo chat)
|
||||
:deleted-at-clock-value (.-deletedAtClockValue chat)
|
||||
:chat-type (.-chatType chat)
|
||||
:unviewed-messages-count (.-unviewedMessagesCount chat)
|
||||
:unviewed-mentions-count (.-unviewedMentionsCount chat)
|
||||
:last-message {:content {:text (.-text chat)
|
||||
:parsed-text (types/js->clj (.-parsedText
|
||||
chat))
|
||||
:response-to (.-responseTo chat)}
|
||||
:content-type (.-contentType chat)
|
||||
:community-id (.-contentCommunityId chat)
|
||||
:outgoing (boolean (.-outgoingStatus chat))
|
||||
:album-images-count (.-albumImagesCount chat)
|
||||
:from (.-from chat)
|
||||
:deleted? (.-deleted chat)
|
||||
:deleted-for-me? (.-deletedForMe chat)}
|
||||
:last-clock-value (.-lastClockValue chat)
|
||||
:profile-public-key (.-profile chat)
|
||||
:highlight (.-highlight chat)
|
||||
:active (.-active chat)
|
||||
:members (types/js->clj (.-members chat))
|
||||
:hide-if-permissions-not-met (.-hideIfPermissionsNotMet chat)}
|
||||
rpc->type
|
||||
unmarshal-members))
|
||||
|
||||
(rf/defn fetch-chats-preview
|
||||
[_ {:keys [on-success]}]
|
||||
{:json-rpc/call [{:method "wakuext_chatsPreview"
|
||||
:params []
|
||||
:js-response true
|
||||
:on-success #(on-success ^js %)
|
||||
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
|
||||
(re-frame/reg-fx :fetch-chats-preview
|
||||
(fn [{:keys [on-success]}]
|
||||
(json-rpc/call {:method "wakuext_chatsPreview"
|
||||
:params []
|
||||
:js-response true
|
||||
:on-success #(on-success ^js %)
|
||||
:on-error #(log/error "failed to fetch chats" 0 -1 %)})))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
(deftest normalize-chat-test
|
||||
(let [chat {:id "chat-id"
|
||||
:color "color"
|
||||
:color "yellow"
|
||||
:name "name"
|
||||
:chatType 3
|
||||
:members [{:id "a"
|
||||
@@ -26,7 +26,7 @@
|
||||
:timestamp 2}
|
||||
expected-chat {:public? false
|
||||
:group-chat true
|
||||
:color "color"
|
||||
:color :yellow
|
||||
:chat-name "name"
|
||||
:contacts #{"a" "b" "c" "d"}
|
||||
:chat-type 3
|
||||
|
||||
@@ -27,9 +27,11 @@
|
||||
(assoc acc
|
||||
(name k)
|
||||
(-> v
|
||||
(assoc :token-gated? (:tokenGated v)
|
||||
:can-post? (:canPost v))
|
||||
(dissoc :canPost :tokenGated)
|
||||
(assoc :token-gated? (:tokenGated v)
|
||||
:can-post? (:canPost v)
|
||||
:can-view? (:canView v)
|
||||
:hide-if-permissions-not-met? (:hideIfPermissionsNotMet v))
|
||||
(dissoc :canPost :tokenGated :canView :hideIfPermissionsNotMet)
|
||||
(update :members walk/stringify-keys))))
|
||||
{}
|
||||
chats))
|
||||
@@ -62,6 +64,7 @@
|
||||
:canJoin :can-join?
|
||||
:requestedToJoinAt :requested-to-join-at
|
||||
:isMember :is-member?
|
||||
:outroMessage :outro-message
|
||||
:adminSettings :admin-settings
|
||||
:tokenPermissions :token-permissions
|
||||
:communityTokensMetadata :tokens-metadata
|
||||
|
||||
@@ -82,7 +82,13 @@
|
||||
:albumImagesCount :album-images-count
|
||||
:displayName :display-name
|
||||
:linkPreviews :link-previews
|
||||
:statusLinkPreviews :status-link-previews})
|
||||
:statusLinkPreviews :status-link-previews
|
||||
:bridgeMessage :bridge-message})
|
||||
(update :bridge-message
|
||||
set/rename-keys
|
||||
{:bridgeName :bridge-name
|
||||
:userName :user-name
|
||||
:userAvatar :user-avatar})
|
||||
(update :link-previews #(map <-link-preview-rpc %))
|
||||
(update :status-link-previews #(map <-status-link-previews-rpc %))
|
||||
(update :quoted-message
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
:image nil
|
||||
:response-to "a"
|
||||
:links nil}
|
||||
:bridge-message nil
|
||||
:whisper-timestamp 1
|
||||
:contact-verification-state 1
|
||||
:contact-request-state 2
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[clojure.walk :as walk]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -32,11 +34,11 @@
|
||||
:on-success #()
|
||||
:on-error #()}]})
|
||||
|
||||
(rf/defn fetch-switcher-cards-rpc
|
||||
[_]
|
||||
{:json-rpc/call [{:method "wakuext_switcherCards"
|
||||
:params []
|
||||
:on-success #(rf/dispatch
|
||||
[:shell/switcher-cards-loaded
|
||||
(:switcherCards ^js %)])
|
||||
:on-error #(log/error "Failed to fetch switcher cards" %)}]})
|
||||
(re-frame/reg-fx :switcher-cards/fetch
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_switcherCards"
|
||||
:params []
|
||||
:on-success #(rf/dispatch
|
||||
[:shell/switcher-cards-loaded
|
||||
(:switcherCards ^js %)])
|
||||
:on-error #(log/error "Failed to fetch switcher cards" %)})))
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn <-rpc
|
||||
[visibility-status-update]
|
||||
@@ -18,13 +18,13 @@
|
||||
{:current-user-status :current-user-visibility-status})
|
||||
(update :current-user-visibility-status <-rpc)))
|
||||
|
||||
(rf/defn fetch-visibility-status-updates-rpc
|
||||
[_]
|
||||
{:json-rpc/call [{:method "wakuext_statusUpdates"
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch
|
||||
[:visibility-status-updates/visibility-status-updates-loaded
|
||||
(:statusUpdates ^js %)])
|
||||
:on-error #(log/error
|
||||
"failed to fetch visibility-status-updates"
|
||||
%)}]})
|
||||
(re-frame/reg-fx :visibility-status-updates/fetch
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_statusUpdates"
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch
|
||||
[:visibility-status-updates/visibility-status-updates-loaded
|
||||
(:statusUpdates ^js %)])
|
||||
:on-error #(log/error
|
||||
"failed to fetch visibility-status-updates"
|
||||
%)})))
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
|
||||
(rf/defn tx-history-end-reached
|
||||
[{:keys [db] :as cofx} address]
|
||||
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
|
||||
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? db)]
|
||||
{:db (assoc-in db
|
||||
[:wallet-legacy :fetching address :all-fetched?]
|
||||
(if syncing-allowed?
|
||||
@@ -327,7 +327,7 @@
|
||||
{:chain-tokens (:wallet-legacy/all-tokens db)
|
||||
:addresses [address]
|
||||
:before-block min-known-block
|
||||
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
|
||||
:fetch-more? (utils.mobile-sync/syncing-allowed? db)
|
||||
;; Transfers are requested before and including `min-known-block` because there is no
|
||||
;; guarantee that all transfers from that block are shown already. To make sure that we fetch
|
||||
;; the whole `default-transfers-limit` of transfers the number of transfers already received
|
||||
|
||||
@@ -8,11 +8,16 @@
|
||||
legacy.status-im.chat.models.loading
|
||||
legacy.status-im.contact.block
|
||||
legacy.status-im.currency.core
|
||||
legacy.status-im.data-store.chats
|
||||
legacy.status-im.data-store.switcher-cards
|
||||
legacy.status-im.data-store.visibility-status-updates
|
||||
legacy.status-im.fleet.core
|
||||
legacy.status-im.group-chats.core
|
||||
[legacy.status-im.keycard.core :as keycard]
|
||||
legacy.status-im.log-level.core
|
||||
legacy.status-im.mailserver.constants
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
legacy.status-im.mobile-sync-settings.core
|
||||
legacy.status-im.multiaccounts.login.core
|
||||
legacy.status-im.multiaccounts.logout.core
|
||||
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
[legacy.status-im.data-store.invitations :as data-store.invitations]
|
||||
[oops.core :as oops]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.events :as chat.events]
|
||||
[status-im.contexts.shell.activity-center.events :as activity-center]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -19,15 +19,13 @@
|
||||
(when (get-in cofx [:db :chats chat-id])
|
||||
(chat.events/pop-to-root-and-navigate-to-chat cofx chat-id nil)))
|
||||
|
||||
(rf/defn handle-chat-removed
|
||||
{:events [:chat-removed]}
|
||||
[cofx response chat-id]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc (:db cofx) :current-chat-id)
|
||||
:dispatch-n [[:shell/close-switcher-card chat-id]
|
||||
[:sanitize-messages-and-process-response response]
|
||||
[:pop-to-root :shell-stack]]}
|
||||
(activity-center/notifications-fetch-unread-count)))
|
||||
(re-frame/reg-event-fx :chat-removed
|
||||
(fn [{:keys [db]} [response chat-id]]
|
||||
{:db (dissoc db :current-chat-id)
|
||||
:fx [[:dispatch [:shell/close-switcher-card chat-id]]
|
||||
[:dispatch [:sanitize-messages-and-process-response response]]
|
||||
[:dispatch [:pop-to-root :shell-stack]]
|
||||
[:activity-center.notifications/fetch-unread-count]]}))
|
||||
|
||||
(rf/defn handle-chat-update
|
||||
{:events [:chat-updated]}
|
||||
@@ -66,16 +64,6 @@
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
||||
|
||||
(rf/defn create
|
||||
{: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)]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
|
||||
|
||||
(rf/defn create-from-link
|
||||
{:events [:group-chats/create-from-link]}
|
||||
[cofx {:keys [chat-id invitation-admin chat-name]}]
|
||||
@@ -264,8 +252,7 @@
|
||||
{}
|
||||
invitations))})
|
||||
|
||||
(rf/defn get-group-chat-invitations
|
||||
[_]
|
||||
{:json-rpc/call
|
||||
[{:method "wakuext_getGroupChatInvitations"
|
||||
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
|
||||
(re-frame/reg-fx :group-chats/get-group-chat-invitations
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_getGroupChatInvitations"
|
||||
:on-success [::initialize-invitations]})))
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[legacy.status-im.node.core :as node]
|
||||
[legacy.status-im.utils.mobile-sync :as mobile-network-utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -61,7 +62,7 @@
|
||||
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
|
||||
|
||||
(defn fetch-use-mailservers?
|
||||
[{:keys [db]}]
|
||||
[db]
|
||||
(get-in db [:profile/profile :use-mailservers?]))
|
||||
|
||||
(defonce showing-connection-error-popup? (atom false))
|
||||
@@ -117,24 +118,32 @@
|
||||
[{:keys [db] :as cofx}]
|
||||
{:db (dissoc db :mailserver/current-request)})
|
||||
|
||||
(defn needs-to-fetch-historic-messages?
|
||||
[db]
|
||||
(and
|
||||
(:messenger/started? db)
|
||||
(mobile-network-utils/syncing-allowed? db)
|
||||
(fetch-use-mailservers? db)
|
||||
(not (:mailserver/current-request db))))
|
||||
|
||||
(rf/defn process-next-messages-request
|
||||
{:events [::request-messages]}
|
||||
[{:keys [db now] :as cofx}]
|
||||
(when (and
|
||||
(:messenger/started? db)
|
||||
(mobile-network-utils/syncing-allowed? cofx)
|
||||
(fetch-use-mailservers? cofx)
|
||||
(not (:mailserver/current-request db)))
|
||||
{:db (assoc db :mailserver/current-request true)
|
||||
:json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
|
||||
:params [false]
|
||||
:js-response true
|
||||
:on-success #(do
|
||||
(log/info "fetched historical messages")
|
||||
(re-frame/dispatch [::request-success %]))
|
||||
:on-error #(do
|
||||
(log/error "failed retrieve historical messages" %)
|
||||
(re-frame/dispatch [::request-error]))}]}))
|
||||
[{:keys [db]}]
|
||||
(when (needs-to-fetch-historic-messages? db)
|
||||
{:db (assoc db :mailserver/current-request true)
|
||||
:mailserver/request-all-historic-messages nil}))
|
||||
|
||||
(re-frame/reg-fx :mailserver/request-all-historic-messages
|
||||
(fn []
|
||||
(json-rpc/call {:method "wakuext_requestAllHistoricMessagesWithRetries"
|
||||
:params [false]
|
||||
:js-response true
|
||||
:on-success #(do
|
||||
(log/info "fetched historical messages")
|
||||
(re-frame/dispatch [::request-success %]))
|
||||
:on-error #(do
|
||||
(log/error "failed retrieve historical messages" %)
|
||||
(re-frame/dispatch [::request-error]))})))
|
||||
|
||||
(rf/defn handle-mailserver-changed
|
||||
[{:keys [db] :as cofx} ms]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.utils.mobile-sync :as utils]
|
||||
[status-im.contexts.chat.home.add-new-contact.events :as add-new-contact]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -18,27 +18,24 @@
|
||||
(or (nil? remember-choice?)
|
||||
remember-choice?))}))
|
||||
|
||||
(rf/defn on-network-status-change
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [initialized? (get db :network-status/initialized?)
|
||||
logged-in? (multiaccounts.model/logged-in? db)
|
||||
{:keys [remember-syncing-choice?]} (:profile/profile db)]
|
||||
(apply
|
||||
rf/merge
|
||||
cofx
|
||||
{:db (assoc db :network-status/initialized? true)}
|
||||
(cond
|
||||
;; NOTE(rasom): When we log into account on-network-status-change is
|
||||
;; dispatched, but that doesn't mean there was a status change, thus
|
||||
;; no reason to restart wallet.
|
||||
(and logged-in? initialized?)
|
||||
[(mailserver/process-next-messages-request)
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
#(add-new-contact/set-new-identity-reconnected %)]
|
||||
|
||||
logged-in?
|
||||
[(mailserver/process-next-messages-request)
|
||||
(bottom-sheet/hide-bottom-sheet-old)]))))
|
||||
(re-frame/reg-event-fx :mobile-network/on-network-status-change
|
||||
(fn [{:keys [db]}]
|
||||
(let [previously-initialized? (get db :network-status/initialized?)
|
||||
logged-in? (multiaccounts.model/logged-in? db)
|
||||
fetch-historic-messages? (mailserver/needs-to-fetch-historic-messages? db)]
|
||||
(if logged-in?
|
||||
{:db (cond-> (-> db
|
||||
(assoc :network-status/initialized? true)
|
||||
(assoc :bottom-sheet/show? false))
|
||||
fetch-historic-messages?
|
||||
(assoc :mailserver/current-request true))
|
||||
:fx [(when fetch-historic-messages?
|
||||
[:mailserver/request-all-historic-messages])
|
||||
[:dismiss-bottom-sheet-overlay-old]
|
||||
(when previously-initialized?
|
||||
(let [new-identity-input (get-in db [:contacts/new-identity :input])]
|
||||
[:dispatch [:contacts/set-new-identity {:input new-identity-input}]]))]}
|
||||
{:db (assoc db :network-status/initialized? true)}))))
|
||||
|
||||
(defn apply-settings
|
||||
([sync?] (apply-settings sync? :default))
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
(rf/merge cofx
|
||||
{:effects.shell/reset-state nil
|
||||
{:set-root :progress
|
||||
:effects.shell/reset-state nil
|
||||
:hide-popover nil
|
||||
::logout nil
|
||||
:profile.settings/webview-debug-changed false
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns legacy.status-im.network.net-info
|
||||
(:require
|
||||
["@react-native-community/netinfo" :default net-info]
|
||||
[legacy.status-im.mobile-sync-settings.core :as mobile-network]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -13,11 +12,11 @@
|
||||
{:db (assoc db :network-status (if is-connected? :online :offline))}))
|
||||
|
||||
(rf/defn change-network-type
|
||||
[{:keys [db] :as cofx} old-network-type network-type expensive?]
|
||||
[{:keys [db] :as cofx} network-type expensive?]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :network/type network-type)
|
||||
:network/notify-status-go [network-type expensive?]}
|
||||
(mobile-network/on-network-status-change)))
|
||||
:network/notify-status-go [network-type expensive?]
|
||||
:dispatch [:mobile-network/on-network-status-change]}))
|
||||
|
||||
(rf/defn handle-network-info-change
|
||||
{:events [::network-info-changed]}
|
||||
@@ -37,7 +36,7 @@
|
||||
(when-not status-changed?
|
||||
(change-network-status isConnected))
|
||||
(when-not type-changed?
|
||||
(change-network-type old-network-type type (:is-connection-expensive details))))))
|
||||
(change-network-type type (:is-connection-expensive details))))))
|
||||
|
||||
(defn add-net-info-listener
|
||||
[]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.constants :as constants]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -22,6 +23,21 @@
|
||||
:params [(chain/chain-id db) id]
|
||||
:on-success #()}]}))
|
||||
|
||||
(re-frame/reg-fx :stickers/load-packs
|
||||
(fn [chain-id]
|
||||
(json-rpc/call {:method "stickers_market"
|
||||
:params [chain-id]
|
||||
:on-success [:stickers/stickers-market-success]})
|
||||
(json-rpc/call {:method "stickers_installed"
|
||||
:params []
|
||||
:on-success [:stickers/stickers-installed-success]})
|
||||
(json-rpc/call {:method "stickers_pending"
|
||||
:params []
|
||||
:on-success [:stickers/stickers-pending-success]})
|
||||
(json-rpc/call {:method "stickers_recent"
|
||||
:params []
|
||||
:on-success [:stickers/stickers-recent-success]})))
|
||||
|
||||
(rf/defn load-packs
|
||||
{:events [:stickers/load-packs]}
|
||||
[{:keys [db]}]
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
(re-frame/reg-sub
|
||||
:mailserver/use-status-nodes?
|
||||
(fn [db _]
|
||||
(boolean (mailserver/fetch-use-mailservers? {:db db}))))
|
||||
(boolean (mailserver/fetch-use-mailservers? db))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver.edit/validation-errors
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
(reg-root-key-sub :peers-count :peers-count)
|
||||
(reg-root-key-sub :peers-summary :peers-summary)
|
||||
(reg-root-key-sub :web3-node-version :web3-node-version)
|
||||
(reg-root-key-sub :alert-banners :alert-banners)
|
||||
|
||||
;;keycard
|
||||
(reg-root-key-sub :keycard :keycard)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[legacy.status-im.react-native.resources :as resources]
|
||||
[legacy.status-im.ui.components.colors :as quo.colors]
|
||||
[legacy.status-im.ui.components.fast-image :as fast-image]
|
||||
[legacy.status-im.ui.screens.chat.message.legacy-style :as style]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
@@ -145,23 +144,6 @@
|
||||
[rn/text {:style (style/status-text)}]
|
||||
(-> content :parsed-text peek :children))]])
|
||||
|
||||
;; EMOJI
|
||||
(defn emoji
|
||||
[]
|
||||
(fn [{:keys [content] :as message}]
|
||||
[rn/view (style/message-view message)
|
||||
[rn/view {:style (style/message-view-content)}
|
||||
[rn/view {:style (style/style-message-text)}
|
||||
[rn/text {:style (style/emoji-message message)}
|
||||
(:text content)]]]]))
|
||||
|
||||
;; STICKER
|
||||
(defn sticker
|
||||
[{:keys [content]}]
|
||||
[fast-image/fast-image
|
||||
{:style {:margin 10 :width 140 :height 140}
|
||||
:source {:uri (str (-> content :sticker :url) "&download=true")}}])
|
||||
|
||||
(defn contact-request-status-pending
|
||||
[]
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
{:active (= value id)
|
||||
:accessory :radio
|
||||
:title (get titles id)
|
||||
:on-press #(re-frame/dispatch [:profile.settings/update-value :default-sync-period id])}])
|
||||
:on-press #(re-frame/dispatch [:profile.settings/profile-update :default-sync-period id])}])
|
||||
|
||||
(views/defview default-sync-period-settings
|
||||
[]
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
:subtitle (i18n/label :t/webview-camera-permission-requests-subtitle)
|
||||
:subtitle-max-lines 2
|
||||
:on-press #(re-frame/dispatch
|
||||
[:profile.settings/update-value
|
||||
[:profile.settings/profile-update
|
||||
:webview-allow-permission-requests?
|
||||
((complement boolean) webview-allow-permission-requests?)])}])
|
||||
[separator]
|
||||
@@ -169,8 +169,7 @@
|
||||
{:active (= value id)
|
||||
:accessory :radio
|
||||
:title (get titles id)
|
||||
:on-press #(re-frame/dispatch [:profile.settings/update-value :profile-pictures-visibility
|
||||
id])}])
|
||||
:on-press #(re-frame/dispatch [:profile.settings/profile-update :profile-pictures-visibility id])}])
|
||||
|
||||
(views/defview profile-pic
|
||||
[]
|
||||
|
||||
@@ -51,4 +51,4 @@
|
||||
:icon :main-icons/delete
|
||||
:theme :accent
|
||||
:title (i18n/label :t/profile-pic-remove)
|
||||
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture nil])}])]))
|
||||
:on-press #(re-frame/dispatch [:profile.settings/delete-profile-picture])}])]))
|
||||
|
||||
@@ -91,11 +91,6 @@
|
||||
:options {:insets {:top? true}}
|
||||
:component stickers/pack}
|
||||
|
||||
{:name :new-group
|
||||
:options {:insets {:top? true}}
|
||||
;;TODO custom subtitle
|
||||
:component group-chat/new-group}
|
||||
|
||||
{:name :currency-settings
|
||||
:options {:topBar (topbar-options :t/main-currency)
|
||||
:insets {:top? true}}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.mail :as react-native-mail]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.common.log :as log]
|
||||
[status-im.config :as config]
|
||||
[utils.datetime :as datetime]
|
||||
@@ -31,11 +32,10 @@
|
||||
[{:keys [db]} node-version]
|
||||
{:db (assoc db :web3-node-version node-version)})
|
||||
|
||||
(rf/defn initialize-web3-client-version
|
||||
{:events [:logging/initialize-web3-client-version]}
|
||||
[_]
|
||||
{:json-rpc/call [{:method "web3_clientVersion"
|
||||
:on-success #(re-frame/dispatch [:logging/store-web3-client-version %])}]})
|
||||
(re-frame/reg-fx :logging/initialize-web3-client-version
|
||||
(fn []
|
||||
(json-rpc/call {:method "web3_clientVersion"
|
||||
:on-success [:logging/store-web3-client-version]})))
|
||||
|
||||
(defn extract-url-components
|
||||
[address]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
(= network-type "cellular"))
|
||||
|
||||
(defn syncing-allowed?
|
||||
[{:keys [db]}]
|
||||
[db]
|
||||
(let [network (:network/type db)
|
||||
{:keys [syncing-on-mobile-network?]} (:profile/profile db)]
|
||||
(or (= network "wifi")
|
||||
|
||||
@@ -2,10 +2,17 @@
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(defn- get-dimensions
|
||||
[size]
|
||||
(case size
|
||||
:size-24 24
|
||||
:size-20 20
|
||||
nil))
|
||||
|
||||
(defn collection-avatar
|
||||
[theme]
|
||||
{:width 24
|
||||
:height 24
|
||||
[theme size]
|
||||
{:width (get-dimensions size)
|
||||
:height (get-dimensions size)
|
||||
:border-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
|
||||
:border-radius 6})
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
:image - collection image
|
||||
:theme - keyword -> :light/:dark"
|
||||
[{:keys [image theme]}]
|
||||
[{:keys [image theme size] :or {size :size-24}}]
|
||||
[fast-image/fast-image
|
||||
{:accessibility-label :collection-avatar
|
||||
:source image
|
||||
:style (style/collection-avatar theme)}])
|
||||
:style (style/collection-avatar theme size)}])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
:or {size :size-20
|
||||
customization-color :blue
|
||||
picture nil
|
||||
icon-name :i/group}}]
|
||||
icon-name :i/members}}]
|
||||
(let [container-size (get-in sizes [size :container])
|
||||
icon-size (get-in sizes [size :icon])]
|
||||
[rn/view
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
[quo.components.colors.color.constants :as constants]
|
||||
[quo.components.colors.color.view :as color]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]))
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]))
|
||||
|
||||
(defn get-item-layout
|
||||
[_ index]
|
||||
@@ -52,7 +53,7 @@
|
||||
:index index
|
||||
:viewPosition 0.5})))))
|
||||
50)))
|
||||
[rn/flat-list
|
||||
[gesture/flat-list
|
||||
{:ref on-ref
|
||||
;; TODO: using :feng-shui? temporarily while b & w is being developed.
|
||||
;; https://github.com/status-im/status-mobile/discussions/16676
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
(ns quo.components.community.channel-action.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(defn channel-action-container
|
||||
[{:keys [big? disabled?]}]
|
||||
(cond-> {}
|
||||
disabled? (assoc :opacity 0.3)
|
||||
big? (assoc :flex-grow 1)
|
||||
(not big?) (assoc :width 104)))
|
||||
|
||||
(defn channel-action
|
||||
[{:keys [color pressed? theme]}]
|
||||
{:height 102
|
||||
:padding 12
|
||||
:border-radius 16
|
||||
:background-color (colors/resolve-color color theme (if pressed? 20 10))
|
||||
:justify-content :space-between})
|
||||
|
||||
(def channel-action-row
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center})
|
||||
@@ -0,0 +1,39 @@
|
||||
(ns quo.components.community.channel-action.view
|
||||
(:require
|
||||
[quo.components.community.channel-action.style :as style]
|
||||
[quo.components.counter.counter.view :as counter]
|
||||
[quo.components.icon :as icons]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn view
|
||||
[{:keys [big? customization-color label counter-value icon on-press accessibility-label disabled?]}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[pressed? set-pressed] (rn/use-state false)
|
||||
on-press-in (rn/use-callback #(set-pressed true))
|
||||
on-press-out (rn/use-callback #(set-pressed false))]
|
||||
[rn/view
|
||||
{:style (style/channel-action-container
|
||||
{:big? big?
|
||||
:disabled? disabled?})}
|
||||
[rn/pressable
|
||||
(cond-> {:style (style/channel-action
|
||||
{:big? big?
|
||||
:color customization-color
|
||||
:pressed? pressed?
|
||||
:theme theme
|
||||
:disabled? disabled?})
|
||||
:accessibility-label accessibility-label}
|
||||
(not disabled?) (assoc :on-press on-press
|
||||
:on-press-in on-press-in
|
||||
:on-press-out on-press-out))
|
||||
[rn/view {:style style/channel-action-row}
|
||||
[icons/icon icon]
|
||||
(when counter-value
|
||||
[counter/view {:type :secondary} counter-value])]
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:number-of-lines 2}
|
||||
label]]]))
|
||||
@@ -1,32 +0,0 @@
|
||||
(ns quo.components.community.channel-actions
|
||||
(:require
|
||||
[quo.components.community.style :as style]
|
||||
[quo.components.counter.counter.view :as counter]
|
||||
[quo.components.icon :as icons]
|
||||
[quo.components.markdown.text :as text]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn channel-action
|
||||
[{:keys [big? color label counter-value icon on-press accessibility-label]}]
|
||||
[rn/touchable-opacity
|
||||
{:on-press on-press
|
||||
:style (style/channel-action-touch big?)
|
||||
:accessibility-label accessibility-label}
|
||||
[rn/view {:style (style/channel-action color)}
|
||||
[rn/view {:style style/channel-action-row}
|
||||
[icons/icon icon]
|
||||
(when counter-value
|
||||
[counter/view {:type :secondary} counter-value])]
|
||||
[text/text {:size :paragraph-1 :weight :medium :number-of-lines 2} label]]])
|
||||
|
||||
(defn channel-actions
|
||||
[{:keys [container-style actions]}]
|
||||
[rn/view {:style (assoc container-style :flex-direction :row)}
|
||||
(map-indexed
|
||||
(fn [index action]
|
||||
^{:key index}
|
||||
[:<>
|
||||
[channel-action action]
|
||||
(when (not= action (last actions))
|
||||
[rn/view {:width 16}])])
|
||||
actions)])
|
||||
@@ -0,0 +1,16 @@
|
||||
(ns quo.components.community.channel-actions.view
|
||||
(:require
|
||||
[quo.components.community.channel-action.view :as channel-action]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn view
|
||||
[{:keys [container-style actions]}]
|
||||
[rn/view {:style (assoc container-style :flex-direction :row)}
|
||||
(map-indexed
|
||||
(fn [index action]
|
||||
^{:key index}
|
||||
[:<>
|
||||
[channel-action/view action]
|
||||
(when (not= action (last actions))
|
||||
[rn/view {:width 16}])])
|
||||
actions)])
|
||||
@@ -133,24 +133,6 @@
|
||||
colors/neutral-80
|
||||
theme)})
|
||||
|
||||
(defn channel-action-touch
|
||||
[big?]
|
||||
{:flex 1
|
||||
:max-width (if big? 216 104)})
|
||||
|
||||
(defn channel-action
|
||||
[color]
|
||||
{:padding 12
|
||||
:height 102
|
||||
:border-radius 16
|
||||
:background-color (colors/custom-color color 50 10)
|
||||
:justify-content :space-between})
|
||||
|
||||
(def channel-action-row
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center})
|
||||
|
||||
(defn loading-card
|
||||
[width theme]
|
||||
(merge
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[:catn
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:value {:optional true} [:maybe [:or :string :int]]]
|
||||
[:status {:optional true} [:maybe :keyword]]
|
||||
[:size {:optional true} [:maybe [:enum :size-32 :size-24]]]
|
||||
@@ -19,7 +20,7 @@
|
||||
:any])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [value accessibility-label]
|
||||
[{:keys [value accessibility-label container-style]
|
||||
:as props}]
|
||||
(let [default-props {:status :default
|
||||
:size :size-32}
|
||||
@@ -27,7 +28,7 @@
|
||||
[rn/view
|
||||
{:accessible true
|
||||
:accessibility-label (or accessibility-label :collectible-counter)
|
||||
:style (style/container props)}
|
||||
:style (merge (style/container props) container-style)}
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size (style/get-text-size props)
|
||||
|
||||
@@ -58,14 +58,15 @@
|
||||
:on-press on-press}
|
||||
[rn/view
|
||||
{:style (style/row-container sub-label)}
|
||||
[rn/view
|
||||
{:accessibility-label :left-icon-for-action
|
||||
:accessible true
|
||||
:style (style/left-icon sub-label)}
|
||||
[icon/icon icon
|
||||
{:color (or icon-color (get-icon-color danger? theme))
|
||||
:no-color no-icon-color?
|
||||
:size 20}]]
|
||||
(when icon
|
||||
[rn/view
|
||||
{:accessibility-label :left-icon-for-action
|
||||
:accessible true
|
||||
:style (style/left-icon sub-label)}
|
||||
[icon/icon icon
|
||||
{:color (or icon-color (get-icon-color danger? theme))
|
||||
:no-color no-icon-color?
|
||||
:size 20}]])
|
||||
[rn/view
|
||||
{:style style/text-container}
|
||||
[text/text
|
||||
|
||||
@@ -59,4 +59,15 @@
|
||||
:button-one-label "Request to join"}])
|
||||
(h/is-truthy (h/get-by-text "Eligible to join as"))
|
||||
(h/is-truthy (h/get-by-text "Admin"))
|
||||
(h/is-truthy (h/get-by-text "Request to join")))
|
||||
|
||||
(h/test "render with top description with custom text & 1 action"
|
||||
(render [bottom-actions/view
|
||||
{:description :top
|
||||
:role :admin
|
||||
:actions :one-action
|
||||
:description-top-text "You'll be an"
|
||||
:button-one-label "Request to join"}])
|
||||
(h/is-truthy (h/get-by-text "You'll be an"))
|
||||
(h/is-truthy (h/get-by-text "Admin"))
|
||||
(h/is-truthy (h/get-by-text "Request to join"))))
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
[:actions [:maybe [:enum :one-action :two-actions]]]
|
||||
[:description {:optional true} [:maybe [:enum :top :bottom :top-error]]]
|
||||
[:description-text {:optional true} [:maybe :string]]
|
||||
[:description-top-text {:optional true} [:maybe :string]]
|
||||
[:error-message {:optional true} [:maybe :string]]
|
||||
[:role {:optional true} [:maybe [:enum :admin :member :token-master :owner]]]
|
||||
[:button-one-label {:optional true} [:maybe :string]]
|
||||
@@ -38,8 +39,8 @@
|
||||
:owner :i/crown})
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [actions description description-text error-message role button-one-label button-two-label
|
||||
blur? button-one-props button-two-props theme scroll? container-style]}]
|
||||
[{:keys [actions description description-text description-top-text error-message role button-one-label
|
||||
button-two-label blur? button-one-props button-two-props theme scroll? container-style]}]
|
||||
[rn/view
|
||||
{:style (merge (style/container scroll? blur? theme) container-style)}
|
||||
(when (= description :top-error)
|
||||
@@ -54,12 +55,11 @@
|
||||
error-message]])
|
||||
|
||||
(when (and (= description :top) role)
|
||||
[rn/view
|
||||
{:style style/description-top}
|
||||
[rn/view {:style style/description-top}
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style (style/description-top-text scroll? blur? theme)}
|
||||
(i18n/label :t/eligible-to-join-as)]
|
||||
(or description-top-text (i18n/label :t/eligible-to-join-as))]
|
||||
[context-tag/view
|
||||
{:type :icon
|
||||
:size 24
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
;; the `:or` destructuring won't work because it's only applied when the
|
||||
;; `:customization-color` key is non-existent. While deleting an account the key exists
|
||||
;; and has a `nil` value.
|
||||
(when customization-color
|
||||
(let [color-top (colors/resolve-color customization-color 50 20)
|
||||
color-bottom (colors/resolve-color customization-color 50 0)]
|
||||
(let [color-top (colors/resolve-color customization-color 50 20)
|
||||
color-bottom (colors/resolve-color customization-color 50 0)]
|
||||
(when (and color-top color-bottom)
|
||||
[linear-gradient/linear-gradient
|
||||
{:accessibility-label :gradient-cover
|
||||
:colors [color-top color-bottom]
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
(h/fire-event :on-blur (h/get-by-label-text :address-text-input))
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:placeholder-text-color
|
||||
colors/neutral-30))))))
|
||||
colors/neutral-40))))))
|
||||
|
||||
(h/test "on blur with text blur? true"
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
@@ -75,7 +75,7 @@
|
||||
(h/fire-event :on-blur (h/get-by-label-text :address-text-input))
|
||||
(h/has-prop (h/get-by-label-text :address-text-input)
|
||||
:placeholder-text-color
|
||||
colors/neutral-80-opa-20))))))
|
||||
colors/neutral-80-opa-40))))))
|
||||
|
||||
(h/test "on blur with no text and blur? false"
|
||||
(with-redefs [clipboard/get-string #(% "")]
|
||||
|
||||
@@ -58,78 +58,64 @@
|
||||
[{:keys [default-value blur? on-change-text on-blur on-focus on-clear on-scan
|
||||
on-detect-ens on-detect-address on-detect-unclassified address-regex ens-regex
|
||||
valid-ens-or-address? container-style]}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[status set-status] (rn/use-state :default)
|
||||
value (rn/use-ref-atom nil)
|
||||
[_ trigger-render-value] (rn/use-state @value)
|
||||
[focused? set-focused] (rn/use-state false)
|
||||
on-change (rn/use-callback
|
||||
(fn [text]
|
||||
(let [address? (when address-regex
|
||||
(boolean (re-matches address-regex text)))
|
||||
ens? (when ens-regex
|
||||
(boolean (re-matches ens-regex text)))]
|
||||
(reset! value text)
|
||||
(if (> (count text) 0)
|
||||
(set-status :typing)
|
||||
(set-status :active))
|
||||
(when on-change-text
|
||||
(on-change-text text))
|
||||
(when (and on-detect-ens ens?)
|
||||
(set-status :loading)
|
||||
(on-detect-ens text #(set-status :typing)))
|
||||
(when (and address? on-detect-address)
|
||||
(set-status :loading)
|
||||
(on-detect-address text))
|
||||
(when (and (not address?)
|
||||
(not ens?)
|
||||
on-detect-unclassified)
|
||||
(on-detect-unclassified text)))))
|
||||
set-value (rn/use-callback
|
||||
(fn [new-value]
|
||||
(reset! value new-value)
|
||||
(on-change new-value)
|
||||
(trigger-render-value new-value)))
|
||||
on-paste (rn/use-callback
|
||||
(fn []
|
||||
(clipboard/get-string
|
||||
(fn [clipboard]
|
||||
(when-not (empty? clipboard)
|
||||
(set-value clipboard))))))
|
||||
on-clear (rn/use-callback
|
||||
(fn []
|
||||
(set-value "")
|
||||
(set-status (if focused? :active :default))
|
||||
(when on-change-text
|
||||
(on-change-text ""))
|
||||
(when on-clear
|
||||
(on-clear)))
|
||||
[focused?])
|
||||
on-clear (rn/use-callback
|
||||
(fn []
|
||||
(set-value "")
|
||||
(set-status (if focused? :active :default))
|
||||
(when on-change-text
|
||||
(on-change-text ""))
|
||||
(when on-clear
|
||||
(on-clear)))
|
||||
[focused?])
|
||||
on-scan (when on-scan (rn/use-callback #(on-scan set-value)))
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(when (= (count @value) 0)
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
[status set-status] (rn/use-state :default)
|
||||
[value set-value] (rn/use-state nil)
|
||||
[focused? set-focused] (rn/use-state false)
|
||||
on-change (rn/use-callback
|
||||
(fn [text]
|
||||
(let [address? (when address-regex
|
||||
(boolean (re-matches address-regex text)))
|
||||
ens? (when ens-regex
|
||||
(boolean (re-matches ens-regex text)))]
|
||||
(set-value text)
|
||||
(if (> (count text) 0)
|
||||
(set-status :typing)
|
||||
(set-status :active))
|
||||
(set-focused true)
|
||||
(when on-focus (on-focus))))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(when (= status :active)
|
||||
(set-status :default))
|
||||
(set-focused false)
|
||||
(when on-blur (on-blur)))
|
||||
[status])
|
||||
placeholder-text-color (rn/use-memo #(get-placeholder-text-color status theme blur?)
|
||||
[status theme blur?])]
|
||||
(when on-change-text
|
||||
(on-change-text text))
|
||||
(when (and on-detect-ens ens?)
|
||||
(set-status :loading)
|
||||
(on-detect-ens text #(set-status :typing)))
|
||||
(when (and address? on-detect-address)
|
||||
(set-status :loading)
|
||||
(on-detect-address text))
|
||||
(when (and (not address?)
|
||||
(not ens?)
|
||||
on-detect-unclassified)
|
||||
(on-detect-unclassified text)))))
|
||||
on-paste (rn/use-callback
|
||||
(fn []
|
||||
(clipboard/get-string
|
||||
(fn [clipboard]
|
||||
(when-not (empty? clipboard)
|
||||
(on-change clipboard))))))
|
||||
on-clear (rn/use-callback
|
||||
(fn []
|
||||
(on-change "")
|
||||
(set-status (if focused? :active :default))
|
||||
(when on-change-text
|
||||
(on-change-text ""))
|
||||
(when on-clear
|
||||
(on-clear)))
|
||||
[focused?])
|
||||
on-scan (rn/use-callback #(when on-scan (on-scan on-change))
|
||||
[on-scan])
|
||||
on-focus (rn/use-callback
|
||||
(fn []
|
||||
(when (= (count value) 0)
|
||||
(set-status :active))
|
||||
(set-focused true)
|
||||
(when on-focus (on-focus))))
|
||||
on-blur (rn/use-callback
|
||||
(fn []
|
||||
(when (= status :active)
|
||||
(set-status :default))
|
||||
(set-focused false)
|
||||
(when on-blur (on-blur)))
|
||||
[status])
|
||||
placeholder-text-color (rn/use-memo #(get-placeholder-text-color status theme blur?)
|
||||
[status theme blur?])]
|
||||
(rn/use-mount #(on-change (or default-value "")))
|
||||
[rn/view {:style (style/container container-style)}
|
||||
[rn/text-input
|
||||
@@ -137,7 +123,7 @@
|
||||
:style (style/input-text theme)
|
||||
:placeholder (i18n/label :t/name-ens-or-address)
|
||||
:placeholder-text-color placeholder-text-color
|
||||
:value @value
|
||||
:value value
|
||||
:auto-complete (when platform/ios? :off)
|
||||
:auto-capitalize :none
|
||||
:auto-correct false
|
||||
|
||||
@@ -57,14 +57,19 @@
|
||||
"Custom properties that must be removed from properties map passed to InputText."
|
||||
[:type :blur? :error? :right-icon :left-icon :disabled? :small? :button
|
||||
:label :char-limit :on-char-limit-reach :icon-name :multiline? :on-focus :on-blur
|
||||
:container-style])
|
||||
:container-style :ref])
|
||||
|
||||
(defn- base-input
|
||||
[{:keys [blur? error? right-icon left-icon disabled? small? button
|
||||
label char-limit multiline? clearable? on-focus on-blur container-style
|
||||
on-change-text on-char-limit-reach weight default-value]
|
||||
on-change-text on-char-limit-reach weight default-value on-clear]
|
||||
:as props}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
ref (rn/use-ref-atom nil)
|
||||
on-ref (rn/use-callback (fn [value]
|
||||
(when (:ref props)
|
||||
((:ref props) value))
|
||||
(reset! ref value)))
|
||||
[status set-status] (rn/use-state :default)
|
||||
internal-on-focus (rn/use-callback #(set-status :focus))
|
||||
internal-on-blur (rn/use-callback #(set-status :default))
|
||||
@@ -93,6 +98,15 @@
|
||||
:else status)
|
||||
colors-by-status (style/status-colors status-kw blur? theme)
|
||||
variant-colors (style/variants-colors blur? theme)
|
||||
clear-on-press (rn/use-callback (fn []
|
||||
(.clear ^js @ref)
|
||||
(when on-clear (on-clear)))
|
||||
[on-clear])
|
||||
right-icon (or right-icon
|
||||
(when clearable?
|
||||
{:style-fn style/clear-icon
|
||||
:icon-name :i/clear
|
||||
:on-press clear-on-press}))
|
||||
clean-props (apply dissoc props custom-props)]
|
||||
[rn/view {:style container-style}
|
||||
(when (or label char-limit)
|
||||
@@ -108,7 +122,8 @@
|
||||
:small? small?
|
||||
:icon-name icon-name}])
|
||||
[rn/text-input
|
||||
(cond-> {:style (style/input colors-by-status small? multiple-lines? weight)
|
||||
(cond-> {:ref on-ref
|
||||
:style (style/input colors-by-status small? multiple-lines? weight)
|
||||
:accessibility-label :input
|
||||
:placeholder-text-color (:placeholder colors-by-status)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark theme)
|
||||
@@ -147,7 +162,10 @@
|
||||
[{:keys [default-shown?]
|
||||
:or {default-shown? false}
|
||||
:as props}]
|
||||
(let [[password-shown? set-password-shown] (rn/use-state default-shown?)]
|
||||
(let [[password-shown?
|
||||
set-password-shown] (rn/use-state default-shown?)
|
||||
on-press (rn/use-callback #(set-password-shown (not password-shown?))
|
||||
[password-shown?])]
|
||||
[base-input
|
||||
(assoc props
|
||||
:accessibility-label :password-input
|
||||
@@ -156,7 +174,7 @@
|
||||
:secure-text-entry (not password-shown?)
|
||||
:right-icon {:style-fn style/password-icon
|
||||
:icon-name (if password-shown? :i/hide-password :i/reveal)
|
||||
:on-press #(set-password-shown (not password-shown?))})]))
|
||||
:on-press on-press})]))
|
||||
|
||||
(defn input
|
||||
"This input supports the following properties:
|
||||
@@ -182,15 +200,11 @@
|
||||
- :on-change-text
|
||||
...
|
||||
"
|
||||
[{:keys [type clearable? on-clear icon-name]
|
||||
[{:keys [type icon-name]
|
||||
:or {type :text}
|
||||
:as props}]
|
||||
(let [base-props (cond-> props
|
||||
icon-name (assoc-in [:left-icon :icon-name] icon-name)
|
||||
clearable? (assoc :right-icon
|
||||
{:style-fn style/clear-icon
|
||||
:icon-name :i/clear
|
||||
:on-press #(when on-clear (on-clear))}))]
|
||||
icon-name (assoc-in [:left-icon :icon-name] icon-name))]
|
||||
(if (= type :password)
|
||||
[password-input base-props]
|
||||
[base-input base-props])))
|
||||
|
||||
@@ -76,12 +76,12 @@
|
||||
:blur? overflow-label blur?}
|
||||
items preview list items (only 4 items is required for preview)
|
||||
"
|
||||
[{:keys [type size number blur?]} items]
|
||||
[{:keys [type size number blur? container-style]} items]
|
||||
(let [size-key (if (contains? properties/sizes size) size :size-24)
|
||||
number (or number (count items))
|
||||
border-type (properties/border-type type)
|
||||
margin-left (get-in properties/sizes [size-key :margin-left])]
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[rn/view {:style (assoc container-style :flex-direction :row)}
|
||||
(for [index (range (if (> number 4) 3 number))]
|
||||
^{:key (str index number)}
|
||||
[list-item
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
:align-items :center})
|
||||
|
||||
(defn action-icon
|
||||
[{:keys [type on-press on-check disabled? checked?]} theme]
|
||||
[{:keys [type on-press on-check disabled? checked?]} customization-color theme]
|
||||
[rn/touchable-opacity
|
||||
{:on-press (when on-press on-press)}
|
||||
{:on-press on-press}
|
||||
(case type
|
||||
:options
|
||||
[icons/icon :i/options
|
||||
@@ -30,6 +30,7 @@
|
||||
[selectors/view
|
||||
{:type :checkbox
|
||||
:checked? checked?
|
||||
:customization-color customization-color
|
||||
:accessibility-label :user-list-toggle-check
|
||||
:disabled? disabled?
|
||||
:on-change (when on-check on-check)}]
|
||||
@@ -68,4 +69,4 @@
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
short-chat-key])]
|
||||
(when accessory
|
||||
[action-icon accessory theme])]])
|
||||
[action-icon accessory customization-color theme])]])
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
(ns quo.components.profile.collectible-list-item.component-spec
|
||||
(:require
|
||||
[quo.components.profile.collectible-list-item.view :as collectible-list-item]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Profile/ collectible list item tests"
|
||||
(h/describe "type card"
|
||||
(h/test "Renders default and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-called on-press)))
|
||||
|
||||
(h/test "Renders loading and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :loading
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-not-called on-press)
|
||||
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
|
||||
|
||||
(h/test "Renders counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500")))
|
||||
|
||||
(h/test "Renders counter and collectible name"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:collectible-name "Doodle #6822"
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500"))
|
||||
(h/is-truthy (h/get-by-text "Doodle #6822")))
|
||||
|
||||
(h/test "Renders status cant-fetch"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :cant-fetch}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
|
||||
|
||||
(h/test "Renders status unsupported"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :unsupported}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
|
||||
|
||||
(h/test "Renders status unsupported and counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :card
|
||||
:status :unsupported
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500"))
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file))))
|
||||
|
||||
(h/describe "type image"
|
||||
(h/test "Renders default and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-called on-press)))
|
||||
|
||||
(h/test "Renders loading and on press fires"
|
||||
(let [on-press (h/mock-fn)]
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :loading
|
||||
:on-press on-press}])
|
||||
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
|
||||
(h/was-not-called on-press)
|
||||
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
|
||||
|
||||
(h/test "Renders counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:counter "x500"}])
|
||||
(h/is-truthy (h/get-by-text "x500")))
|
||||
|
||||
(h/test "Renders status cant-fetch"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :cant-fetch}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
|
||||
|
||||
(h/test "Renders status unsupported"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :unsupported}])
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
|
||||
|
||||
(h/test "Renders status unsupported and counter"
|
||||
(h/render-with-theme-provider
|
||||
[collectible-list-item/view
|
||||
{:type :image
|
||||
:status :unsupported
|
||||
:counter "x500"}])
|
||||
(h/get-by-text "x500")
|
||||
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))
|
||||
@@ -0,0 +1,90 @@
|
||||
(ns quo.components.profile.collectible-list-item.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[quo.foundations.shadows :as shadows]))
|
||||
|
||||
(def container-border-radius 12)
|
||||
(def card-image-padding-vertical 3)
|
||||
(def card-image-padding-horizontal 3)
|
||||
|
||||
(defn fallback
|
||||
[{:keys [theme]}]
|
||||
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
|
||||
:border-style :dashed
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
|
||||
:border-width 1
|
||||
:border-radius container-border-radius
|
||||
:width "100%"
|
||||
:aspect-ratio 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def collectible-counter
|
||||
{:position :absolute
|
||||
:top 12
|
||||
:right 12})
|
||||
|
||||
(def avatar
|
||||
{:position :absolute
|
||||
:bottom 12
|
||||
:left 12})
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
|
||||
(defn card-view-container
|
||||
[theme]
|
||||
(merge
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
|
||||
:padding-top card-image-padding-vertical
|
||||
:padding-left card-image-padding-horizontal
|
||||
:padding-right card-image-padding-horizontal
|
||||
:padding-bottom card-image-padding-vertical
|
||||
:border-radius 14
|
||||
:border-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)}
|
||||
(shadows/get 2)))
|
||||
|
||||
(def image
|
||||
{:width "100%"
|
||||
:flex 1
|
||||
:border-radius container-border-radius})
|
||||
|
||||
(def card-details-container
|
||||
{:flex-direction :row
|
||||
:height 27
|
||||
:margin-top 3
|
||||
:margin-bottom 2
|
||||
:align-items :center
|
||||
:padding-left 8
|
||||
:padding-right 0
|
||||
:padding-top 4})
|
||||
|
||||
(def card-detail-text
|
||||
{:flex 1})
|
||||
|
||||
(def image-view-container
|
||||
{:aspect-ratio 1
|
||||
:border-radius container-border-radius})
|
||||
|
||||
(defn loading-square
|
||||
[theme]
|
||||
{:height 20
|
||||
:width 20
|
||||
:border-radius 6
|
||||
:align-self :center
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
|
||||
|
||||
(defn loading-message
|
||||
[theme]
|
||||
{:height 14
|
||||
:width 72
|
||||
:margin-left 8
|
||||
:border-radius 6
|
||||
:align-self :center
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
|
||||
|
||||
(defn loading-image
|
||||
[theme]
|
||||
{:flex 1
|
||||
:border-radius container-border-radius
|
||||
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)})
|
||||
@@ -0,0 +1,195 @@
|
||||
(ns quo.components.profile.collectible-list-item.view
|
||||
(:require
|
||||
[quo.components.avatars.collection-avatar.view :as collection-avatar]
|
||||
[quo.components.counter.collectible-counter.view :as collectible-counter]
|
||||
[quo.components.icon :as icon]
|
||||
[quo.components.list-items.preview-list.view :as preview-list]
|
||||
[quo.components.markdown.text :as quo]
|
||||
[quo.components.profile.collectible-list-item.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.foundations.gradients :as gradients]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[schema.core :as schema]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn- fallback-view
|
||||
[{:keys [label theme type]}]
|
||||
[rn/view
|
||||
{:style (style/fallback {:type type
|
||||
:theme theme})}
|
||||
[rn/view
|
||||
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
|
||||
[rn/view {:style {:height 4}}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
|
||||
label]])
|
||||
|
||||
(defn- loading-square
|
||||
[theme]
|
||||
[rn/view {:style (style/loading-square theme)}])
|
||||
|
||||
(defn- loading-message
|
||||
[theme]
|
||||
[rn/view {:style (style/loading-message theme)}])
|
||||
|
||||
(defn- loading-image
|
||||
[{:keys [theme gradient-color-index]}]
|
||||
[gradients/view
|
||||
{:theme theme
|
||||
:container-style (style/loading-image theme)
|
||||
:color-index gradient-color-index}])
|
||||
|
||||
(defn- card-details
|
||||
[{:keys [status community? avatar-image-src collectible-name theme]}]
|
||||
[rn/view {:style style/card-details-container}
|
||||
|
||||
(cond (= :cant-fetch status)
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
|
||||
(i18n/label :t/unknown)]
|
||||
|
||||
(= :loading status)
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[loading-square theme]
|
||||
[loading-message theme]]
|
||||
|
||||
community?
|
||||
[:<>
|
||||
[preview-list/view
|
||||
{:type :communities
|
||||
:size :size-20}
|
||||
[avatar-image-src]]
|
||||
[rn/view {:style {:width 8}}]
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style style/card-detail-text}
|
||||
collectible-name]]
|
||||
|
||||
:else
|
||||
[:<>
|
||||
[collection-avatar/view
|
||||
{:size :size-20
|
||||
:image avatar-image-src}]
|
||||
[rn/view {:style {:width 8}}]
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style style/card-detail-text}
|
||||
collectible-name]])])
|
||||
|
||||
(defn- card-view
|
||||
[{:keys [avatar-image-src collectible-name community? counter
|
||||
gradient-color-index image-src status type]}]
|
||||
(let [theme (quo.theme/use-theme-value)]
|
||||
[rn/view {:style (style/card-view-container theme)}
|
||||
[rn/view {:style {:aspect-ratio 1}}
|
||||
(cond
|
||||
(= :loading status)
|
||||
[loading-image
|
||||
{:theme theme
|
||||
:gradient-color-index gradient-color-index}]
|
||||
|
||||
(= status :unsupported)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:type type
|
||||
:label (i18n/label :t/unsupported-file)}]
|
||||
|
||||
(= status :cant-fetch)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:type type
|
||||
:label (i18n/label :t/cant-fetch-info)}]
|
||||
|
||||
:else
|
||||
[rn/view {:style {:aspect-ratio 1}}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:source image-src}]])]
|
||||
(when (and (not= status :loading) (not= status :cant-fetch) counter)
|
||||
[collectible-counter/view
|
||||
{:container-style style/collectible-counter
|
||||
:size :size-24
|
||||
:value counter}])
|
||||
[card-details
|
||||
{:status status
|
||||
:community? community?
|
||||
:avatar-image-src avatar-image-src
|
||||
:collectible-name collectible-name
|
||||
:theme theme}]]))
|
||||
|
||||
(defn- image-view
|
||||
[{:keys [avatar-image-src community? counter
|
||||
gradient-color-index image-src status]}]
|
||||
(let [theme (quo.theme/use-theme-value)]
|
||||
[rn/view {:style style/image-view-container}
|
||||
(cond
|
||||
(= :loading status)
|
||||
[loading-image
|
||||
{:theme theme
|
||||
:gradient-color-index gradient-color-index}]
|
||||
|
||||
(= status :unsupported)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:type type
|
||||
:label (i18n/label :t/unsupported-file)}]
|
||||
|
||||
(= status :cant-fetch)
|
||||
[fallback-view
|
||||
{:theme theme
|
||||
:type type
|
||||
:label (i18n/label :t/cant-fetch-info)}]
|
||||
|
||||
:else [rn/view {:style {:aspect-ratio 1}}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:source image-src}]])
|
||||
(when (and (not= status :loading) (not= status :cant-fetch) counter)
|
||||
[collectible-counter/view
|
||||
{:container-style style/collectible-counter
|
||||
:size :size-24
|
||||
:value counter}])
|
||||
(when (and (not= status :loading) (not= status :cant-fetch) community?)
|
||||
[preview-list/view
|
||||
{:container-style style/avatar
|
||||
:type :communities
|
||||
:size :size-24}
|
||||
[avatar-image-src]])]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [container-style type on-press status]
|
||||
:as props}]
|
||||
[rn/pressable
|
||||
{:on-press (when-not (= status :loading) on-press)
|
||||
:accessibility-label :collectible-list-item
|
||||
:style (merge container-style style/container)}
|
||||
(if (= type :card)
|
||||
[card-view props]
|
||||
[image-view props])])
|
||||
|
||||
(def ?schema
|
||||
[:=>
|
||||
[:catn
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:avatar-image-src {:optional true} [:maybe :schema.common/image-source]]
|
||||
[:collectible-name {:optional true} [:maybe string?]]
|
||||
[:community? {:optional true} [:maybe boolean?]]
|
||||
[:counter {:optional true} [:maybe string?]]
|
||||
[:gradient-color-index {:optional true}
|
||||
[:maybe [:enum :gradient-1 :gradient-2 :gradient-3 :gradient-4 :gradient-5]]]
|
||||
[:image-src {:optional true} [:maybe :schema.common/image-source]]
|
||||
[:on-press {:optional true} [:maybe fn?]]
|
||||
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
|
||||
[:type [:enum :card :image]]]]]
|
||||
:any])
|
||||
|
||||
(def view (schema/instrument #'view-internal ?schema))
|
||||
@@ -188,21 +188,21 @@
|
||||
nil))]]])
|
||||
|
||||
(defn- view-internal
|
||||
[props]
|
||||
(let [[component-width
|
||||
[{provided-width :width :as props}]
|
||||
(let [[calculated-width
|
||||
set-component-width] (rn/use-state nil)
|
||||
on-layout (rn/use-callback #(set-component-width
|
||||
(oops/oget % "nativeEvent.layout.width")))
|
||||
props (-> props
|
||||
(assoc :component-width component-width)
|
||||
(assoc :component-width (or provided-width calculated-width))
|
||||
(clojure.set/rename-keys {:type :share-qr-type}))]
|
||||
[quo.theme/provider {:theme :dark}
|
||||
[rn/view
|
||||
{:accessibility-label :share-qr-code
|
||||
:style style/outer-container
|
||||
:on-layout on-layout}
|
||||
:on-layout (when-not provided-width on-layout)}
|
||||
[rn/view {:style {:background-color style/overlay-color}}
|
||||
(when component-width
|
||||
(when (:component-width props)
|
||||
[share-qr-code props])]]]))
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
:max-fade-percentage fade-end-percentage})]
|
||||
;; Avoid unnecessary re-rendering.
|
||||
(when (not= new-percentage (get fading :fade-end-percentage))
|
||||
(set-fading (assoc fading :fade-end-percentage new-percentage)))))
|
||||
(set-fading new-percentage))))
|
||||
(when on-scroll
|
||||
(on-scroll e)))
|
||||
|
||||
@@ -61,13 +61,10 @@
|
||||
[{:keys [id label notification-dot? accessibility-label]}
|
||||
index _
|
||||
{:keys [active-tab-id
|
||||
set-active-tab-id
|
||||
blur?
|
||||
customization-color
|
||||
flat-list-ref
|
||||
number-of-items
|
||||
on-change
|
||||
scroll-on-press?
|
||||
on-press
|
||||
size
|
||||
style]}]
|
||||
[rn/view
|
||||
@@ -84,16 +81,7 @@
|
||||
:size size
|
||||
:blur? blur?
|
||||
:active (= id active-tab-id)
|
||||
:on-press (fn [id]
|
||||
(set-active-tab-id id)
|
||||
(when (and scroll-on-press? @flat-list-ref)
|
||||
(.scrollToIndex ^js @flat-list-ref
|
||||
#js
|
||||
{:animated true
|
||||
:index index
|
||||
:viewPosition 0.5}))
|
||||
(when on-change
|
||||
(on-change id)))}
|
||||
:on-press #(on-press % index)}
|
||||
label]])
|
||||
|
||||
(defn view
|
||||
@@ -125,42 +113,63 @@
|
||||
size default-tab-size}
|
||||
:as props}]
|
||||
(let [[active-tab-id
|
||||
set-active-tab-id] (rn/use-state default-active)
|
||||
[fading set-fading] (rn/use-state {:fade-end-percentage fade-end-percentage})
|
||||
flat-list-ref (rn/use-ref-atom nil)
|
||||
clean-props (dissoc props
|
||||
:default-active
|
||||
:fade-end-percentage
|
||||
:fade-end?
|
||||
:on-change
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
on-scroll (rn/use-callback
|
||||
(partial on-scroll-handler
|
||||
{:fade-end-percentage fade-end-percentage
|
||||
:fade-end? fade-end?
|
||||
:fading fading
|
||||
:set-fading set-fading
|
||||
:on-scroll on-scroll})
|
||||
[fade-end? fading])]
|
||||
set-active-tab-id] (rn/use-state default-active)
|
||||
[fading set-fading] (rn/use-state fade-end-percentage)
|
||||
flat-list-ref (rn/use-ref-atom nil)
|
||||
clean-props (dissoc props
|
||||
:default-active
|
||||
:fade-end-percentage
|
||||
:fade-end?
|
||||
:on-change
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
on-scroll (rn/use-callback
|
||||
(partial on-scroll-handler
|
||||
{:fade-end-percentage fade-end-percentage
|
||||
:fade-end? fade-end?
|
||||
:fading fading
|
||||
:set-fading set-fading
|
||||
:on-scroll on-scroll})
|
||||
[fade-end? fading])
|
||||
set-initial-scroll-poisition (rn/use-callback
|
||||
(fn []
|
||||
(reagent/next-tick
|
||||
(fn []
|
||||
(.scrollToIndex
|
||||
@flat-list-ref
|
||||
#js
|
||||
{:animated false
|
||||
:index
|
||||
(utils.collection/first-index
|
||||
#(= active-tab-id (:id %))
|
||||
data)}))))
|
||||
[active-tab-id data])
|
||||
on-tab-press (rn/use-callback (fn [id index]
|
||||
(set-active-tab-id id)
|
||||
(when (and scroll-on-press? @flat-list-ref)
|
||||
(.scrollToIndex ^js @flat-list-ref
|
||||
#js
|
||||
{:animated true
|
||||
:index index
|
||||
:viewPosition 0.5}))
|
||||
(when on-change
|
||||
(on-change id)))
|
||||
[set-active-tab-id scroll-on-press? on-change])]
|
||||
(if scrollable?
|
||||
[rn/view {:style {:margin-top (- (dec unread-count-offset))}}
|
||||
[masked-view-wrapper
|
||||
{:fade-end-percentage (get fading :fade-end-percentage) :fade-end? fade-end?}
|
||||
{:fade-end-percentage fading :fade-end? fade-end?}
|
||||
[(if in-scroll-view?
|
||||
gesture/flat-list
|
||||
rn/flat-list)
|
||||
(merge
|
||||
clean-props
|
||||
(when scroll-on-press?
|
||||
{:initial-scroll-index (utils.collection/first-index #(= active-tab-id (:id %)) data)})
|
||||
{:ref #(reset! flat-list-ref %)
|
||||
:style style
|
||||
;; The padding-top workaround is needed because on Android
|
||||
;; {:overflow :visible} doesn't work on components inheriting
|
||||
;; from ScrollView (e.g. FlatList). There are open issues, here's
|
||||
;; just one about this topic:
|
||||
;; https://github.com/facebook/react-native/issues/31218
|
||||
;; from ScrollView (e.g. FlatList). There are open issues, here's just one about this
|
||||
;; topic: Https://github.com/facebook/react-native/issues/31218
|
||||
:content-container-style
|
||||
(assoc container-style :padding-top (dec unread-count-offset))
|
||||
:horizontal true
|
||||
@@ -170,27 +179,24 @@
|
||||
:key-fn (comp str :id)
|
||||
:on-scroll-to-index-failed identity
|
||||
:on-scroll on-scroll
|
||||
:on-layout set-initial-scroll-poisition
|
||||
:render-fn tab-view
|
||||
:render-data {:active-tab-id active-tab-id
|
||||
:set-active-tab-id set-active-tab-id
|
||||
:blur? blur?
|
||||
:customization-color customization-color
|
||||
:flat-list-ref flat-list-ref
|
||||
:number-of-items (count data)
|
||||
:on-change on-change
|
||||
:scroll-on-press? scroll-on-press?
|
||||
:size size
|
||||
:on-press on-tab-press
|
||||
:style style}})]]]
|
||||
[rn/view (merge style {:flex-direction :row})
|
||||
(map-indexed (fn [index item]
|
||||
^{:key (:id item)}
|
||||
[tab-view item index nil
|
||||
{:active-tab-id active-tab-id
|
||||
:set-active-tab-id set-active-tab-id
|
||||
:blur? blur?
|
||||
:customization-color customization-color
|
||||
:number-of-items (count data)
|
||||
:on-change on-change
|
||||
:size size
|
||||
:on-press on-tab-press
|
||||
:style style}])
|
||||
data)])))
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[:enum :default :multiuser :group :channel :community :token :network :multinetwork :account
|
||||
:collectible :address :icon :audio]]]
|
||||
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:theme :schema.common/theme]
|
||||
[:blur? {:optional true} [:maybe :boolean]]
|
||||
[:state {:optional true} [:maybe [:enum :selected :default]]]])
|
||||
@@ -38,6 +39,7 @@
|
||||
(def ^:private ?channel
|
||||
[:map
|
||||
[:community-name {:optional true} [:maybe :string]]
|
||||
[:community-logo {:optional true} [:maybe :schema.common/image-source]]
|
||||
[:channel-name {:optional true} [:maybe :string]]])
|
||||
|
||||
(def ^:private ?community
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
(colors/custom-color customization-color 60)
|
||||
theme)]
|
||||
(cond-> {:padding 2
|
||||
:padding-right 8
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:height size
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- tag-skeleton
|
||||
@@ -30,7 +31,7 @@
|
||||
(let [text-size (if (= size 24) :paragraph-2 :paragraph-1)
|
||||
icon-size (if (= size 24) 16 20)]
|
||||
[rn/view {:style (style/tag-container size)}
|
||||
[rn/image {:style (style/circle-logo size) :source community-logo}]
|
||||
[fast-image/fast-image {:style (style/circle-logo size) :source community-logo}]
|
||||
[rn/view {:style (style/tag-spacing size)}
|
||||
[text/text
|
||||
{:style (style/text theme)
|
||||
@@ -82,81 +83,81 @@
|
||||
type :default
|
||||
state :default}
|
||||
:as props}]
|
||||
[rn/view
|
||||
{:style (merge (style/container {:theme theme
|
||||
:type type
|
||||
:size size
|
||||
:state state
|
||||
:blur? blur?
|
||||
:customization-color customization-color})
|
||||
container-style)
|
||||
:accessibility-label :context-tag}
|
||||
(case type
|
||||
:default
|
||||
[tag-skeleton {:theme theme :size size :text full-name}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name full-name
|
||||
:profile-picture profile-picture
|
||||
:size (if (= size 24) :xxs 28)
|
||||
:status-indicator? false
|
||||
:ring? false
|
||||
:customization-color customization-color}]]
|
||||
[rn/view {:style (merge {:align-items :flex-start} container-style)}
|
||||
[rn/view
|
||||
{:style (style/container {:theme theme
|
||||
:type type
|
||||
:size size
|
||||
:state state
|
||||
:blur? blur?
|
||||
:customization-color customization-color})
|
||||
:accessibility-label :context-tag}
|
||||
(case type
|
||||
:default
|
||||
[tag-skeleton {:theme theme :size size :text full-name}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name full-name
|
||||
:profile-picture profile-picture
|
||||
:size (if (= size 24) :xxs 28)
|
||||
:status-indicator? false
|
||||
:ring? false
|
||||
:customization-color customization-color}]]
|
||||
|
||||
:multiuser
|
||||
[preview-list/view {:type :user :size :size-20}
|
||||
users]
|
||||
:multiuser
|
||||
[preview-list/view {:type :user :size :size-20}
|
||||
users]
|
||||
|
||||
:multinetwork
|
||||
[preview-list/view {:type :network :size :size-20}
|
||||
networks]
|
||||
:multinetwork
|
||||
[preview-list/view {:type :network :size :size-20}
|
||||
networks]
|
||||
|
||||
:audio
|
||||
[tag-skeleton {:theme theme :text (str duration)}
|
||||
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
|
||||
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
|
||||
:audio
|
||||
[tag-skeleton {:theme theme :text (str duration)}
|
||||
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
|
||||
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
|
||||
|
||||
:group
|
||||
[tag-skeleton {:theme theme :size size :text group-name}
|
||||
[group-avatar/view
|
||||
{:icon-name :i/members
|
||||
:size (if (= size 24) :size-20 :size-28)
|
||||
:customization-color (colors/custom-color customization-color 50)}]]
|
||||
:group
|
||||
[tag-skeleton {:theme theme :size size :text group-name}
|
||||
[group-avatar/view
|
||||
{:icon-name :i/members
|
||||
:size (if (= size 24) :size-20 :size-28)
|
||||
:customization-color (colors/custom-color customization-color 50)}]]
|
||||
|
||||
(:channel :community)
|
||||
[communities-tag (assoc props :channel? (= type :channel))]
|
||||
(:channel :community)
|
||||
[communities-tag (assoc props :channel? (= type :channel))]
|
||||
|
||||
:token
|
||||
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
|
||||
[token/view
|
||||
{:style (style/token-logo size)
|
||||
:token token
|
||||
:size (if (= size 24) :size-20 :size-28)}]]
|
||||
:token
|
||||
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
|
||||
[token/view
|
||||
{:style (style/token-logo size)
|
||||
:token token
|
||||
:size (if (= size 24) :size-20 :size-28)}]]
|
||||
|
||||
:network
|
||||
[tag-skeleton {:theme theme :size size :text network-name}
|
||||
[rn/image {:style (style/circle-logo size) :source network-logo}]]
|
||||
:network
|
||||
[tag-skeleton {:theme theme :size size :text network-name}
|
||||
[rn/image {:style (style/circle-logo size) :source network-logo}]]
|
||||
|
||||
:collectible
|
||||
[tag-skeleton
|
||||
{:theme theme
|
||||
:size size
|
||||
:text (str collectible-name " #" collectible-number)}
|
||||
[rn/image {:style (style/rounded-logo size) :source collectible}]]
|
||||
:collectible
|
||||
[tag-skeleton
|
||||
{:theme theme
|
||||
:size size
|
||||
:text (str collectible-name " #" collectible-number)}
|
||||
[rn/image {:style (style/rounded-logo size) :source collectible}]]
|
||||
|
||||
:account
|
||||
[tag-skeleton {:theme theme :size size :text account-name}
|
||||
[account-avatar/view
|
||||
{:customization-color customization-color
|
||||
:emoji emoji
|
||||
:size (if (= size 24) 20 28)}]]
|
||||
:account
|
||||
[tag-skeleton {:theme theme :size size :text account-name}
|
||||
[account-avatar/view
|
||||
{:customization-color customization-color
|
||||
:emoji emoji
|
||||
:size (if (= size 24) 20 28)}]]
|
||||
|
||||
:address
|
||||
[address-tag props]
|
||||
:address
|
||||
[address-tag props]
|
||||
|
||||
:icon
|
||||
[icon-tag props]
|
||||
:icon
|
||||
[icon-tag props]
|
||||
|
||||
nil)])
|
||||
nil)]])
|
||||
|
||||
(def view
|
||||
(quo.theme/with-theme
|
||||
|
||||
@@ -115,12 +115,13 @@
|
||||
emojis))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [theme description input blur? input-props container-style]
|
||||
[{:keys [theme description title input blur? input-props container-style]
|
||||
emojis :emoji-dash
|
||||
:as props}]
|
||||
[rn/view {:style container-style}
|
||||
[rn/view {:style style/top-container}
|
||||
[header props]
|
||||
(when (or title input)
|
||||
[header props])
|
||||
(when description
|
||||
[description-container props])
|
||||
(when emojis
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
(def title-container
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center})
|
||||
|
||||
(def avatar-container
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- username-text
|
||||
[{:keys [theme name-type username blur?]
|
||||
[{:keys [theme name-type username accessibility-label blur?]
|
||||
real-name :name}]
|
||||
[rn/view {:style style/username-text-container}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:weight :semi-bold}
|
||||
{:size :heading-1
|
||||
:accessibility-label accessibility-label
|
||||
:weight :semi-bold}
|
||||
username]
|
||||
(when (= name-type :nickname)
|
||||
[:<>
|
||||
@@ -22,9 +23,10 @@
|
||||
:weight :medium}
|
||||
"∙"]
|
||||
[text/text
|
||||
{:style (style/real-name-text theme blur?)
|
||||
:size :paragraph-1
|
||||
:weight :medium}
|
||||
{:style (style/real-name-text theme blur?)
|
||||
:size :paragraph-1
|
||||
:accessibility-label :real-name
|
||||
:weight :medium}
|
||||
real-name]])])
|
||||
|
||||
(defn- icon-20
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
{:accessibility-label title-accessibility-label
|
||||
:weight :semi-bold
|
||||
:ellipsize-mode :tail
|
||||
:style {:flex 1}
|
||||
:number-of-lines title-number-of-lines
|
||||
:size :heading-1}
|
||||
title]]
|
||||
|
||||
@@ -100,8 +100,7 @@
|
||||
:or {customization-color :blue}}]
|
||||
(let [time-frame-string (time-string time-frame time-frame-string)
|
||||
up? (= metrics :positive)]
|
||||
[rn/view
|
||||
{:style style/account-overview-wrapper}
|
||||
[rn/view {:style style/account-overview-wrapper}
|
||||
(if (= :loading state)
|
||||
[loading-state (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)]
|
||||
[rn/view
|
||||
@@ -113,19 +112,17 @@
|
||||
:size :heading-1
|
||||
:style style/current-value}
|
||||
current-value]
|
||||
[rn/view
|
||||
{:style style/row-centered}
|
||||
[:<>
|
||||
(when (seq time-frame-string)
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/bottom-time-text (and (not= :custom time-frame)
|
||||
(seq time-frame-to-string)))}
|
||||
time-frame-string])
|
||||
(when (and (= :custom time-frame)
|
||||
(seq time-frame-to-string))
|
||||
[custom-time-frame time-frame-to-string])]
|
||||
[rn/view {:style style/row-centered}
|
||||
(when (seq time-frame-string)
|
||||
[text/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/bottom-time-text (and (not= :custom time-frame)
|
||||
(seq time-frame-to-string)))}
|
||||
time-frame-string])
|
||||
(when (and (= :custom time-frame)
|
||||
(seq time-frame-to-string))
|
||||
[custom-time-frame time-frame-to-string])
|
||||
(when (and (seq percentage-change)
|
||||
(seq currency-change))
|
||||
[numeric-changes percentage-change currency-change customization-color theme up?])]])]))
|
||||
|
||||
@@ -4,19 +4,18 @@
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(defn container
|
||||
[{:keys [blur? customization-color theme selected?]}]
|
||||
{:border-radius 16
|
||||
:border-width 1
|
||||
:border-color (if selected?
|
||||
(if blur?
|
||||
colors/white
|
||||
(colors/theme-colors (colors/custom-color customization-color 50)
|
||||
(colors/custom-color customization-color 60)
|
||||
theme))
|
||||
(if blur?
|
||||
colors/white-opa-5
|
||||
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme)))
|
||||
:padding-bottom 8})
|
||||
[{:keys [blur? customization-color theme selected? container-style]}]
|
||||
(merge {:border-radius 16
|
||||
:border-width 1
|
||||
:border-color (if selected?
|
||||
(if blur?
|
||||
colors/white
|
||||
(colors/resolve-color customization-color theme))
|
||||
(if blur?
|
||||
colors/white-opa-5
|
||||
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme)))
|
||||
:padding-bottom 8}
|
||||
container-style))
|
||||
|
||||
(def header-container
|
||||
{:padding-horizontal 12
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn keypair-string
|
||||
@@ -34,7 +33,7 @@
|
||||
:profile-picture profile-picture}]
|
||||
[icon-avatar/icon-avatar
|
||||
{:size :size-32
|
||||
:icon :i/placeholder
|
||||
:icon :i/seed
|
||||
:border? true}]))
|
||||
|
||||
(defn title-view
|
||||
@@ -91,23 +90,23 @@
|
||||
[account-list-card/view item])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [default-selected?]}]
|
||||
(let [selected? (reagent/atom default-selected?)]
|
||||
(fn [{:keys [accounts action container-style] :as props}]
|
||||
[rn/pressable
|
||||
{:style (merge (style/container (merge props {:selected? @selected?})) container-style)
|
||||
:on-press #(when (= action :selector) (reset! selected? (not @selected?)))}
|
||||
[rn/view {:style style/header-container}
|
||||
[avatar props]
|
||||
[rn/view
|
||||
{:style {:margin-left 8
|
||||
:flex 1}}
|
||||
[title-view (assoc props :selected? @selected?)]
|
||||
[details-view props]]]
|
||||
[rn/flat-list
|
||||
{:data accounts
|
||||
:render-fn acc-list-card
|
||||
:separator [rn/view {:style {:height 8}}]
|
||||
:style {:padding-horizontal 8}}]])))
|
||||
[{:keys [accounts action container-style selected? on-press] :as props}]
|
||||
[rn/pressable
|
||||
{:style (style/container (merge props
|
||||
{:selected? selected?
|
||||
:container-style container-style}))
|
||||
:on-press #(when (= action :selector) (on-press))}
|
||||
[rn/view {:style style/header-container}
|
||||
[avatar props]
|
||||
[rn/view
|
||||
{:style {:margin-left 8
|
||||
:flex 1}}
|
||||
[title-view (assoc props :selected? selected?)]
|
||||
[details-view props]]]
|
||||
[rn/flat-list
|
||||
{:data accounts
|
||||
:render-fn acc-list-card
|
||||
:separator [rn/view {:style {:height 8}}]
|
||||
:style {:padding-horizontal 8}}]])
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -30,8 +30,12 @@
|
||||
(defn networks
|
||||
[values theme]
|
||||
(let [{:keys [ethereum optimism arbitrum]} values
|
||||
show-optimism? (and optimism (pos? (:amount optimism)))
|
||||
show-arbitrum? (and arbitrum (pos? (:amount arbitrum)))]
|
||||
show-optimism? (and optimism
|
||||
(or (pos? (:amount optimism))
|
||||
(= (:amount optimism) "<0.01")))
|
||||
show-arbitrum? (and arbitrum
|
||||
(or (pos? (:amount arbitrum))
|
||||
(= (:amount arbitrum) "<0.01")))]
|
||||
[rn/view
|
||||
{:style style/networks-container
|
||||
:accessibility-label :networks}
|
||||
|
||||
+7
-3
@@ -29,7 +29,8 @@
|
||||
quo.components.common.notification-dot.view
|
||||
quo.components.common.separator.view
|
||||
quo.components.community.banner.view
|
||||
quo.components.community.channel-actions
|
||||
quo.components.community.channel-action.view
|
||||
quo.components.community.channel-actions.view
|
||||
quo.components.community.community-card-view
|
||||
quo.components.community.community-list-view
|
||||
quo.components.community.community-stat.view
|
||||
@@ -55,7 +56,7 @@
|
||||
quo.components.dropdowns.network-dropdown.view
|
||||
quo.components.empty-state.empty-state.view
|
||||
quo.components.gradient.gradient-cover.view
|
||||
[quo.components.graph.interactive-graph.view :as interactive-graph]
|
||||
quo.components.graph.interactive-graph.view
|
||||
quo.components.graph.wallet-graph.view
|
||||
quo.components.header
|
||||
quo.components.icon
|
||||
@@ -109,6 +110,7 @@
|
||||
quo.components.onboarding.small-option-card.view
|
||||
quo.components.overlay.view
|
||||
quo.components.password.tips.view
|
||||
quo.components.profile.collectible-list-item.view
|
||||
quo.components.profile.collectible.view
|
||||
quo.components.profile.link-card.view
|
||||
quo.components.profile.profile-card.view
|
||||
@@ -229,7 +231,8 @@
|
||||
(def discover-card quo.components.community.banner.view/view)
|
||||
(def community-icon quo.components.community.icon/community-icon)
|
||||
(def token-requirement-list quo.components.community.token-gating/token-requirement-list)
|
||||
(def channel-actions quo.components.community.channel-actions/channel-actions)
|
||||
(def channel-action quo.components.community.channel-action.view/view)
|
||||
(def channel-actions quo.components.community.channel-actions.view/view)
|
||||
|
||||
;;;; Counter
|
||||
(def collectible-counter quo.components.counter.collectible-counter.view/view)
|
||||
@@ -350,6 +353,7 @@
|
||||
|
||||
;;;; Profile
|
||||
(def collectible quo.components.profile.collectible.view/collectible)
|
||||
(def collectible-list-item quo.components.profile.collectible-list-item.view/view)
|
||||
(def link-card quo.components.profile.link-card.view/view)
|
||||
(def profile-card quo.components.profile.profile-card.view/profile-card)
|
||||
(def select-profile quo.components.profile.select-profile.view/view)
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
quo.components.numbered-keyboard.keyboard-key.component-spec
|
||||
quo.components.onboarding.small-option-card.component-spec
|
||||
quo.components.password.tips.component-spec
|
||||
quo.components.profile.collectible-list-item.component-spec
|
||||
quo.components.profile.link-card.component-spec
|
||||
quo.components.profile.select-profile.component-spec
|
||||
quo.components.profile.showcase-nav.component-spec
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
(ns quo.foundations.gradients
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme]
|
||||
[react-native.linear-gradient :as linear-gradient]))
|
||||
|
||||
(defn- gradient-colors
|
||||
[index theme]
|
||||
(case index
|
||||
:gradient-1 [(colors/resolve-color :yellow theme)
|
||||
(colors/resolve-color :sky theme)
|
||||
(colors/resolve-color :purple theme)]
|
||||
:gradient-2 [(colors/resolve-color :orange theme)
|
||||
(colors/resolve-color :purple theme)
|
||||
(colors/resolve-color :blue theme)]
|
||||
:gradient-3 [(colors/resolve-color :blue theme)
|
||||
(colors/resolve-color :magenta theme)
|
||||
(colors/resolve-color :yellow theme)]
|
||||
:gradient-4 [(colors/resolve-color :army theme)
|
||||
(colors/resolve-color :orange theme)
|
||||
(colors/resolve-color :blue theme)]
|
||||
[(colors/resolve-color :purple theme)
|
||||
(colors/resolve-color :army theme)
|
||||
(colors/resolve-color :yellow theme)]))
|
||||
|
||||
(defn view
|
||||
[{:keys [color-index container-style] :or {color-index 1}}]
|
||||
(let [theme (quo.theme/use-theme-value)]
|
||||
[linear-gradient/linear-gradient
|
||||
{:style (merge {:border-radius 16} container-style)
|
||||
:accessibility-label :gradient-overlay
|
||||
:colors (gradient-colors color-index theme)
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0 :y 1}}]))
|
||||
+13
-11
@@ -156,17 +156,19 @@
|
||||
(defn get-js-deps
|
||||
[deps]
|
||||
(if deps
|
||||
(let [prev-state (use-ref-atom {:value false :deps nil})
|
||||
prev-deps (:deps @prev-state)
|
||||
prev-value (:value @prev-state)]
|
||||
(if (and (not (nil? prev-deps)) (not= (count deps) (count prev-deps)))
|
||||
(throw (js/Error. "Hooks can't have a different number of dependencies across re-renders"))
|
||||
(if (not= deps prev-deps)
|
||||
(let [new-value (not prev-value)]
|
||||
(reset! prev-state {:value new-value
|
||||
:deps deps})
|
||||
#js [new-value])
|
||||
#js [prev-value])))
|
||||
(if (empty? deps)
|
||||
#js [true]
|
||||
(let [prev-state (use-ref-atom {:value false :deps nil})
|
||||
prev-deps (:deps @prev-state)
|
||||
prev-value (:value @prev-state)]
|
||||
(if (and (not (nil? prev-deps)) (not= (count deps) (count prev-deps)))
|
||||
(throw (js/Error. "Hooks can't have a different number of dependencies across re-renders"))
|
||||
(if (not= deps prev-deps)
|
||||
(let [new-value (not prev-value)]
|
||||
(reset! prev-state {:value new-value
|
||||
:deps deps})
|
||||
#js [new-value])
|
||||
#js [prev-value]))))
|
||||
js/undefined))
|
||||
|
||||
(defn use-effect
|
||||
|
||||
@@ -95,13 +95,34 @@
|
||||
(into [{:title title :header? true}] data))
|
||||
sections))
|
||||
|
||||
(defn- find-sticky-indices
|
||||
[data]
|
||||
(->> data
|
||||
(map-indexed (fn [index item] (when (:header? item) index)))
|
||||
(remove nil?)
|
||||
(vec)))
|
||||
|
||||
(defn- is-last-item-in-section
|
||||
[data index]
|
||||
(let [next-item (nth data (inc index) nil)]
|
||||
(or (nil? next-item) (:header? next-item))))
|
||||
|
||||
(defn section-list
|
||||
[{:keys [sections render-section-header-fn render-fn] :as props}]
|
||||
[{:keys [sections sticky-section-headers-enabled render-section-header-fn render-section-footer-fn
|
||||
render-fn]
|
||||
:or {sticky-section-headers-enabled true}
|
||||
:as props}]
|
||||
(let [data (flatten-sections sections)]
|
||||
[flat-list
|
||||
(merge props
|
||||
{:data data
|
||||
:render-fn (fn [p1 p2 p3 p4]
|
||||
(if (:header? p1)
|
||||
[render-section-header-fn p1 p2 p3 p4]
|
||||
[render-fn p1 p2 p3 p4]))})]))
|
||||
{:data data
|
||||
:render-fn (fn [p1 p2 p3 p4]
|
||||
[:<>
|
||||
(if (:header? p1)
|
||||
[render-section-header-fn p1 p2 p3 p4]
|
||||
[render-fn p1 p2 p3 p4])
|
||||
(when (and render-section-footer-fn
|
||||
(is-last-item-in-section data p2))
|
||||
[render-section-footer-fn p1 p2 p3 p4])])
|
||||
:sticky-header-indices (when sticky-section-headers-enabled
|
||||
(find-sticky-indices data))})]))
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
LinearTransition
|
||||
enableLayoutAnimations
|
||||
useAnimatedScrollHandler
|
||||
runOnJS)
|
||||
:as reanimated*]
|
||||
runOnJS)]
|
||||
["react-native-redash" :refer (withPause)]
|
||||
[react-native.flat-list :as rn-flat-list]
|
||||
[react-native.utils :as rn.utils]
|
||||
@@ -108,8 +107,6 @@
|
||||
(when (and anim (some? v))
|
||||
(set! (.-value anim) v)))
|
||||
|
||||
(def interpolate* reanimated*/interpolate)
|
||||
|
||||
(defn interpolate
|
||||
([shared-value input-range output-range]
|
||||
(interpolate shared-value input-range output-range nil))
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
(def ^:private ?cofx
|
||||
[:map])
|
||||
|
||||
(def ^:private ?event
|
||||
[:and
|
||||
[:vector {:min 1} :any]
|
||||
[:catn
|
||||
[:event-id keyword?]
|
||||
[:event-args [:* :any]]]])
|
||||
|
||||
(defn register-schemas
|
||||
[]
|
||||
(registry/register ::cofx ?cofx))
|
||||
(registry/register ::cofx ?cofx)
|
||||
(registry/register ::event ?event))
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
db (assoc-in db [:alert-banners (:type banner)] banner)]
|
||||
(cond-> {:db db}
|
||||
(zero? current-banners-count)
|
||||
(assoc :show-alert-banner nil))))
|
||||
(assoc :show-alert-banner (:view-id db)))))
|
||||
|
||||
(defn remove-alert-banner
|
||||
[{:keys [db]} [banner-type]]
|
||||
@@ -15,12 +15,12 @@
|
||||
new-count (count (get db :alert-banners))]
|
||||
(cond-> {:db db}
|
||||
(zero? new-count)
|
||||
(assoc :hide-alert-banner nil))))
|
||||
(assoc :hide-alert-banner (:view-id db)))))
|
||||
|
||||
(defn remove-all-alert-banners
|
||||
[{:keys [db]}]
|
||||
{:db (dissoc db :alert-banners)
|
||||
:hide-alert-banner nil})
|
||||
:hide-alert-banner (:view-id db)})
|
||||
|
||||
(re-frame/reg-event-fx :alert-banners/add add-alert-banner)
|
||||
(re-frame/reg-event-fx :alert-banners/remove remove-alert-banner)
|
||||
|
||||
@@ -66,26 +66,35 @@
|
||||
gradient-cover? customization-color hide-handle? blur-radius]
|
||||
:or {border-radius 12}}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
sheet-height (rn/use-ref-atom 0)
|
||||
item-height (rn/use-ref-atom 0)
|
||||
set-sheet-height (rn/use-callback #(reset! sheet-height (get-layout-height %)))
|
||||
set-item-height (rn/use-callback #(reset! item-height (get-layout-height %)))
|
||||
[sheet-height set-sheet-height] (rn/use-state 0)
|
||||
handle-sheet-height (rn/use-callback (fn [e]
|
||||
(when (= sheet-height 0)
|
||||
(set-sheet-height
|
||||
(get-layout-height e))))
|
||||
[sheet-height])
|
||||
[item-height set-item-height] (rn/use-state 0)
|
||||
handle-item-height (rn/use-callback (fn [e]
|
||||
(when (= item-height 0)
|
||||
(set-item-height
|
||||
(get-layout-height e))))
|
||||
[item-height])
|
||||
{window-height :height} (rn/get-window)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
translate-y (reanimated/use-shared-value window-height)
|
||||
sheet-gesture (get-sheet-gesture translate-y
|
||||
bg-opacity
|
||||
window-height
|
||||
on-close)
|
||||
selected-item-smaller-than-sheet? (< @item-height
|
||||
sheet-gesture (rn/use-memo #(get-sheet-gesture translate-y
|
||||
bg-opacity
|
||||
window-height
|
||||
on-close)
|
||||
[window-height on-close])
|
||||
selected-item-smaller-than-sheet? (< item-height
|
||||
(- window-height
|
||||
@sheet-height
|
||||
sheet-height
|
||||
(:top insets)
|
||||
(:bottom insets)
|
||||
bottom-margin))
|
||||
top (- window-height (:top insets) @sheet-height)
|
||||
top (- window-height (:top insets) sheet-height)
|
||||
bottom (if selected-item-smaller-than-sheet?
|
||||
(+ @sheet-height bottom-margin)
|
||||
(+ sheet-height bottom-margin)
|
||||
(:bottom insets))
|
||||
sheet-max-height (- window-height (:top insets))
|
||||
content-padding-bottom (or padding-bottom-override
|
||||
@@ -123,11 +132,12 @@
|
||||
:overlay-color :transparent}])
|
||||
(when selected-item
|
||||
[rn/view
|
||||
{:on-layout set-item-height
|
||||
:style (style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
|
||||
{:on-layout handle-item-height
|
||||
:style
|
||||
(style/selected-item theme top bottom selected-item-smaller-than-sheet? border-radius)}
|
||||
[selected-item]])
|
||||
[rn/view
|
||||
{:on-layout set-sheet-height
|
||||
{:on-layout handle-sheet-height
|
||||
:style (style/sheet-content {:theme theme
|
||||
:shell? shell?
|
||||
:padding-bottom content-padding-bottom})}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
(ns status-im.common.contact-list.style)
|
||||
(ns status-im.common.contact-list.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def contacts-section-footer
|
||||
{:height 8})
|
||||
|
||||
(defn contacts-section-header
|
||||
[first-item?]
|
||||
{:padding-top (if first-item? 0 8)})
|
||||
[theme]
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
(ns status-im.common.contact-list.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.contact-list.style :as style]))
|
||||
|
||||
(defn contacts-section-footer
|
||||
[]
|
||||
[rn/view style/contacts-section-footer])
|
||||
|
||||
(defn contacts-section-header
|
||||
[{:keys [title index]}]
|
||||
[rn/view (style/contacts-section-header (= index 0))
|
||||
[quo/divider-label title]])
|
||||
[{:keys [title]}]
|
||||
(let [theme (quo.theme/use-theme-value)]
|
||||
[rn/view (style/contacts-section-header theme)
|
||||
[quo/divider-label title]]))
|
||||
|
||||
@@ -148,28 +148,26 @@
|
||||
(reset! search-text ""))
|
||||
|
||||
(defn f-view
|
||||
[{:keys [search-text on-change-text clear-states active-category scroll-ref theme]
|
||||
[{:keys [search-active? on-change-text clear-states active-category scroll-ref theme]
|
||||
:as sheet-opts}]
|
||||
(let [search-active? (pos? (count @search-text))]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style style/flex-spacer
|
||||
:keyboard-vertical-offset 8}
|
||||
[rn/view {:style style/flex-spacer}
|
||||
[rn/view {:style style/search-input-container}
|
||||
[quo/input
|
||||
{:small? true
|
||||
:placeholder (i18n/label :t/emoji-search-placeholder)
|
||||
:icon-name :i/search
|
||||
:value @search-text
|
||||
:on-change-text on-change-text
|
||||
:clearable? search-active?
|
||||
:on-clear clear-states}]]
|
||||
[render-list sheet-opts]
|
||||
(when-not search-active?
|
||||
[footer
|
||||
{:theme theme
|
||||
:active-category active-category
|
||||
:scroll-ref scroll-ref}])]]))
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style style/flex-spacer
|
||||
:keyboard-vertical-offset 8}
|
||||
[rn/view {:style style/flex-spacer}
|
||||
[rn/view {:style style/search-input-container}
|
||||
[quo/input
|
||||
{:small? true
|
||||
:placeholder (i18n/label :t/emoji-search-placeholder)
|
||||
:icon-name :i/search
|
||||
:on-change-text on-change-text
|
||||
:clearable? search-active?
|
||||
:on-clear clear-states}]]
|
||||
[render-list sheet-opts]
|
||||
(when-not search-active?
|
||||
[footer
|
||||
{:theme theme
|
||||
:active-category active-category
|
||||
:scroll-ref scroll-ref}])]])
|
||||
|
||||
(defn- view-internal
|
||||
[_]
|
||||
@@ -202,7 +200,7 @@
|
||||
(fn [sheet-opts]
|
||||
[:f> f-view
|
||||
(assoc sheet-opts
|
||||
:search-text search-text
|
||||
:search-active? (pos? (count @search-text))
|
||||
:on-change-text on-change-text
|
||||
:clear-states clear-states
|
||||
:filtered-data @filtered-data
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
@@ -90,7 +91,7 @@
|
||||
{:on-layout set-header-height
|
||||
:style header-container-style}
|
||||
header]
|
||||
[rn/scroll-view
|
||||
[gesture/scroll-view
|
||||
{:on-scroll set-content-y-scroll
|
||||
:scroll-event-throttle 64
|
||||
:content-container-style {:flex-grow 1}}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user