Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f0ce0d7bd | ||
|
|
bc51a59774 | ||
|
|
4639660943 | ||
|
|
b58e7d6fff | ||
|
|
3b593bedac | ||
|
|
944cb6c822 | ||
|
|
8700886ae4 | ||
|
|
c5cc18e9e0 | ||
|
|
2b6f354fb6 | ||
|
|
717a225fd4 |
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"presets": [
|
||||
"module:metro-react-native-babel-preset"
|
||||
],
|
||||
"plugins": [
|
||||
"react-native-reanimated/plugin"
|
||||
]
|
||||
}
|
||||
@@ -200,7 +200,7 @@ status-im.utils.platform/isMacOs?
|
||||
status-im.utils.platform/isNix?
|
||||
status-im.utils.platform/isWin?
|
||||
status-im.utils.platform/android-version>=
|
||||
utils.debounce/clear-all
|
||||
status-im.utils.debounce/clear-all
|
||||
status-im.transport.db/create-chat
|
||||
status-im.utils.priority-map/priority-map
|
||||
status-im.utils.priority-map/priority-map-by
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
{:lint-as {status-im.utils.views/defview clojure.core/defn
|
||||
status-im.utils.views/letsubs clojure.core/let
|
||||
reagent.core/with-let clojure.core/let
|
||||
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
|
||||
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
|
||||
quo.react/with-deps-check clojure.core/fn
|
||||
quo.previews.preview/list-comp clojure.core/for
|
||||
status-im.utils.styles/def clojure.core/def
|
||||
status-im.utils.styles/defn clojure.core/defn
|
||||
status-im.test-helpers/deftest-sub clojure.core/defn
|
||||
taoensso.tufte/defnp clojure.core/defn}
|
||||
:linters {:consistent-alias {:level :error
|
||||
:aliases {clojure.string string
|
||||
taoensso.timbre log}}
|
||||
:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
|
||||
;; TODO remove number when this is fixed
|
||||
;; https://github.com/borkdude/clj-kondo/issues/867
|
||||
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
|
||||
number
|
||||
status-im.test-helpers/restore-app-db]}}}
|
||||
{:lint-as {status-im.utils.views/defview clojure.core/defn
|
||||
status-im.utils.views/letsubs clojure.core/let
|
||||
reagent.core/with-let clojure.core/let
|
||||
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
|
||||
quo.react/with-deps-check clojure.core/fn
|
||||
quo.previews.preview/list-comp clojure.core/for
|
||||
status-im.utils.styles/def clojure.core/def
|
||||
status-im.utils.styles/defn clojure.core/defn
|
||||
taoensso.tufte/defnp clojure.core/defn}
|
||||
:linters {:invalid-arity {:skip-args [status-im.utils.fx/defn]}
|
||||
;;TODO remove number when this is fixed
|
||||
;;https://github.com/borkdude/clj-kondo/issues/867
|
||||
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY number]}}}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
module.exports = {
|
||||
"testRunner": "jest",
|
||||
"testRegex": "\\.visual\\.js$",
|
||||
"runner-config": "visual-test/config.json",
|
||||
"devices": {
|
||||
"simulator": {
|
||||
"type": "ios.simulator",
|
||||
"device": {
|
||||
"type": "iPhone 11 Pro"
|
||||
}
|
||||
}
|
||||
},
|
||||
"apps": {
|
||||
"ios.release": {
|
||||
"name": "StatusIm",
|
||||
"type": "ios.app",
|
||||
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/StatusIm.app",
|
||||
"build": "make release-ios"
|
||||
},
|
||||
"ios.debug": {
|
||||
"name": "StatusIm",
|
||||
"type": "ios.app",
|
||||
"binaryPath": process.env.TEST_BINARY_PATH,
|
||||
"build": "make run-ios SIMULATOR='iPhone 11 Pro'"
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"ios.sim.release": {
|
||||
"device": "simulator",
|
||||
"app": "ios.release"
|
||||
},
|
||||
"ios.sim.debug": {
|
||||
"device": "simulator",
|
||||
"app": "ios.debug"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ DEFAULT_NETWORK=mainnet_rpc
|
||||
DEV_BUILD=1
|
||||
ETHEREUM_DEV_CLUSTER=1
|
||||
EXTENSIONS=0
|
||||
FLEET=status.prod
|
||||
FLEET=eth.prod
|
||||
GROUP_CHATS_ENABLED=1
|
||||
LOG_LEVEL=info
|
||||
MAILSERVER_CONFIRMATIONS_ENABLED=1
|
||||
@@ -32,4 +32,3 @@ COMMANDS_ENABLED=1
|
||||
TWO_MINUTES_SYNCING=1
|
||||
SWAP_ENABLED=1
|
||||
STICKERS_TEST_ENABLED=1
|
||||
LOCAL_PAIRING_ENABLED=1
|
||||
|
||||
@@ -2,7 +2,7 @@ DEBUG_WEBVIEW=1
|
||||
DEFAULT_NETWORK=goerli_rpc
|
||||
ETHEREUM_DEV_CLUSTER=1
|
||||
EXTENSIONS=0
|
||||
FLEET=status.prod
|
||||
FLEET=eth.staging
|
||||
GROUP_CHATS_ENABLED=1
|
||||
LOG_LEVEL=debug
|
||||
MAILSERVER_CONFIRMATIONS_ENABLED=0
|
||||
@@ -32,4 +32,3 @@ COMMUNITIES_MANAGEMENT_ENABLED=1
|
||||
DELETE_MESSAGE_ENABLED=1
|
||||
TWO_MINUTES_SYNCING=1
|
||||
STICKERS_TEST_ENABLED=1
|
||||
LOCAL_PAIRING_ENABLED=1
|
||||
|
||||
@@ -3,7 +3,7 @@ DEBUG_WEBVIEW=1
|
||||
DEFAULT_NETWORK=goerli_rpc
|
||||
ETHEREUM_DEV_CLUSTER=1
|
||||
EXTENSIONS=0
|
||||
FLEET=status.prod
|
||||
FLEET=eth.prod
|
||||
GROUP_CHATS_ENABLED=1
|
||||
LOG_LEVEL=debug
|
||||
MAILSERVER_CONFIRMATIONS_ENABLED=1
|
||||
@@ -34,4 +34,3 @@ DELETE_MESSAGE_ENABLED=1
|
||||
TWO_MINUTES_SYNCING=1
|
||||
ENABLE_QUO_PREVIEW=1
|
||||
STICKERS_TEST_ENABLED=1
|
||||
LOCAL_PAIRING_ENABLED=1
|
||||
|
||||
@@ -2,7 +2,7 @@ DEBUG_WEBVIEW=1
|
||||
DEFAULT_NETWORK=mainnet_rpc
|
||||
ETHEREUM_DEV_CLUSTER=1
|
||||
EXTENSIONS=0
|
||||
FLEET=status.prod
|
||||
FLEET=eth.prod
|
||||
GROUP_CHATS_ENABLED=1
|
||||
LOG_LEVEL=info
|
||||
MAILSERVER_CONFIRMATIONS_ENABLED=1
|
||||
|
||||
@@ -2,7 +2,7 @@ DEBUG_WEBVIEW=0
|
||||
DEFAULT_NETWORK=mainnet_rpc
|
||||
ETHEREUM_DEV_CLUSTER=0
|
||||
EXTENSIONS=0
|
||||
FLEET=status.prod
|
||||
FLEET=eth.prod
|
||||
GROUP_CHATS_ENABLED=1
|
||||
LOG_LEVEL=
|
||||
MAILSERVER_CONFIRMATIONS_ENABLED=1
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
# Xcode
|
||||
#
|
||||
/component-spec
|
||||
result/
|
||||
build/
|
||||
*.pbxuser
|
||||
@@ -176,11 +175,3 @@ test/appium/tests/users.py
|
||||
##node bindings
|
||||
/bin/
|
||||
/lib/
|
||||
|
||||
## visual tests
|
||||
/artifacts
|
||||
|
||||
/.calva/
|
||||
|
||||
## component-tests
|
||||
*.log
|
||||
@@ -48,7 +48,7 @@ export _NIX_GCROOTS = /nix/var/nix/gcroots/per-user/$(USER)/status-mobile
|
||||
# Defines which variables will be kept for Nix pure shell, use semicolon as divider
|
||||
export _NIX_KEEP ?= TMPDIR,BUILD_ENV,STATUS_GO_SRC_OVERRIDE
|
||||
|
||||
# Useful for Android release builds
|
||||
# Useful for Andoird release builds
|
||||
TMP_BUILD_NUMBER := $(shell ./scripts/version/gen_build_no.sh | cut -c1-10)
|
||||
|
||||
# MacOS root is read-only, read nix/README.md for details
|
||||
@@ -307,36 +307,13 @@ test-watch: ##@ Watch tests and re-run no changes to cljs files
|
||||
|
||||
test: export TARGET := clojure
|
||||
test: ##@test Run tests once in NodeJS
|
||||
# Here we create the gyp bindings for nodejs
|
||||
# Here we creates the gyp bindings for nodejs
|
||||
yarn install
|
||||
yarn shadow-cljs compile mocks && \
|
||||
yarn shadow-cljs compile test && \
|
||||
node --require ./test-resources/override.js target/test/test.js
|
||||
|
||||
|
||||
run-visual-test-ios: export TARGET := clojure
|
||||
run-visual-test-ios: XCODE_DERIVED_DATA := $(HOME)/Library/Developer/Xcode/DerivedData
|
||||
run-visual-test-ios: APPLICATION_NAME := StatusIm-brfnruzfrkkycpbndmdoeyrigthc
|
||||
run-visual-test-ios: export TEST_BINARY_PATH := $(XCODE_DERIVED_DATA)/$(APPLICATION_NAME)/Build/Products/Debug-iphonesimulator/StatusIm.app
|
||||
run-visual-test-ios: ##@test Run tests once in NodeJS
|
||||
detox test --configuration ios.sim.debug
|
||||
|
||||
component-test-watch: export TARGET := clojure
|
||||
component-test-watch: export COMPONENT_TEST := true
|
||||
component-test-watch: export BABEL_ENV := test
|
||||
component-test-watch: ##@ Watch tests and re-run no changes to cljs files
|
||||
yarn install
|
||||
nodemon --exec 'yarn shadow-cljs compile component-test && jest --config=test/jest/jest.config.js' -e cljs
|
||||
|
||||
component-test: export TARGET := clojure
|
||||
component-test: export COMPONENT_TEST := true
|
||||
component-test: export BABEL_ENV := test
|
||||
component-test: ##@test Run tests once in NodeJS
|
||||
# Here we create the gyp bindings for nodejs
|
||||
yarn install
|
||||
yarn shadow-cljs compile component-test && \
|
||||
jest --config=test/jest/jest.config.js
|
||||
|
||||
#--------------
|
||||
# Other
|
||||
#--------------
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
"presets": [
|
||||
"module:metro-react-native-babel-preset"
|
||||
],
|
||||
"plugins": [
|
||||
"react-native-reanimated/plugin"
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": [
|
||||
'@babel/preset-react',
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
node: '14',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -36,7 +36,7 @@ pipeline {
|
||||
LANG = "en_US.UTF-8"
|
||||
LC_ALL = "en_US.UTF-8"
|
||||
LANGUAGE = "en_US.UTF-8"
|
||||
TARGET = "android${utils.isE2EBuild() ? "-e2e" : ""}"
|
||||
TARGET = 'android'
|
||||
BUILD_ENV = 'prod'
|
||||
NIX_CONF_DIR = "${env.WORKSPACE}/nix"
|
||||
FASTLANE_DISABLE_COLORS = 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -62,7 +62,7 @@ pipeline {
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
-m testrail_id \
|
||||
-m \"new_ui_critical or new_ui_medium\" \
|
||||
-m \"new_ui_critical\" \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
--apk=${params.APK_NAME}
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.1'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -93,6 +93,6 @@ To use a physical iPhone your device UDID must be added to provisioning profiles
|
||||
- Invite your Apple account to be Developer in Status team.
|
||||
3. Run a build in XCode using the project from `status-mobile/ios` directory.
|
||||
- You might see error: `Select a development team in the Signing & Capabilities editor`
|
||||
- Select `Status Research & Development GmbH` as the development team and rebuild again.
|
||||
- Select `STATUS HOLDINGS PTE. LTD.` as the development team and rebuild again.
|
||||
|
||||
Once build finishes Status should start on your iPhone with its logs in terminal running `make run-metro`.
|
||||
|
||||
@@ -62,31 +62,6 @@ with the source file using it. For a real example, see
|
||||
(do-something)]])
|
||||
```
|
||||
|
||||
#### Styles def vs defn
|
||||
|
||||
Always use `def` over `defn`, unless the style relies on dynamic values, such as
|
||||
deref'ed atoms.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(defn title-column []
|
||||
{:height 56})
|
||||
|
||||
;; good
|
||||
(def title-column
|
||||
{:height 56})
|
||||
```
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(def community-card
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-90)})
|
||||
|
||||
;; good
|
||||
(defn community-card []
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-90)})
|
||||
```
|
||||
|
||||
### Using TODOs comments
|
||||
|
||||
_TODO_ comments are used extensively in the codebase, but prefer to use them
|
||||
@@ -274,22 +249,6 @@ test macros `deftest` and `is`, which are ubiquitous in the Clojure community.
|
||||
(:require [cljs-time.coerce :as time.coerce]))
|
||||
```
|
||||
|
||||
### Javascript interop
|
||||
|
||||
Use [binaryage/oops](https://github.com/binaryage/cljs-oops) macros instead of
|
||||
core interop macros.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(fn [^js event]
|
||||
(.-width (.-nativeEvent event)))
|
||||
|
||||
;; good
|
||||
(require '[oops.core :as oops])
|
||||
(fn [event]
|
||||
(oops/oget event "nativeEvent.width"))
|
||||
```
|
||||
|
||||
### Accessibility labels
|
||||
|
||||
Use keywords instead of strings. As a bonus, remember keywords are cached in
|
||||
@@ -337,53 +296,6 @@ keywords and concatenating them into a single string.
|
||||
(i18n/label :t/biometric-auth-error {:code error-code})
|
||||
```
|
||||
|
||||
### Tests
|
||||
#### Subscription tests
|
||||
|
||||
Test [layer-3 subscriptions](https://day8.github.io/re-frame/subscriptions/) by
|
||||
actually subscribing to them, so reframe's signal graph gets validated too.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(defn user-recipes
|
||||
[[current-user all-recipes location]]
|
||||
...)
|
||||
|
||||
(re-frame/reg-sub
|
||||
:user/recipes
|
||||
:<- [:current-user]
|
||||
:<- [:all-recipes]
|
||||
:<- [:location]
|
||||
user-recipes)
|
||||
|
||||
(deftest user-recipes-test
|
||||
(testing "builds list of recipes"
|
||||
(let [current-user {...}
|
||||
all-recipes {...}
|
||||
location [...]]
|
||||
(is (= expected (recipes [current-user all-recipes location]))))))
|
||||
|
||||
;; good
|
||||
(require '[status-im.test-helpers :as h])
|
||||
|
||||
(re-frame/reg-sub
|
||||
:user/recipes
|
||||
:<- [:current-user]
|
||||
:<- [:all-recipes]
|
||||
:<- [:location]
|
||||
(fn [[current-user all-recipes location]]
|
||||
...))
|
||||
|
||||
(h/deftest-sub :user/recipes
|
||||
[sub-name]
|
||||
(testing "builds list of recipes"
|
||||
(swap! rf-db/app-db assoc
|
||||
:current-user {...}
|
||||
:all-recipes {...}
|
||||
:location [...])
|
||||
(is (= expected (rf/sub [sub-name])))))
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
First, the bird's-eye view with some example ClojureScript files:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -319,6 +319,7 @@
|
||||
FBF6AB84EBC2085D28C3CDEF /* Pods-Status-StatusImPR.debug.xcconfig */,
|
||||
BF23313BEFBC84C6BB7E7677 /* Pods-Status-StatusImPR.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -400,12 +401,12 @@
|
||||
TargetAttributes = {
|
||||
00E356ED1AD99517003FC87E = {
|
||||
CreatedOnToolsVersion = 6.2;
|
||||
DevelopmentTeam = 8B5X2M6H2Y;
|
||||
DevelopmentTeam = DTX7Z4U3YA;
|
||||
ProvisioningStyle = Manual;
|
||||
TestTargetID = 13B07F861A680F5B00A75B9A;
|
||||
};
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
DevelopmentTeam = 8B5X2M6H2Y;
|
||||
DevelopmentTeam = DTX7Z4U3YA;
|
||||
LastSwiftMigration = 1140;
|
||||
ProvisioningStyle = Manual;
|
||||
SystemCapabilities = {
|
||||
@@ -424,7 +425,7 @@
|
||||
};
|
||||
};
|
||||
3AAD2AB924A3A60E0075D594 = {
|
||||
DevelopmentTeam = 8B5X2M6H2Y;
|
||||
DevelopmentTeam = DTX7Z4U3YA;
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
@@ -756,7 +757,7 @@
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
@@ -767,11 +768,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = StatusImTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -794,18 +791,14 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = StatusImTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -825,12 +818,12 @@
|
||||
BUNDLE_ID_SUFFIX = .debug;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = StatusIm/StatusIm.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CUSTOM_PRODUCT_NAME = "Status Debug";
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
EXCLUDED_ARCHS = "";
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -864,11 +857,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = StatusIm/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
@@ -899,12 +888,12 @@
|
||||
BUNDLE_ID_SUFFIX = "";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = StatusIm/StatusIm.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CUSTOM_PRODUCT_NAME = Status;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
EXCLUDED_ARCHS = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../modules/react-native-status/ios/RCTStatus",
|
||||
@@ -930,11 +919,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = StatusIm/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
@@ -968,7 +953,7 @@
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CUSTOM_PRODUCT_NAME = "Status Debug";
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../modules/react-native-status/ios/RCTStatus",
|
||||
"$(inherited)",
|
||||
@@ -999,11 +984,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = StatusImPR/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
@@ -1015,7 +996,7 @@
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum.pr;
|
||||
PRODUCT_NAME = "Status PR";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match Development im.status.ethereum.pr";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc im.status.ethereum.pr";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "StatusIm-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -1032,12 +1013,12 @@
|
||||
BUNDLE_ID_SUFFIX = "";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = StatusImPR/StatusImPR.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CUSTOM_PRODUCT_NAME = Status;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(PROJECT_DIR)/../modules/react-native-status/ios/RCTStatus",
|
||||
"$(inherited)",
|
||||
@@ -1062,11 +1043,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = StatusImPR/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
/usr/lib/swift,
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
@@ -1119,7 +1096,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -1202,7 +1179,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
|
||||
DEVELOPMENT_TEAM = DTX7Z4U3YA;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package im.status.ethereum.module;
|
||||
|
||||
import android.view.ActionMode;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.UIBlock;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.views.textinput.ReactEditText;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
class RNSelectableTextInputModule extends ReactContextBaseJavaModule {
|
||||
|
||||
private ActionMode lastActionMode;
|
||||
|
||||
public RNSelectableTextInputModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNSelectableTextInputManager";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setupMenuItems(final Integer selectableTextViewReactTag, final Integer textInputReactTag) {
|
||||
ReactApplicationContext reactContext = this.getReactApplicationContext();
|
||||
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
public void execute (NativeViewHierarchyManager nvhm) {
|
||||
RNSelectableTextInputViewManager rnSelectableTextManager = (RNSelectableTextInputViewManager) nvhm.resolveViewManager(selectableTextViewReactTag);
|
||||
ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag);
|
||||
rnSelectableTextManager.registerSelectionListener(reactTextView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void startActionMode(final Integer textInputReactTag) {
|
||||
ReactApplicationContext reactContext = this.getReactApplicationContext();
|
||||
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
public void execute (NativeViewHierarchyManager nvhm) {
|
||||
ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag);
|
||||
lastActionMode = reactTextView.startActionMode(reactTextView.getCustomSelectionActionModeCallback(), ActionMode.TYPE_FLOATING);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void hideLastActionMode(){
|
||||
ReactApplicationContext reactContext = this.getReactApplicationContext();
|
||||
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
public void execute (NativeViewHierarchyManager nvhm) {
|
||||
if(lastActionMode!=null){
|
||||
lastActionMode.finish();
|
||||
lastActionMode = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setSelection(final Integer textInputReactTag, final Integer start, final Integer end){
|
||||
ReactApplicationContext reactContext = this.getReactApplicationContext();
|
||||
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
|
||||
uiManager.addUIBlock(new UIBlock() {
|
||||
public void execute (NativeViewHierarchyManager nvhm) {
|
||||
ReactEditText reactTextView = (ReactEditText) nvhm.resolveView(textInputReactTag);
|
||||
reactTextView.setSelection(start, end);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package im.status.ethereum.module;
|
||||
|
||||
import android.view.ActionMode;
|
||||
import android.view.ActionMode.Callback;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import com.facebook.react.views.textinput.ReactEditText;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
import com.facebook.react.views.view.ReactViewManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RNSelectableTextInputViewManager extends ReactViewManager {
|
||||
public static final String REACT_CLASS = "RNSelectableTextInput";
|
||||
private String[] _menuItems = new String[0];
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactViewGroup createViewInstance(ThemedReactContext context) {
|
||||
return new ReactViewGroup(context);
|
||||
}
|
||||
|
||||
@ReactProp(name = "menuItems")
|
||||
public void setMenuItems(ReactViewGroup reactViewGroup, ReadableArray items) {
|
||||
if(items != null) {
|
||||
List<String> result = new ArrayList<String>(items.size());
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
result.add(items.getString(i));
|
||||
}
|
||||
this._menuItems = result.toArray(new String[items.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerSelectionListener(final ReactEditText view) {
|
||||
view.setCustomSelectionActionModeCallback(new Callback() {
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
menu.clear();
|
||||
for (int i = 0; i < _menuItems.length; i++) {
|
||||
menu.add(0, i, 0, _menuItems[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
int selectionStart = view.getSelectionStart();
|
||||
int selectionEnd = view.getSelectionEnd();
|
||||
String selectedText = view.getText().toString().substring(selectionStart, selectionEnd);
|
||||
|
||||
// Dispatch event
|
||||
onSelectNativeEvent(view, item.getItemId(), selectedText, selectionStart, selectionEnd);
|
||||
|
||||
mode.finish();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void onSelectNativeEvent(ReactEditText view, int eventType, String content, int selectionStart, int selectionEnd) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putInt("eventType", eventType);
|
||||
event.putString("content", content);
|
||||
event.putInt("selectionStart", selectionStart);
|
||||
event.putInt("selectionEnd", selectionEnd);
|
||||
|
||||
// Dispatch
|
||||
ReactContext reactContext = (ReactContext) view.getContext();
|
||||
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(view.getId(), "topSelection", event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getExportedCustomDirectEventTypeConstants() {
|
||||
return MapBuilder.builder()
|
||||
.put("topSelection", MapBuilder.of("registrationName","onSelection"))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -940,52 +940,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException {
|
||||
final JSONObject jsonConfig = new JSONObject(configJSON);
|
||||
final String keyUID = jsonConfig.getString("keyUID");
|
||||
final String keyStorePath = this.getKeyStorePath(keyUID);
|
||||
jsonConfig.put("keystorePath", keyStorePath);
|
||||
|
||||
if (!checkAvailability()) {
|
||||
callback.invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable runnableTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String res = Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString());
|
||||
callback.invoke(res);
|
||||
}
|
||||
};
|
||||
|
||||
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException {
|
||||
final JSONObject jsonConfig = new JSONObject(configJSON);
|
||||
final String keyStorePath = pathCombine(this.getNoBackupDirectory(), "/keystore");
|
||||
jsonConfig.put("keystorePath", keyStorePath);
|
||||
|
||||
if (!checkAvailability()) {
|
||||
callback.invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable runnableTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String res = Statusgo.inputConnectionStringForBootstrapping(connectionString,jsonConfig.toString());
|
||||
callback.invoke(res);
|
||||
}
|
||||
};
|
||||
|
||||
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void hashTypedData(final String data, final Callback callback) {
|
||||
Log.d(TAG, "hashTypedData");
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -30,15 +29,12 @@ public class StatusPackage implements ReactPackage {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
|
||||
modules.add(new StatusModule(reactContext, this.rootedDevice));
|
||||
modules.add(new RNSelectableTextInputModule(reactContext));
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Arrays.<ViewManager>asList(
|
||||
new RNSelectableTextInputViewManager()
|
||||
);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,42 +318,6 @@ RCT_EXPORT_METHOD(hashMessage:(NSString *)message
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// getConnectionStringForBootstrappingAnotherDevice
|
||||
RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
|
||||
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
|
||||
NSString *keyUID = [configDict objectForKey:@"keyUID"];
|
||||
NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID];
|
||||
NSString *keystoreDir = multiaccountKeystoreDir.path;
|
||||
|
||||
[configDict setValue:keystoreDir forKey:@"keystorePath"];
|
||||
NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO];
|
||||
|
||||
NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// inputConnectionStringForBootstrapping
|
||||
RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
|
||||
configJSON:(NSString *)configJSON
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
|
||||
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
|
||||
NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
|
||||
NSString *keystoreDir = multiaccountKeystoreDir.path;
|
||||
|
||||
[configDict setValue:keystoreDir forKey:@"keystorePath"];
|
||||
NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO];
|
||||
|
||||
NSString *result = StatusgoInputConnectionStringForBootstrapping(cs,modifiedConfigJSON);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// hashTypedData
|
||||
RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
@@ -538,11 +502,11 @@ RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData
|
||||
- (NSString *) getExportDbFilePath {
|
||||
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
|
||||
if ([fileManager fileExistsAtPath:filePath]) {
|
||||
[fileManager removeItemAtPath:filePath error:nil];
|
||||
}
|
||||
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
@@ -993,10 +957,10 @@ RCT_EXPORT_METHOD(exportUnencryptedDatabase:(NSString *)accountData
|
||||
#if DEBUG
|
||||
NSLog(@"exportUnencryptedDatabase() method called");
|
||||
#endif
|
||||
|
||||
|
||||
NSString *filePath = [self getExportDbFilePath];
|
||||
StatusgoExportUnencryptedDatabase(accountData, password, filePath);
|
||||
|
||||
|
||||
callback(@[filePath]);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ in stdenv.mkDerivation rec {
|
||||
filter = lib.mkFilter {
|
||||
root = path;
|
||||
include = [
|
||||
"package.json" "yarn.lock" "metro.config.js" "babel.config.js"
|
||||
"resources/.*" "translations/.*" "src/js/.*"
|
||||
"package.json" "yarn.lock" "metro.config.js" ".babelrc"
|
||||
"resources/.*" "translations/.*" "src/js/worklet_factory.js"
|
||||
"modules/react-native-status/android.*" "android/.*"
|
||||
envFileName "VERSION" "status-go-version.json" "react-native.config.js"
|
||||
];
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"react-native-touch-id": "^4.4.1",
|
||||
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"rn-emoji-keyboard": "0.7.0",
|
||||
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#refs/tags/v0.4.3",
|
||||
"tdigest": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -82,21 +82,12 @@
|
||||
"@babel/helper-builder-react-jsx": "7.0.0",
|
||||
"@babel/plugin-transform-block-scoping": "7.0.0",
|
||||
"@babel/preset-env": "7.1.0",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/register": "7.0.0",
|
||||
"@jest/globals": "^25.1.0",
|
||||
"@mapbox/node-pre-gyp": "^1.0.9",
|
||||
"@testing-library/jest-native": "^5.0.0",
|
||||
"@testing-library/react-native": "^11.2.0",
|
||||
"@types/jest": "^28.1.6",
|
||||
"detox": "^19.9.1",
|
||||
"jest": "^25.1.0",
|
||||
"jest-circus": "^26.0.0",
|
||||
"jest-image-snapshot": "^5.1.0",
|
||||
"nodemon": "^2.0.16",
|
||||
"nyc": "^14.1.1",
|
||||
"process": "0.11.10",
|
||||
"react-test-renderer": "16.13.1",
|
||||
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#refs/tags/v2.0.2-status",
|
||||
"shadow-cljs": "2.11.16"
|
||||
},
|
||||
|
||||
|
Before Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 758 B |
|
Before Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 759 B |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 924 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 377 KiB |
|
Before Width: | Height: | Size: 738 KiB |
@@ -2,10 +2,10 @@
|
||||
|
||||
CHANGES=$(git diff --no-ext-diff --diff-filter=d --cached --unified=0 --no-prefix --minimal --exit-code src/quo src/quo2 | grep '^+' || echo '')
|
||||
|
||||
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im)')
|
||||
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt)')
|
||||
|
||||
if test -n "$INVALID_CHANGES"; then
|
||||
echo "re-frame dispatch/subscribe and status-im are not allowed in quo/quo2 components"
|
||||
echo "re-frame dispatch/subscribe is not allowed in quo/quo2 components"
|
||||
echo ''
|
||||
echo "$INVALID_CHANGES"
|
||||
exit 1
|
||||
|
||||
@@ -64,15 +64,15 @@
|
||||
{:closure-defines
|
||||
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
|
||||
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
|
||||
:compiler-options {:output-feature-set :es6
|
||||
:compiler-options {:output-feature-set :es6
|
||||
;;disable for android build as there
|
||||
;;is an intermittent warning with deftype
|
||||
:warnings-as-errors false
|
||||
:infer-externs :auto
|
||||
:static-fns true
|
||||
:fn-invoke-direct true
|
||||
:optimizations :advanced
|
||||
:js-options {:js-provider :closure}}}}
|
||||
:warnings-as-errors false
|
||||
:infer-externs :auto
|
||||
:static-fns true
|
||||
:fn-invoke-direct true
|
||||
:optimizations :advanced
|
||||
:js-options {:js-provider :closure}}}}
|
||||
;; the tests are ran with node, react-native dependencies are mocked
|
||||
;; by using node --require override.js, which uses the node-library
|
||||
;; produced by the target :mocks below and redefines node require
|
||||
@@ -106,11 +106,4 @@
|
||||
:output-to "target/mocks/mocks.js"
|
||||
:output-dir "target/mocks"
|
||||
:compiler-options {:optimizations :simple
|
||||
:source-map false}}
|
||||
:component-test {:target :npm-module
|
||||
:entries [quo2.core-spec]
|
||||
:ns-regexp "-component-spec$"
|
||||
:output-dir "component-spec"
|
||||
:compiler-options {:warnings-as-errors false
|
||||
:static-fns false
|
||||
:infer-externs true}}}}
|
||||
:source-map false}}}}
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
|
||||
|
||||
// Shell Worklets
|
||||
|
||||
// Home Stack States
|
||||
const CLOSE_WITH_ANIMATION = 0;
|
||||
const OPEN_WITH_ANIMATION = 1;
|
||||
const CLOSE_WITHOUT_ANIMATION = 3;
|
||||
const OPEN_WITHOUT_ANIMATION = 4;
|
||||
|
||||
// Derived Values
|
||||
export function stackOpacity (stackId, selectedStackId) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return selectedStackId.value == stackId ? 1 : 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function stackPointer (stackId, selectedStackId) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return selectedStackId.value == stackId ? "auto" : "none";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function bottomTabIconColor (stackId, selectedStackId, homeStackState,
|
||||
passThrough, selectedTabColor, defaultColor,
|
||||
passThroughColor) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
var homeStackStateValue = homeStackState.value;
|
||||
if (selectedStackId.value == stackId &&
|
||||
(homeStackStateValue == OPEN_WITH_ANIMATION ||
|
||||
homeStackStateValue == OPEN_WITHOUT_ANIMATION)){
|
||||
return selectedTabColor;
|
||||
}
|
||||
else if (passThrough.value){
|
||||
return passThroughColor;
|
||||
}
|
||||
else {
|
||||
return defaultColor;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function bottomTabsHeight(homeStackState, height, extendedHeight) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
switch (homeStackState.value) {
|
||||
case OPEN_WITH_ANIMATION:
|
||||
return withTiming(extendedHeight, defaultDurationAndEasing);
|
||||
break;
|
||||
case CLOSE_WITH_ANIMATION:
|
||||
return withTiming(height, defaultDurationAndEasing);
|
||||
break;
|
||||
case OPEN_WITHOUT_ANIMATION:
|
||||
return extendedHeight;
|
||||
break;
|
||||
case CLOSE_WITHOUT_ANIMATION:
|
||||
return height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// Home Stack
|
||||
|
||||
const shellAnimationTime = 200;
|
||||
|
||||
const defaultDurationAndEasing = {
|
||||
duration: shellAnimationTime,
|
||||
easing: Easing.bezier(0, 0, 1, 1),
|
||||
}
|
||||
|
||||
export function homeStackOpacity (homeStackState) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
switch (homeStackState.value) {
|
||||
case OPEN_WITH_ANIMATION:
|
||||
return withTiming(1, defaultDurationAndEasing);
|
||||
break;
|
||||
case CLOSE_WITH_ANIMATION:
|
||||
return withTiming(0, defaultDurationAndEasing);
|
||||
break;
|
||||
case OPEN_WITHOUT_ANIMATION:
|
||||
return 1;
|
||||
break;
|
||||
case CLOSE_WITHOUT_ANIMATION:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackTop (homeStackState, top) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
switch (homeStackState.value) {
|
||||
case OPEN_WITH_ANIMATION:
|
||||
return withTiming(0, defaultDurationAndEasing);
|
||||
break;
|
||||
case CLOSE_WITH_ANIMATION:
|
||||
return withTiming(top, defaultDurationAndEasing);
|
||||
break;
|
||||
case OPEN_WITHOUT_ANIMATION:
|
||||
return 0;
|
||||
break;
|
||||
case CLOSE_WITHOUT_ANIMATION:
|
||||
return top;
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackLeft (selectedStackId, animateHomeStackLeft, homeStackState, left) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
if (animateHomeStackLeft.value) {
|
||||
var leftValue = left[selectedStackId.value];
|
||||
switch (homeStackState.value) {
|
||||
case OPEN_WITH_ANIMATION:
|
||||
return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, defaultDurationAndEasing))
|
||||
break;
|
||||
case CLOSE_WITH_ANIMATION:
|
||||
return withTiming(leftValue, defaultDurationAndEasing);
|
||||
break;
|
||||
case OPEN_WITHOUT_ANIMATION:
|
||||
return 0;
|
||||
break;
|
||||
case CLOSE_WITHOUT_ANIMATION:
|
||||
return leftValue;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackPointer (homeStackState) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
var homeStackStateValue = homeStackState.value;
|
||||
return (homeStackStateValue == OPEN_WITH_ANIMATION ||
|
||||
homeStackStateValue == OPEN_WITHOUT_ANIMATION) ? "auto" : "none";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackScale (homeStackState, minimizeScale) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
switch (homeStackState.value) {
|
||||
case OPEN_WITH_ANIMATION:
|
||||
return withTiming(1, defaultDurationAndEasing);
|
||||
break;
|
||||
case CLOSE_WITH_ANIMATION:
|
||||
return withTiming(minimizeScale, defaultDurationAndEasing);
|
||||
break;
|
||||
case OPEN_WITHOUT_ANIMATION:
|
||||
return 1;
|
||||
break;
|
||||
case CLOSE_WITHOUT_ANIMATION:
|
||||
return minimizeScale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
|
||||
|
||||
// Generic Worklets
|
||||
|
||||
export function applyAnimationsToStyle(animations, style) {
|
||||
@@ -27,3 +29,106 @@ export function applyAnimationsToStyle(animations, style) {
|
||||
return Object.assign(animatedStyle, style);
|
||||
};
|
||||
};
|
||||
|
||||
// Switcher Worklets
|
||||
|
||||
export function stackOpacity (stackId, selectedStackId) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return selectedStackId.value == stackId ? 1 : 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function stackPointer (stackId, selectedStackId) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return selectedStackId.value == stackId ? "auto" : "none";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function bottomTabIconColor (stackId, selectedStackId, homeStackOpen,
|
||||
passThrough, selectedTabColor, defaultColor,
|
||||
passThroughColor) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
if (selectedStackId.value == stackId && homeStackOpen.value){
|
||||
return selectedTabColor;
|
||||
}
|
||||
else if (passThrough.value){
|
||||
return passThroughColor;
|
||||
}
|
||||
else {
|
||||
return defaultColor;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Home Stack
|
||||
|
||||
const shellAnimationTime = 200;
|
||||
|
||||
const defaultDurationAndEasing = {
|
||||
duration: shellAnimationTime,
|
||||
easing: Easing.bezier(0, 0, 1, 1),
|
||||
}
|
||||
|
||||
export function homeStackOpacity (homeStackOpen) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return withTiming(homeStackOpen.value ? 1 : 0, defaultDurationAndEasing);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackTop (homeStackOpen, top) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return withTiming(homeStackOpen.value ? 0 : top, defaultDurationAndEasing);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackLeft (selectedStackId, animateHomeStackLeft, homeStackOpen, left) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
if (animateHomeStackLeft.value) {
|
||||
var leftValue = left[selectedStackId.value];
|
||||
if (homeStackOpen.value) {
|
||||
return withSequence(withTiming(leftValue, {duration: 0}), withTiming(0, defaultDurationAndEasing))
|
||||
} else {
|
||||
return withTiming(leftValue, defaultDurationAndEasing);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackPointer (homeStackOpen) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return homeStackOpen.value ? "auto" : "none";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function homeStackScale (homeStackOpen, minimizeScale) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return withTiming(homeStackOpen.value ? 1 : minimizeScale, defaultDurationAndEasing);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -282,8 +282,6 @@
|
||||
(def worklet-factory
|
||||
#js {:applyAnimationsToStyle (fn [])})
|
||||
|
||||
(def shell-worklets #js {})
|
||||
|
||||
;; Update i18n_resources.cljs
|
||||
(defn mock [module]
|
||||
(case module
|
||||
@@ -330,7 +328,6 @@
|
||||
"@react-native-async-storage/async-storage" async-storage
|
||||
"react-native-svg" react-native-svg
|
||||
"../src/js/worklet_factory.js" worklet-factory
|
||||
"../src/js/shell_worklets.js" shell-worklets
|
||||
"./fleets.js" default-fleets
|
||||
"./chats.js" default-chats
|
||||
"@walletconnect/client" wallet-connect-client
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
(defn button [{:keys [on-press disabled type theme before after
|
||||
haptic-feedback haptic-type on-long-press on-press-start
|
||||
accessibility-label loading border-radius style test-ID]
|
||||
accessibility-label loading border-radius style]
|
||||
:or {theme :main
|
||||
type :primary
|
||||
haptic-feedback true
|
||||
@@ -92,7 +92,7 @@
|
||||
{:on-press-start (fn []
|
||||
(optional-haptic)
|
||||
(on-press-start))}))
|
||||
[rn/view {:test-ID test-ID :style (merge (style-container type) style)}
|
||||
[rn/view {:style (merge (style-container type) style)}
|
||||
(when before
|
||||
[rn/view
|
||||
[icons/icon before {:color icon-color}]])
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
(def touchable-opacity (reagent/adapt-react-class (.-TouchableOpacity ^js rn)))
|
||||
(def touchable-highlight (reagent/adapt-react-class (.-TouchableHighlight ^js rn)))
|
||||
(def touchable-without-feedback (reagent/adapt-react-class (.-TouchableWithoutFeedback ^js rn)))
|
||||
(def text-input (reagent/adapt-react-class (.-TextInput ^js rn)))
|
||||
(def text-input (reagent/adapt-react-class (.-TextInput ^js rn)))
|
||||
|
||||
(def keyboard-avoiding-view-class (reagent/adapt-react-class (.-KeyboardAvoidingView ^js rn)))
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 142 KiB |
@@ -1,44 +0,0 @@
|
||||
const waitToNavigate = duration => new Promise(resolve => setTimeout(() => resolve(), duration));
|
||||
|
||||
const SUPER_SECRET_PASSWORD = 'password'
|
||||
|
||||
const loginToHomePage = async () => {
|
||||
if (device.getPlatform() === 'ios') {
|
||||
await device.setStatusBar({ time: '12:34', dataNetwork: 'wifi', wifiBars: '3', batteryState: 'charging', batteryLevel: '100' });
|
||||
}
|
||||
await device.reloadReactNative();
|
||||
await element(by.id('terms-of-service')).tap();
|
||||
await waitToNavigate(400);
|
||||
await element(by.id('get-started')).tap();
|
||||
await waitToNavigate(300);
|
||||
await element(by.id('generate-keys')).tap();
|
||||
await waitToNavigate(200);
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(700);
|
||||
await element(by.id('password-placeholder')).typeText(SUPER_SECRET_PASSWORD);
|
||||
await element(by.id('confirm-password-placeholder')).typeText(SUPER_SECRET_PASSWORD);
|
||||
await element(by.text('Next')).tap();
|
||||
await waitToNavigate(200);
|
||||
await element(by.id("browser-stack")).tap();
|
||||
await waitToNavigate(400);
|
||||
await element(by.text("Quo2.0 Preview")).tap();
|
||||
await waitToNavigate(400);
|
||||
}
|
||||
|
||||
describe('Default Renders', () => {
|
||||
beforeAll(async () => loginToHomePage())
|
||||
beforeEach(async () => {
|
||||
});
|
||||
afterEach(async () => {
|
||||
await element(by.id("back-button")).tap();
|
||||
await waitToNavigate(200);
|
||||
});
|
||||
|
||||
it(`button page should match image render`, async () => {
|
||||
await element(by.id(`quo2-:button`)).tap();
|
||||
await waitToNavigate(200);
|
||||
const res = await jestExpect(`button`).toMatchImageSnapshot();
|
||||
})
|
||||
});
|
||||
@@ -15,12 +15,18 @@
|
||||
(defn group-avatar [_]
|
||||
(fn [{:keys [color size]}]
|
||||
(let [container-size (get-in sizes [:container size])
|
||||
icon-size (get-in sizes [:icon size])]
|
||||
icon-size (get-in sizes [:icon size])
|
||||
;; theme (or override-theme (if (colors/dark?) :dark :light))
|
||||
]
|
||||
[rn/view {:width container-size
|
||||
:height container-size
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius (/ container-size 2)
|
||||
:background-color (colors/custom-color-by-theme color 50 60)}
|
||||
[icon/icon :i/group {:size icon-size
|
||||
:background-color color
|
||||
;; :background-color (if (= theme :light) TODO: colors/custom-color method here is not working for some reason.
|
||||
;; (colors/custom-color color 50)
|
||||
;; (colors/custom-color color 60))
|
||||
}
|
||||
[icon/icon :i/group {:size icon-size ; TODO: group icon sizes 12 and 20 (small and large) are missing
|
||||
:color colors/white-opa-70}]])))
|
||||
|
||||
@@ -122,20 +122,20 @@
|
||||
first-initial-letter
|
||||
initials)
|
||||
"")]
|
||||
[rn/view {:accessibility-label :user-avatar
|
||||
:style {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:border-radius outer-dimensions}}
|
||||
[rn/view {:style {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:border-radius outer-dimensions}}
|
||||
(when (and ring? identicon?)
|
||||
[icons/icon :i/identicon-ring {:size outer-dimensions
|
||||
:no-color true}])
|
||||
[icons/icon :main-icons/identicon-ring {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:size outer-dimensions
|
||||
:no-color true}])
|
||||
(if profile-picture
|
||||
;; display image
|
||||
[fast-image/fast-image {:source {:uri profile-picture}
|
||||
:style (container-styling inner-dimensions outer-dimensions)}]
|
||||
;; else display initials
|
||||
[container inner-dimensions outer-dimensions
|
||||
^{:key :icon-text}
|
||||
[text/text {:weight :semi-bold
|
||||
:size font-size
|
||||
:style {:color colors/white-opa-70}}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[clojure.string :as string]))
|
||||
[clojure.string :as clojure-string]))
|
||||
|
||||
(def circle-sizes {:small 20
|
||||
:medium 32
|
||||
@@ -29,10 +29,10 @@
|
||||
(let [circle-size (size circle-sizes)
|
||||
small? (= size :small)
|
||||
f-name-initial (-> f-name
|
||||
string/upper-case
|
||||
clojure-string/upper-case
|
||||
(subs 0 1))
|
||||
l-name-initial (-> l-name
|
||||
string/upper-case
|
||||
clojure-string/upper-case
|
||||
(subs 0 1))
|
||||
circle-color (colors/custom-color color 50 20)
|
||||
text-color (colors/custom-color-by-theme color 50 60)]
|
||||
|
||||
@@ -7,149 +7,147 @@
|
||||
[quo2.components.icon :as quo2.icons]))
|
||||
|
||||
(def themes
|
||||
{:light {:primary {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/primary-50
|
||||
:pressed colors/primary-60
|
||||
:disabled colors/primary-50}}
|
||||
:secondary {:icon-color colors/primary-50
|
||||
:label-color colors/primary-50
|
||||
:background-color {:default colors/primary-50-opa-20
|
||||
:pressed colors/primary-50-opa-40
|
||||
:disabled colors/primary-50-opa-20}}
|
||||
:grey {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label-color colors/neutral-100
|
||||
:background-color {:default colors/neutral-10
|
||||
:pressed colors/neutral-20
|
||||
:disabled colors/neutral-10}}
|
||||
:dark-grey {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label-color colors/neutral-100
|
||||
:background-color {:default colors/neutral-20
|
||||
:pressed colors/neutral-30
|
||||
:disabled colors/neutral-20}}
|
||||
:outline {:icon-color colors/neutral-50
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label-color colors/neutral-100
|
||||
:border-color {:default colors/neutral-20
|
||||
:pressed colors/neutral-40
|
||||
:disabled colors/neutral-20}}
|
||||
:ghost {:icon-color colors/neutral-50
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label-color colors/neutral-100
|
||||
:background-color {:pressed colors/neutral-10}}
|
||||
:danger {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/danger-50
|
||||
:pressed colors/danger-60
|
||||
:disabled colors/danger-50}}
|
||||
:positive {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/success-50
|
||||
:pressed colors/success-60
|
||||
:disabled colors/success-50-opa-30}}
|
||||
:photo-bg {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label-color colors/neutral-100
|
||||
:background-color {:default colors/white-opa-40
|
||||
:pressed colors/white-opa-50
|
||||
:disabled colors/white-opa-40}}
|
||||
:blur-bg {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label-color colors/neutral-100
|
||||
:background-color {:default colors/neutral-80-opa-5
|
||||
:pressed colors/neutral-80-opa-10
|
||||
:disabled colors/neutral-80-opa-5}}
|
||||
:blur-bg-outline {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label-color colors/neutral-100
|
||||
:border-color {:default colors/neutral-80-opa-10
|
||||
:pressed colors/neutral-80-opa-20
|
||||
:disabled colors/neutral-80-opa-10}}
|
||||
{:light {:primary {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/primary-50
|
||||
:pressed colors/primary-60
|
||||
:disabled colors/primary-50}}
|
||||
:secondary {:icon-color colors/primary-50
|
||||
:label {:style {:color colors/primary-50}}
|
||||
:background-color {:default colors/primary-50-opa-20
|
||||
:pressed colors/primary-50-opa-40
|
||||
:disabled colors/primary-50-opa-20}}
|
||||
:grey {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:background-color {:default colors/neutral-10
|
||||
:pressed colors/neutral-20
|
||||
:disabled colors/neutral-10}}
|
||||
:dark-grey {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:background-color {:default colors/neutral-20
|
||||
:pressed colors/neutral-30
|
||||
:disabled colors/neutral-20}}
|
||||
:outline {:icon-color colors/neutral-50
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:border-color {:default colors/neutral-20
|
||||
:pressed colors/neutral-40
|
||||
:disabled colors/neutral-20}}
|
||||
:ghost {:icon-color colors/neutral-50
|
||||
:icon-secondary-color colors/neutral-50
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:background-color {:pressed colors/neutral-10}}
|
||||
:danger {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/danger-50
|
||||
:pressed colors/danger-60
|
||||
:disabled colors/danger-50}}
|
||||
:positive {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/success-50
|
||||
:pressed colors/success-60
|
||||
:disabled colors/success-50-opa-30}}
|
||||
:photo-bg {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:background-color {:default colors/white-opa-40
|
||||
:pressed colors/white-opa-50
|
||||
:disabled colors/white-opa-40}}
|
||||
:blur-bg {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:background-color {:default colors/neutral-80-opa-5
|
||||
:pressed colors/neutral-80-opa-10
|
||||
:disabled colors/neutral-80-opa-5}}
|
||||
:blur-bg-outline {:icon-color colors/neutral-100
|
||||
:icon-secondary-color colors/neutral-80-opa-40
|
||||
:label {:style {:color colors/neutral-100}}
|
||||
:border-color {:default colors/neutral-80-opa-10
|
||||
:pressed colors/neutral-80-opa-20
|
||||
:disabled colors/neutral-80-opa-10}}
|
||||
:shell {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/neutral-95
|
||||
:pressed colors/neutral-95
|
||||
:disabled colors/neutral-95}}}
|
||||
:dark {:primary {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/primary-60
|
||||
:pressed colors/primary-50
|
||||
:disabled colors/primary-60}}
|
||||
:secondary {:icon-color colors/primary-50
|
||||
:label-color colors/primary-50
|
||||
:background-color {:default colors/primary-50-opa-20
|
||||
:pressed colors/primary-50-opa-30
|
||||
:disabled colors/primary-50-opa-20}}
|
||||
:grey {:icon-color colors/white
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/neutral-80
|
||||
:pressed colors/neutral-60
|
||||
:disabled colors/neutral-80}}
|
||||
:dark-grey {:icon-color colors/white
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/neutral-70
|
||||
:pressed colors/neutral-60
|
||||
:disabled colors/neutral-70}}
|
||||
:outline {:icon-color colors/neutral-40
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label-color colors/white
|
||||
:border-color {:default colors/neutral-70
|
||||
:pressed colors/neutral-60
|
||||
:disabled colors/neutral-70}}
|
||||
:ghost {:icon-color colors/neutral-40
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label-color colors/white
|
||||
:background-color {:pressed colors/neutral-80}}
|
||||
:danger {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/danger-60
|
||||
:pressed colors/danger-50
|
||||
:disabled colors/danger-60}}
|
||||
:positive {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/success-60
|
||||
:pressed colors/success-50
|
||||
:disabled colors/success-60-opa-30}}
|
||||
:photo-bg {:icon-color colors/white
|
||||
:icon-secondary-color colors/neutral-30
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/neutral-80-opa-40
|
||||
:pressed colors/neutral-80-opa-50
|
||||
:disabled colors/neutral-80-opa-40}}
|
||||
:blur-bg {:icon-color colors/white
|
||||
:icon-secondary-color colors/white-opa-40
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/white-opa-5
|
||||
:pressed colors/white-opa-10
|
||||
:disabled colors/white-opa-5}}
|
||||
:blur-bg-outline {:icon-color colors/white
|
||||
:icon-secondary-color colors/white-opa-40
|
||||
:label-color colors/white
|
||||
:border-color {:default colors/white-opa-10
|
||||
:pressed colors/white-opa-20
|
||||
:disabled colors/white-opa-5}}
|
||||
:shell {:icon-color colors/white
|
||||
:label-color colors/white
|
||||
:background-color {:default colors/neutral-95}}}})
|
||||
|
||||
(defn shape-style-container [type icon size]
|
||||
{:border-radius (if (and icon (#{:primary :secondary :danger} type))
|
||||
24
|
||||
(case size
|
||||
56 12
|
||||
40 12
|
||||
32 10
|
||||
24 8))})
|
||||
:dark {:primary {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/primary-60
|
||||
:pressed colors/primary-50
|
||||
:disabled colors/primary-60}}
|
||||
:secondary {:icon-color colors/primary-50
|
||||
:label {:style {:color colors/primary-50}}
|
||||
:background-color {:default colors/primary-50-opa-20
|
||||
:pressed colors/primary-50-opa-30
|
||||
:disabled colors/primary-50-opa-20}}
|
||||
:grey {:icon-color colors/white
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/neutral-80
|
||||
:pressed colors/neutral-60
|
||||
:disabled colors/neutral-80}}
|
||||
:dark-grey {:icon-color colors/white
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/neutral-70
|
||||
:pressed colors/neutral-60
|
||||
:disabled colors/neutral-70}}
|
||||
:outline {:icon-color colors/neutral-40
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label {:style {:color colors/white}}
|
||||
:border-color {:default colors/neutral-70
|
||||
:pressed colors/neutral-60
|
||||
:disabled colors/neutral-70}}
|
||||
:ghost {:icon-color colors/neutral-40
|
||||
:icon-secondary-color colors/neutral-40
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:pressed colors/neutral-80}}
|
||||
:danger {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/danger-60
|
||||
:pressed colors/danger-50
|
||||
:disabled colors/danger-60}}
|
||||
:positive {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/success-60
|
||||
:pressed colors/success-50
|
||||
:disabled colors/success-60-opa-30}}
|
||||
:photo-bg {:icon-color colors/white
|
||||
:icon-secondary-color colors/neutral-30
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/neutral-80-opa-40
|
||||
:pressed colors/neutral-80-opa-50
|
||||
:disabled colors/neutral-80-opa-40}}
|
||||
:blur-bg {:icon-color colors/white
|
||||
:icon-secondary-color colors/white-opa-40
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/white-opa-5
|
||||
:pressed colors/white-opa-10
|
||||
:disabled colors/white-opa-5}}
|
||||
:blur-bg-outline {:icon-color colors/white
|
||||
:icon-secondary-color colors/white-opa-40
|
||||
:label {:style {:color colors/white}}
|
||||
:border-color {:default colors/white-opa-10
|
||||
:pressed colors/white-opa-20
|
||||
:disabled colors/white-opa-5}}
|
||||
:shell {:icon-color colors/white
|
||||
:label {:style {:color colors/white}}
|
||||
:background-color {:default colors/neutral-95}}}})
|
||||
|
||||
(defn style-container [type size disabled background-color border-color icon above width before after]
|
||||
(merge {:height size
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:flex-direction (if above :column :row)
|
||||
:border-radius (if (and icon (#{:primary :secondary :danger} type))
|
||||
24
|
||||
(case size
|
||||
56 12
|
||||
40 12
|
||||
32 10
|
||||
24 8))
|
||||
:background-color background-color
|
||||
:padding-horizontal (when-not (or icon before after)
|
||||
(case size 56 16 40 16 32 12 24 8))
|
||||
@@ -161,7 +159,6 @@
|
||||
(case size 56 0 40 9 32 5 24 3))
|
||||
:padding-bottom (when-not (or icon before after)
|
||||
(case size 56 0 40 9 32 5 24 4))}
|
||||
(shape-style-container type icon size)
|
||||
(when width
|
||||
{:width width})
|
||||
(when icon
|
||||
@@ -172,19 +169,14 @@
|
||||
(when disabled
|
||||
{:opacity 0.3})))
|
||||
|
||||
(defn community-themed? [type community-color]
|
||||
(and (= type :community) (string? community-color)))
|
||||
|
||||
(defn button
|
||||
"with label
|
||||
[button opts \"label\"]
|
||||
opts
|
||||
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
|
||||
:danger/:photo-bg/:blur-bg/:blur-bg-ouline/:shell/:community
|
||||
:danger/:photo-bg/:blur-bg/:blur-bg-ouline/:shell
|
||||
:size 40/32/24
|
||||
:icon true/false
|
||||
:community-color '#FFFFFF'
|
||||
:community-text-color '#000000'
|
||||
:before :icon-keyword
|
||||
:after :icon-keyword}
|
||||
|
||||
@@ -192,21 +184,20 @@
|
||||
[button {:icon true} :main-icons/close-circle]"
|
||||
[_ _]
|
||||
(let [pressed (reagent/atom false)]
|
||||
(fn [{:keys [on-press disabled type size community-color community-text-color before after above width
|
||||
(fn [{:keys [on-press disabled type size before after above width
|
||||
override-theme override-background-color
|
||||
on-long-press accessibility-label icon icon-no-color style test-ID]
|
||||
on-long-press accessibility-label icon icon-no-color style]
|
||||
:or {type :primary
|
||||
size 40}}
|
||||
children]
|
||||
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color]}
|
||||
(let [{:keys [icon-color icon-secondary-color background-color label border-color]}
|
||||
(get-in themes [(or
|
||||
override-theme
|
||||
(theme/get-theme)) type])
|
||||
state (cond disabled :disabled @pressed :pressed :else :default)
|
||||
icon-size (when (= 24 size) 12)
|
||||
icon-secondary-color (or icon-secondary-color icon-color)]
|
||||
[rn/touchable-without-feedback (merge {:test-ID test-ID
|
||||
:disabled disabled
|
||||
[rn/touchable-without-feedback (merge {:disabled disabled
|
||||
:accessibility-label accessibility-label}
|
||||
(when on-press
|
||||
{:on-press (fn []
|
||||
@@ -220,65 +211,48 @@
|
||||
(reset! pressed nil))})
|
||||
|
||||
[rn/view {:style (merge
|
||||
(shape-style-container type icon size)
|
||||
{:background-color
|
||||
(if (= state :pressed)
|
||||
(colors/theme-colors colors/neutral-100 colors/white)
|
||||
:transparent)}
|
||||
(style-container
|
||||
type
|
||||
size
|
||||
disabled
|
||||
(or override-background-color (get background-color state))
|
||||
(get border-color state)
|
||||
icon
|
||||
above
|
||||
width
|
||||
before
|
||||
after)
|
||||
style)}
|
||||
[rn/view {:style (merge
|
||||
(style-container
|
||||
type
|
||||
size
|
||||
disabled
|
||||
(or override-background-color (get background-color state))
|
||||
(get border-color state)
|
||||
icon
|
||||
above
|
||||
width
|
||||
before
|
||||
after)
|
||||
(when
|
||||
(community-themed? type community-color)
|
||||
(merge
|
||||
{:background-color community-color}
|
||||
(when (= state :pressed) {:opacity 0.9}))))}
|
||||
(when above
|
||||
[rn/view
|
||||
[quo2.icons/icon above {:container-style {:margin-bottom 2}
|
||||
(when above
|
||||
[rn/view
|
||||
[quo2.icons/icon above {:container-style {:margin-bottom 2}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
(when before
|
||||
[rn/view
|
||||
[quo2.icons/icon before {:container-style {:margin-left (if (= size 40) 12 8)
|
||||
:margin-right 4}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
(when before
|
||||
[rn/view
|
||||
[quo2.icons/icon before {:container-style {:margin-left (if (= size 40) 12 8)
|
||||
:margin-right 4}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])
|
||||
[rn/view
|
||||
(cond
|
||||
(or icon icon-no-color)
|
||||
[quo2.icons/icon children {:color icon-color
|
||||
:no-color icon-no-color
|
||||
:size icon-size}]
|
||||
[rn/view
|
||||
(cond
|
||||
(or icon icon-no-color)
|
||||
[quo2.icons/icon children {:color icon-color
|
||||
:no-color icon-no-color
|
||||
:size icon-size}]
|
||||
|
||||
(string? children)
|
||||
[text/text {:size (when (#{56 24} size) :paragraph-2)
|
||||
:weight :medium
|
||||
:number-of-lines 1
|
||||
:style {:color (if
|
||||
(and
|
||||
(community-themed? type community-color)
|
||||
(string? community-text-color))
|
||||
community-text-color
|
||||
label-color)}}
|
||||
(string? children)
|
||||
[text/text (merge {:size (when (#{56 24} size) :paragraph-2)
|
||||
:weight :medium
|
||||
:number-of-lines 1}
|
||||
label)
|
||||
children]
|
||||
|
||||
children]
|
||||
|
||||
(vector? children)
|
||||
children)]
|
||||
(when after
|
||||
[rn/view
|
||||
[quo2.icons/icon after {:container-style {:margin-left 4
|
||||
:margin-right (if (= size 40) 12 8)}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])]]]))))
|
||||
(vector? children)
|
||||
children)]
|
||||
(when after
|
||||
[rn/view
|
||||
[quo2.icons/icon after {:container-style {:margin-left 4
|
||||
:margin-right (if (= size 40) 12 8)}
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])]]))))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns quo2.components.code.snippet
|
||||
(:require ["react-native" :as react-native]
|
||||
[cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[clojure.string :as str]
|
||||
[oops.core :as oops]
|
||||
[react-native.core :as rn]
|
||||
[quo2.theme :as theme]
|
||||
@@ -52,7 +52,7 @@
|
||||
:style (text-style (get-in node [:properties :className]))}]
|
||||
(render-nodes children))
|
||||
;; Remove newlines as we already render each line separately.
|
||||
(-> value string/trim-newline)))
|
||||
(-> value str/trim-newline)))
|
||||
nodes))
|
||||
|
||||
(defn- code-block [{:keys [rows line-number-width]}]
|
||||
|
||||
@@ -6,11 +6,15 @@
|
||||
|
||||
(defn community-card-view-item
|
||||
[{:keys [name description locked
|
||||
status tokens cover tags width]} on-press]
|
||||
status tokens cover tags featured]} on-press]
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[rn/view {:style (style/community-card 20)}
|
||||
[rn/view {:style {:width width
|
||||
:height 230
|
||||
[rn/view {:style (merge (style/community-card 20)
|
||||
{:margin-bottom 16}
|
||||
(if featured
|
||||
{:margin-right 12}
|
||||
{:flex 1
|
||||
:margin-horizontal 20}))}
|
||||
[rn/view {:style {:height 230
|
||||
:border-radius 20}
|
||||
:on-press on-press}
|
||||
[rn/view
|
||||
|
||||
@@ -28,9 +28,13 @@
|
||||
[community-stats {:icon :i/group
|
||||
:members-count "629.2K" ;;TODO here should be formatted value, use money/format-members from outside this component
|
||||
:icon-color icon-color}]
|
||||
[community-stats {:icon :i/lightning
|
||||
[community-stats {:icon :i/lightning
|
||||
:members-count "112.1K"
|
||||
:icon-color icon-color}]]))
|
||||
:icon-color icon-color}]
|
||||
(when (= type :card-view)
|
||||
[community-stats {:icon :i/placeholder
|
||||
:count 4
|
||||
:icon-color icon-color}])]))
|
||||
|
||||
(defn community-tags [tags]
|
||||
[rn/view (style/community-tags-container)
|
||||
@@ -65,12 +69,10 @@
|
||||
:style {:margin-top (if (= size :large) 8 2)}}
|
||||
description])])
|
||||
|
||||
(defn permission-tag-container [{:keys [locked? tokens on-press]}]
|
||||
(defn permission-tag-container [{:keys [locked? tokens]}]
|
||||
[permission/tag {:background-color (colors/theme-colors
|
||||
colors/neutral-10
|
||||
colors/neutral-80)
|
||||
:locked? locked?
|
||||
:tokens tokens
|
||||
|
||||
:size 24
|
||||
:on-press on-press}])
|
||||
:size 24}])
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
(ns quo2.components.community.token-gating
|
||||
(:require [quo.react-native :as rn]
|
||||
[quo2.components.avatars.channel-avatar :as channel-avatar]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.info.information-box :as information-box]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.tags.token-tag :as token-tag]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.ui.components.fast-image :as fast-image]))
|
||||
|
||||
(def ^:private token-tag-horizontal-spacing 7)
|
||||
(def token-tag-vertical-spacing 5)
|
||||
|
||||
(def styles {:container {:flex 1
|
||||
:padding-horizontal 20}
|
||||
:header-container {:flex-direction :row
|
||||
:align-items :center}
|
||||
:header-spacing-community {:margin-bottom 16}
|
||||
:header-spacing-channel {:margin-bottom 24}
|
||||
:header-avatar {:margin-right 8}
|
||||
:header-community-avatar-image {:width 32 :height 32}
|
||||
:header-title-container {:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center}
|
||||
:header-title-lock {:margin-left 6}
|
||||
:header-info-button {:margin-left 8}
|
||||
:token-requirement-text-spacing {:margin-vertical 8}
|
||||
:token-requirement-list-spacing {:padding-vertical (- 8 token-tag-vertical-spacing)}
|
||||
:token-row {:flex-direction :row
|
||||
:flex-wrap :wrap
|
||||
:align-items :center}
|
||||
:token-row-container {:flex-direction :row
|
||||
:align-items :center
|
||||
:margin-horizontal (- token-tag-horizontal-spacing)}
|
||||
:token-row-container-no-shift {:margin-left 0}
|
||||
:token-row-or-text {:margin-right 3}
|
||||
:token-tag-spacing {:margin-horizontal token-tag-horizontal-spacing
|
||||
:margin-vertical token-tag-vertical-spacing}
|
||||
:divider {:height 1
|
||||
:margin-horizontal -20
|
||||
:margin-top (- 12 token-tag-vertical-spacing)
|
||||
:margin-bottom 8}
|
||||
:membership-request-denied {:margin-top 13}
|
||||
:enter-button {:margin-top 16}
|
||||
:info-text {:margin-top 12
|
||||
:text-align :center
|
||||
:padding-horizontal 20}})
|
||||
|
||||
(defn multiple-token-requirements? [token-requirement-lists]
|
||||
(when (vector? (first token-requirement-lists))
|
||||
(> (count token-requirement-lists) 1)))
|
||||
|
||||
(defn is-token-requirement-met? [token-requirement-list]
|
||||
(and (seq token-requirement-list)
|
||||
(every?
|
||||
(fn [token]
|
||||
(get token :is-sufficient?))
|
||||
token-requirement-list)))
|
||||
|
||||
(defn are-multiple-token-requirements-met? [token-requirement-lists]
|
||||
(if (multiple-token-requirements? token-requirement-lists)
|
||||
(some is-token-requirement-met? token-requirement-lists)
|
||||
(is-token-requirement-met? token-requirement-lists)))
|
||||
|
||||
(defn token-requirement-list-row [tokens community-color]
|
||||
[rn/view {:style (merge
|
||||
(get styles :token-row)
|
||||
(get styles :token-requirement-list-spacing))}
|
||||
(map-indexed (fn [token-index token]
|
||||
(let [{:keys [token-img-src token amount is-sufficient? is-purchasable?]} token]
|
||||
^{:key token-index}
|
||||
[rn/view {:style (get styles :token-tag-spacing)}
|
||||
[token-tag/token-tag {:token token
|
||||
:value amount
|
||||
:size 24
|
||||
:border-color community-color
|
||||
:is-required is-sufficient?
|
||||
:is-purchasable is-purchasable?
|
||||
:token-img-src token-img-src}]]))
|
||||
tokens)])
|
||||
|
||||
(defn token-requirement-list [props community-color]
|
||||
(let [{:keys [gate token-requirements-changed? required-tokens-lost?]} props
|
||||
[gate-type token-requirement-lists] gate
|
||||
multiple-token-requirements? (multiple-token-requirements? token-requirement-lists)
|
||||
is-sufficient? (are-multiple-token-requirements-met? token-requirement-lists)
|
||||
you-must-hold-label (if (= gate-type :join)
|
||||
(cond
|
||||
token-requirements-changed? :t/you-must-now-hold
|
||||
required-tokens-lost? :t/you-must-always-hold
|
||||
:else :t/you-must-hold)
|
||||
:t/you-must-hold)
|
||||
message-label (cond
|
||||
(= gate-type :join)
|
||||
(cond
|
||||
token-requirements-changed? :t/community-join-requirements-changed
|
||||
required-tokens-lost? :t/community-join-requirements-tokens-lost
|
||||
:else (if is-sufficient? :t/community-join-requirements-met :t/community-join-requirements-not-met))
|
||||
(= gate-type :read)
|
||||
(if is-sufficient?
|
||||
:t/community-channel-read-requirements-met
|
||||
:t/community-channel-read-requirements-not-met)
|
||||
(= gate-type :write)
|
||||
(if is-sufficient?
|
||||
:t/community-channel-write-requirements-met
|
||||
:t/community-channel-write-requirements-not-met))]
|
||||
[rn/view
|
||||
[rn/view {:style (get styles :token-requirement-text-spacing)}
|
||||
[text/text {:weight :medium
|
||||
:number-of-lines 1}
|
||||
(i18n/label
|
||||
message-label)]
|
||||
[text/text {:size :paragraph-2
|
||||
:number-of-lines 1}
|
||||
(i18n/label
|
||||
you-must-hold-label)]]
|
||||
|
||||
(if multiple-token-requirements?
|
||||
(map-indexed
|
||||
(fn [token-requirement-index tokens]
|
||||
^{:key token-requirement-index}
|
||||
[rn/view {:style (merge
|
||||
(get styles :token-row-container)
|
||||
(when-not (= token-requirement-index 0)
|
||||
(get styles :token-row-container-no-shift)))}
|
||||
(when-not (= token-requirement-index 0)
|
||||
[text/text {:style (get styles :token-row-or-text)
|
||||
:size :paragraph-2} "or"])
|
||||
[token-requirement-list-row tokens community-color]])
|
||||
token-requirement-lists)
|
||||
[rn/view {:style (get styles :token-row-container)}
|
||||
[token-requirement-list-row token-requirement-lists community-color]])]))
|
||||
|
||||
(defn is-community-locked? [community]
|
||||
(not (are-multiple-token-requirements-met? (get-in community [:gates :join]))))
|
||||
|
||||
(defn is-channel-locked? [channel]
|
||||
(not (are-multiple-token-requirements-met?
|
||||
(or (get-in channel [:gates :read])
|
||||
(get-in channel [:gates :write])))))
|
||||
|
||||
(defn token-gating
|
||||
"[token-gating opts]
|
||||
opts
|
||||
{
|
||||
:community {
|
||||
:name string
|
||||
:community-avatar-img-src string
|
||||
:community-color string
|
||||
:community-text-color string
|
||||
:token-requirements-changed? boolean
|
||||
:required-tokens-lost? boolean
|
||||
}
|
||||
:channel {
|
||||
:name string
|
||||
:emoji string
|
||||
:emoji-background-color :string
|
||||
:on-enter-channel callback
|
||||
:membership-request-denied? boolean
|
||||
}
|
||||
}"
|
||||
[_ _]
|
||||
(fn [{:keys [community channel]}]
|
||||
(let [type (if (some? community) :community :channel)
|
||||
{:keys [name
|
||||
emoji
|
||||
emoji-background-color
|
||||
on-enter-channel
|
||||
community-avatar-img-src
|
||||
community-color
|
||||
community-text-color
|
||||
membership-request-denied?
|
||||
token-requirements-changed?
|
||||
required-tokens-lost?
|
||||
gates]} (if (= type :community) community channel)
|
||||
locked? (if
|
||||
(= type :community)
|
||||
(is-community-locked? community)
|
||||
(is-channel-locked? channel))]
|
||||
|
||||
[rn/view {:style (merge (get styles :container) {:background-color (colors/theme-colors colors/white colors/neutral-90)})}
|
||||
[rn/view {:style (merge
|
||||
(get styles :header-container)
|
||||
(if
|
||||
(= type :community)
|
||||
(get styles :header-spacing-community)
|
||||
(get styles :header-spacing-channel)))}
|
||||
|
||||
[rn/view {:style (get styles :header-avatar)}
|
||||
(if (= type :community)
|
||||
[fast-image/fast-image {:source community-avatar-img-src
|
||||
:style (get styles :header-community-avatar-image)}]
|
||||
|
||||
[channel-avatar/channel-avatar {:big? true
|
||||
:locked? locked?
|
||||
:emoji emoji
|
||||
:emoji-background-color emoji-background-color}])]
|
||||
|
||||
[rn/view {:style (get styles :header-title-container)}
|
||||
[text/text {:weight :semi-bold
|
||||
:number-of-lines 1
|
||||
:size :heading-1
|
||||
:style (get styles :header-text)} (if (= type :community) name (str "# " name))]
|
||||
|
||||
(when (= type :community)
|
||||
[icon/icon (if locked?
|
||||
:main-icons2/locked
|
||||
:main-icons2/unlocked)
|
||||
{:container-style (get styles :header-title-lock)
|
||||
:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40)}])]
|
||||
|
||||
[button/button {:type :outline
|
||||
:size 32
|
||||
:icon true
|
||||
:style (get styles :header-info-button)} :main-icons2/info]]
|
||||
|
||||
(map-indexed (fn [gate-index gate]
|
||||
^{:key gate-index}
|
||||
[:<>
|
||||
(when-not (= gate-index 0)
|
||||
[rn/view {:style (merge
|
||||
(get styles :divider)
|
||||
{:background-color (colors/theme-colors
|
||||
colors/neutral-10
|
||||
colors/neutral-80)})}])
|
||||
[token-requirement-list {:gate gate :token-requirements-changed? token-requirements-changed? :required-tokens-lost? required-tokens-lost?} community-color]])
|
||||
gates)
|
||||
|
||||
(when (= type :channel)
|
||||
(if membership-request-denied?
|
||||
[information-box/information-box {:type :error
|
||||
:icon :main-icons2/untrustworthy
|
||||
:no-icon-color? true
|
||||
:style (get styles :membership-request-denied)}
|
||||
(i18n/label
|
||||
:t/membership-request-denied)]
|
||||
|
||||
[:<>
|
||||
[button/button {:type :community
|
||||
:community-color community-color
|
||||
:community-text-color community-text-color
|
||||
:style (get styles :enter-button)
|
||||
:disabled locked?
|
||||
:on-press on-enter-channel}
|
||||
(str "# " (i18n/label
|
||||
:t/enter-channel))]
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style (merge
|
||||
(get styles :info-text)
|
||||
{:color (colors/theme-colors
|
||||
colors/neutral-50
|
||||
colors/neutral-40)})}
|
||||
(i18n/label
|
||||
:t/community-enter-channel-info)]]))])))
|
||||
@@ -1,34 +0,0 @@
|
||||
(ns quo2.components.counter.--tests--.counter-component-spec
|
||||
(:require ["@testing-library/react-native" :as rtl]
|
||||
[quo2.components.counter.counter :as counter]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn render-counter
|
||||
([]
|
||||
(render-counter {} nil))
|
||||
([opts value]
|
||||
(rtl/render (reagent/as-element [counter/counter opts value]))))
|
||||
|
||||
(js/global.test "default render of counter component"
|
||||
(fn []
|
||||
(render-counter)
|
||||
(-> (js/expect (rtl/screen.getByTestId "counter-component"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "renders counter with a string value"
|
||||
(fn []
|
||||
(render-counter {} "1")
|
||||
(-> (js/expect (rtl/screen.getByText "1"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "renders counter with an integer value"
|
||||
(fn []
|
||||
(render-counter {} 1)
|
||||
(-> (js/expect (rtl/screen.getByText "1"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "renders counter with value 99+ when the value is greater than 99"
|
||||
(fn []
|
||||
(render-counter {} "100")
|
||||
(-> (js/expect (rtl/screen.getByText "99+"))
|
||||
(.toBeTruthy))))
|
||||
@@ -20,7 +20,7 @@
|
||||
(defn counter
|
||||
"type: default, secondary, grey, outline
|
||||
value: integer"
|
||||
[{:keys [type override-text-color override-bg-color style accessibility-label]} value]
|
||||
[{:keys [type override-text-color override-bg-color style]} value]
|
||||
(let [type (or type :default)
|
||||
text-color (or override-text-color
|
||||
(if (or
|
||||
@@ -38,10 +38,7 @@
|
||||
1 16
|
||||
2 20
|
||||
28)]
|
||||
[rn/view {:test-ID :counter-component
|
||||
:accessible true
|
||||
:accessibility-label accessibility-label
|
||||
:style (cond-> (merge
|
||||
[rn/view {:style (cond-> (merge
|
||||
{:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius 6
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns quo2.components.dividers.date
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.separator :as separator]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn date [value]
|
||||
[rn/view {:margin-vertical 16
|
||||
:padding-right 8
|
||||
:padding-left 62}
|
||||
[text/text {:weight :medium
|
||||
:accessibility-label :divider-date-text
|
||||
:size :label
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
:text-transform :capitalize
|
||||
:margin-bottom 4}}
|
||||
value]
|
||||
[separator/separator]])
|
||||
@@ -1,63 +0,0 @@
|
||||
(ns quo2.components.drawers.--tests--.action-drawers-component-spec
|
||||
(:require ["@testing-library/react-native" :as rtl]
|
||||
[quo2.components.drawers.action-drawers :as action-drawer]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn render-action-drawer
|
||||
([options]
|
||||
(rtl/render (reagent/as-element [action-drawer/action-drawer options]))))
|
||||
|
||||
(js/global.test "action-drawer renders with elements label displaying"
|
||||
(fn []
|
||||
(render-action-drawer [[{:icon :i/friend
|
||||
:label "a sample label"}]])
|
||||
(-> (js/expect (rtl/screen.getByText "a sample label"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "action-drawer renders with elements sub-label displaying"
|
||||
(fn []
|
||||
(render-action-drawer [[{:icon :i/friend
|
||||
:label "a sample label"
|
||||
:sub-label "a sample sub label"}]])
|
||||
(-> (js/expect (rtl/screen.getByText "a sample sub label"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "action-drawer on click action works on element"
|
||||
(let [event (js/jest.fn)]
|
||||
(fn []
|
||||
(render-action-drawer [[{:icon :i/friend
|
||||
:label "a sample label"
|
||||
:on-press event}]])
|
||||
(rtl/fireEvent.press (rtl/screen.getByText "a sample label"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled)))))
|
||||
|
||||
(js/global.test "action-drawer renders two icons when set"
|
||||
(fn []
|
||||
(render-action-drawer [[{:icon :i/friend
|
||||
:label "a sample label"
|
||||
:right-icon :i/friend
|
||||
:accessibility-label :first-element}]])
|
||||
(-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "action-drawer does not render a divider when the add-divider? prop is false"
|
||||
(fn []
|
||||
(render-action-drawer [[{:icon :i/friend
|
||||
:label "a sample label"
|
||||
:add-divider? false
|
||||
:accessibility-label :first-element}]])
|
||||
(-> (js/expect (rtl/screen.getAllByLabelText "divider"))
|
||||
(.not)
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "action-drawer renders a divider when the add-divider? prop is true"
|
||||
(fn []
|
||||
(render-action-drawer [[{:icon :i/friend
|
||||
:label "a sample label"
|
||||
:add-divider? true
|
||||
:accessibility-label :first-element}]])
|
||||
(-> (js/expect (rtl/screen.getAllByLabelText "divider"))
|
||||
(.toBeTruthy))))
|
||||
@@ -6,84 +6,69 @@
|
||||
|
||||
(defn- get-icon-color [danger?]
|
||||
(if danger?
|
||||
colors/danger-50
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40)))
|
||||
|
||||
(def divider
|
||||
[rn/view {:style {:border-top-width 1
|
||||
:border-top-color (colors/theme-colors
|
||||
colors/neutral-10 colors/neutral-90)
|
||||
:margin-top 8
|
||||
:margin-bottom 7
|
||||
:align-items :center
|
||||
:flex-direction :row}
|
||||
:accessible true
|
||||
:accessibility-label :divider}])
|
||||
|
||||
(defn action [{:keys [icon
|
||||
label
|
||||
sub-label
|
||||
right-icon
|
||||
danger?
|
||||
on-press
|
||||
add-divider?
|
||||
accessibility-label] :as action-props}]
|
||||
on-press] :as action-props}]
|
||||
(when action-props
|
||||
[:<> {:key label}
|
||||
(when add-divider? divider)
|
||||
[rn/touchable-highlight {:accessibility-label accessibility-label
|
||||
:style {:border-radius 12
|
||||
:height (if sub-label 58 50)
|
||||
:margin-horizontal 8}
|
||||
:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
|
||||
:on-press on-press}
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[rn/view {:style
|
||||
{:height (if sub-label 56 47)
|
||||
:margin-horizontal 20
|
||||
:flex-direction :row}}
|
||||
[rn/view {:style
|
||||
{:height (if sub-label 58 50)
|
||||
:margin-horizontal 12
|
||||
:flex-direction :row}}
|
||||
[rn/view {:accessibility-label :left-icon-for-action
|
||||
:accessible true
|
||||
:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:margin-right 12
|
||||
:width 20}}
|
||||
[icon/icon icon
|
||||
{:color (get-icon-color danger?)
|
||||
:size 20}]]
|
||||
[rn/view
|
||||
{:style
|
||||
{:flex 1
|
||||
:justify-content :center}}
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color
|
||||
(when danger?
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60))}}
|
||||
label]
|
||||
(when sub-label
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style {:color
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
sub-label])]
|
||||
(when right-icon
|
||||
[rn/view {:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:width 20}
|
||||
:accessible true
|
||||
:accessibility-label :right-icon-for-action}
|
||||
[icon/icon right-icon
|
||||
{:color (get-icon-color danger?)
|
||||
:size 20}]])]]]))
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:margin-right 12
|
||||
:width 20}}
|
||||
[icon/icon icon
|
||||
{:color (get-icon-color danger?)
|
||||
:size 20}]]
|
||||
[rn/view
|
||||
{:style
|
||||
{:flex 1
|
||||
:justify-content :center}}
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color
|
||||
(when danger?
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60))}}
|
||||
label]
|
||||
(when sub-label
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style {:color
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
sub-label])]
|
||||
(when right-icon
|
||||
[rn/view {:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:width 20}}
|
||||
[icon/icon right-icon
|
||||
{:color (get-icon-color danger?)
|
||||
:size 20}]])]]))
|
||||
|
||||
(defn divider []
|
||||
[rn/view {:style {:border-top-width 1
|
||||
:border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
|
||||
:margin-top 8
|
||||
:margin-bottom 7
|
||||
:align-items :center
|
||||
:flex-direction :row}}])
|
||||
|
||||
(defn action-drawer [sections]
|
||||
[:<>
|
||||
(doall
|
||||
[:<> {:style
|
||||
{:flex 1}}
|
||||
(interpose
|
||||
[divider]
|
||||
(for [actions sections]
|
||||
(doall
|
||||
(map action actions))))])
|
||||
(map action actions)))])
|
||||
|
||||
@@ -138,13 +138,14 @@
|
||||
(fn [{:keys [left-accessories left-component border-bottom
|
||||
right-accessories right-component insets get-layout
|
||||
title subtitle title-component style title-align
|
||||
background]
|
||||
background header-style]
|
||||
:or {title-align :center
|
||||
border-bottom false}}]
|
||||
(let [status-bar-height (get insets :top 0)
|
||||
height (+ header-height status-bar-height)]
|
||||
[reanimated/view {:style (header-wrapper-style {:height height
|
||||
:background background
|
||||
:header-style header-style
|
||||
:border-bottom border-bottom})}
|
||||
[rn/view {:pointer-events :box-none
|
||||
:height status-bar-height}]
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
(ns quo2.components.icons.icons
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.string :as string]))
|
||||
[clojure.string :as cstr]))
|
||||
|
||||
(def icon-path "./resources/images/icons2/")
|
||||
|
||||
(defn combine-path [path el]
|
||||
(if (System/getenv "COMPONENT_TEST")
|
||||
(str "." path el "@2x.png")
|
||||
(str "." path el ".png")))
|
||||
|
||||
(defn require-icon [size path]
|
||||
(fn [el]
|
||||
(let [s (combine-path path el)
|
||||
(let [s (str "." path el ".png")
|
||||
k (-> el
|
||||
(string/replace "_" "-")
|
||||
(string/replace " " "-")
|
||||
(string/lower-case)
|
||||
(cstr/replace "_" "-")
|
||||
(cstr/replace " " "-")
|
||||
(cstr/lower-case)
|
||||
(str size))]
|
||||
[k `(js/require ~s)])))
|
||||
|
||||
(defn get-files [path]
|
||||
(->> (io/file path)
|
||||
file-seq
|
||||
(filter #(string/ends-with? % "png"))
|
||||
(map #(first (string/split (.getName %) #"@")))
|
||||
(filter #(cstr/ends-with? % "png"))
|
||||
(map #(first (cstr/split (.getName %) #"@")))
|
||||
distinct))
|
||||
|
||||
(defn get-icons [size]
|
||||
@@ -35,5 +30,4 @@
|
||||
(get-icons 12)
|
||||
(get-icons 16)
|
||||
(get-icons 20)
|
||||
(get-icons 24)
|
||||
(get-icons 32)))
|
||||
(get-icons 24)))
|
||||
|
||||
@@ -19,21 +19,19 @@
|
||||
(defn info-message
|
||||
"[info-message opts \"message\"]
|
||||
opts
|
||||
{:type :default/:success/:error
|
||||
:size :default/:tiny
|
||||
:icon :main-icons/info ;; info message icon
|
||||
:text-color colors/white ;; text color override
|
||||
:icon-color colors/white ;; icon color override
|
||||
:no-icon-color? false ;; disable tint color for icon"
|
||||
[{:keys [type size icon text-color icon-color no-icon-color?]} message]
|
||||
{:type :default/:success/:error
|
||||
:size :default/:tiny
|
||||
:icon :main-icons/info ;; info message icon
|
||||
:text-color colors/white ;; text color override
|
||||
:icon-color colors/white ;; icon color override"
|
||||
[{:keys [type size icon text-color icon-color]} message]
|
||||
(let [weight (if (= size :default) :regular :medium)
|
||||
size (if (= size :default) :paragraph-2 :label)
|
||||
text-color (or text-color (get-color type))
|
||||
icon-color (or icon-color text-color)]
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:flex 1}}
|
||||
[quo2.icons/icon icon {:color icon-color
|
||||
:no-color no-icon-color?
|
||||
[quo2.icons/icon icon {:color icon-color
|
||||
:size 12
|
||||
:container-style {:margin-top 3}}]
|
||||
[text/text {:size size
|
||||
|
||||
@@ -49,12 +49,11 @@
|
||||
:closed? true/false ;; information box's state
|
||||
:id :information-box-id ;; unique id (required for closable? information box)
|
||||
:icon :main-icons/info ;; information box icon
|
||||
:no-icon-color? false ;; disable tint color for icon
|
||||
:style style
|
||||
:button-label \"PressMe\" ;; add action button with label
|
||||
:on-button-press action ;; (required for information box with button-label)
|
||||
:on-close on-close ;; (optional on-close call)"
|
||||
[{:keys [type closable? closed? id icon style button-label on-button-press on-close no-icon-color?]} message]
|
||||
[{:keys [type closable? closed? id icon style button-label on-button-press on-close]} message]
|
||||
(let [background-color (get-color-by-type type :bg)
|
||||
border-color (get-color-by-type type :border)
|
||||
icon-color (get-color-by-type type :icon)
|
||||
@@ -74,8 +73,7 @@
|
||||
[info-message/info-message {:size :default
|
||||
:icon icon
|
||||
:text-color text-color
|
||||
:icon-color icon-color
|
||||
:no-icon-color? no-icon-color?} message]
|
||||
:icon-color icon-color} message]
|
||||
(when closable?
|
||||
[rn/touchable-opacity
|
||||
{:on-press on-close
|
||||
|
||||
@@ -1,57 +1,56 @@
|
||||
(ns quo2.components.list-items.channel
|
||||
(:require [quo2.components.avatars.channel-avatar :as channel-avatar]
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.counter.counter :as quo2.counter]
|
||||
[quo2.components.icon :as quo2.icons]
|
||||
[quo2.components.avatars.channel-avatar :as channel-avatar]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]))
|
||||
[quo2.theme :as theme]))
|
||||
|
||||
(defn list-item [{:keys [name locked? mentions-count unread-messages?
|
||||
muted? is-active-channel? emoji channel-color on-press]
|
||||
muted? is-active-channel? emoji channel-color]
|
||||
:or {channel-color colors/primary-50}}]
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[rn/view {:style (merge {:height 48
|
||||
:display :flex
|
||||
:border-radius 12
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:width "100%"
|
||||
:padding-left 12
|
||||
:padding-right 12}
|
||||
(when is-active-channel?
|
||||
{:background-color (colors/theme-alpha channel-color 0.05 0.05)}))}
|
||||
[rn/view {:display :flex
|
||||
:flex-direction :row
|
||||
:justify-content :flex-start
|
||||
:align-items :center}
|
||||
[channel-avatar/channel-avatar
|
||||
{:big? true
|
||||
:locked? locked?
|
||||
:emoji-background-color (colors/theme-alpha channel-color 0.1 0.1)
|
||||
:emoji emoji}]
|
||||
[quo2.text/text
|
||||
{:style (merge {:margin-left 12}
|
||||
(when (and (not locked?) muted?)
|
||||
{:color (if (theme/dark?) colors/neutral-60 colors/neutral-40)}))
|
||||
:weight :medium :size :paragraph-1} (str "# " name)]]
|
||||
[rn/view {:style {:height 20}}
|
||||
(when (and (not locked?)
|
||||
muted?)
|
||||
[quo2.icons/icon :i/muted
|
||||
{:size 20
|
||||
:no-color true}])
|
||||
(when (and (not locked?)
|
||||
(not muted?)
|
||||
(pos? (int mentions-count)))
|
||||
[rn/view {:style {:margin-right 2
|
||||
:margin-top 2}}
|
||||
[quo2.counter/counter {:override-bg-color channel-color} mentions-count]])
|
||||
(when (and (not locked?)
|
||||
(not muted?)
|
||||
(not (pos? (int mentions-count)))
|
||||
unread-messages?)
|
||||
[quo2.icons/icon :i/channel-notification
|
||||
{:size 20
|
||||
:no-color true}])]]])
|
||||
[rn/view {:style (merge {:height 48
|
||||
:display :flex
|
||||
:border-radius 12
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:width "100%"
|
||||
:padding-left 12
|
||||
:padding-right 12}
|
||||
(when is-active-channel?
|
||||
{:background-color (colors/theme-alpha channel-color 0.05 0.05)}))}
|
||||
[rn/view {:display :flex
|
||||
:flex-direction :row
|
||||
:justify-content :flex-start
|
||||
:align-items :center}
|
||||
[channel-avatar/channel-avatar
|
||||
{:big? true
|
||||
:locked? locked?
|
||||
:emoji-background-color (colors/theme-alpha channel-color 0.1 0.1)
|
||||
:emoji emoji}]
|
||||
[quo2.text/text
|
||||
{:style (merge {:margin-left 12}
|
||||
(when (and (not locked?) muted?)
|
||||
{:color (if (theme/dark?) colors/neutral-60 colors/neutral-40)}))
|
||||
:weight :medium :size :paragraph-1} (str "# " name)]]
|
||||
[rn/view {:style {:height 20}}
|
||||
(when (and (not locked?)
|
||||
muted?)
|
||||
[quo2.icons/icon :i/muted
|
||||
{:size 20
|
||||
:no-color true}])
|
||||
(when (and (not locked?)
|
||||
(not muted?)
|
||||
(pos? (int mentions-count)))
|
||||
[rn/view {:style {:margin-right 2
|
||||
:margin-top 2}}
|
||||
[quo2.counter/counter {:override-bg-color channel-color} mentions-count]])
|
||||
(when (and (not locked?)
|
||||
(not muted?)
|
||||
(not (pos? (int mentions-count)))
|
||||
unread-messages?)
|
||||
[quo2.icons/icon :i/channel-notification
|
||||
{:size 20
|
||||
:no-color true}])]])
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
(ns quo2.components.list-items.index
|
||||
(:require [quo.react-native :as rn]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn index [{:keys [title]}]
|
||||
[rn/view
|
||||
[rn/view {:style {:border-top-width 1
|
||||
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
|
||||
:padding-vertical 8
|
||||
:padding-horizontal 16}}
|
||||
[text/text {:weight :medium
|
||||
:size :paragraph-2
|
||||
:secondary-color (colors/theme-colors colors/neutral-50 colors/neutral-40)}
|
||||
title]]])
|
||||
@@ -0,0 +1,276 @@
|
||||
(ns quo2.components.list-items.list-item
|
||||
(:require [quo.react-native :as rn]
|
||||
[quo.platform :as platform]
|
||||
[quo.haptic :as haptic]
|
||||
[quo.gesture-handler :as gh]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[quo.design-system.colors :as quo.colors]
|
||||
[quo.components.controls.view :as controls]
|
||||
[quo.components.tooltip :as tooltip]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.icon :as quo2.icons]
|
||||
[quo.components.animated.pressable :as animated]))
|
||||
|
||||
(defn themes [theme]
|
||||
(case theme
|
||||
:main {:icon-color (:icon-04 @quo.colors/theme)
|
||||
:icon-bg-color (:interactive-02 @quo.colors/theme)
|
||||
:active-background (:interactive-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:text-01 @quo.colors/theme)}
|
||||
:accent {:icon-color (:icon-04 @quo.colors/theme)
|
||||
:icon-bg-color (:interactive-02 @quo.colors/theme)
|
||||
:active-background (:interactive-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:text-04 @quo.colors/theme)}
|
||||
:negative {:icon-color (:negative-01 @quo.colors/theme)
|
||||
:icon-bg-color (:negative-02 @quo.colors/theme)
|
||||
:active-background (:negative-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:negative-01 @quo.colors/theme)}
|
||||
:positive {:icon-color (:positive-01 @quo.colors/theme)
|
||||
:icon-bg-color (:positive-02 @quo.colors/theme)
|
||||
:active-background (:positive-02 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:positive-01 @quo.colors/theme)}
|
||||
:disabled {:icon-color (:icon-02 @quo.colors/theme)
|
||||
:icon-bg-color (:ui-01 @quo.colors/theme)
|
||||
:active-background (:ui-01 @quo.colors/theme)
|
||||
:passive-background (:ui-background @quo.colors/theme)
|
||||
:text-color (:text-02 @quo.colors/theme)}))
|
||||
|
||||
(defn size->icon-size [size]
|
||||
(case size
|
||||
:small 36
|
||||
40))
|
||||
|
||||
(defn size->container-size [size]
|
||||
(case size
|
||||
:small 52
|
||||
64))
|
||||
|
||||
(defn size->single-title-size [size]
|
||||
(case size
|
||||
:small :paragraph-1
|
||||
:paragraph-1))
|
||||
|
||||
(defn container [{:keys [size container-style container-padding-horizontal container-padding-vertical]} & children]
|
||||
(into [rn/view {:style (merge (or container-padding-horizontal (:tiny spacing/padding-horizontal))
|
||||
{:min-height (size->container-size size)
|
||||
:padding-vertical (or container-padding-vertical 8)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between} container-style)}]
|
||||
children))
|
||||
|
||||
(defn icon-column
|
||||
[{:keys [icon icon-bg-color icon-color size icon-container-style]}]
|
||||
(when icon
|
||||
(let [icon-size (size->icon-size size)]
|
||||
[rn/view {:style (or icon-container-style (:tiny spacing/padding-horizontal))}
|
||||
(cond
|
||||
(vector? icon)
|
||||
icon
|
||||
(keyword? icon)
|
||||
[rn/view {:style {:width icon-size
|
||||
:height icon-size
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius (/ icon-size 2)
|
||||
:background-color icon-bg-color}}
|
||||
(quo2.icons/icon icon {:color icon-color})])])))
|
||||
|
||||
(defn title-column
|
||||
[{:keys [title text-color subtitle subtitle-max-lines subtitle-secondary
|
||||
title-accessibility-label size text-size title-text-weight
|
||||
right-side-present? title-column-style]}]
|
||||
[rn/view {:style (or title-column-style
|
||||
(merge (:tiny spacing/padding-horizontal)
|
||||
;; make left-side title grow if nothing is present on right-side
|
||||
(when-not right-side-present?
|
||||
{:flex 1
|
||||
:justify-content :center})))}
|
||||
(cond
|
||||
|
||||
(and title subtitle)
|
||||
[:<>
|
||||
;; FIXME(Ferossgp): ReactNative 63 will support view inside text on andrid, remove thess if when migrating
|
||||
(if (string? title)
|
||||
[text/text {:weight (or title-text-weight :medium)
|
||||
:style {:color text-color}
|
||||
:accessibility-label title-accessibility-label
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:size text-size}
|
||||
title]
|
||||
title)
|
||||
(if (string? subtitle-secondary)
|
||||
[rn/view {:flex-direction :row}
|
||||
[text/text {:style {:max-width "56.5%"}
|
||||
:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :tail
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
subtitle]
|
||||
[text/text {:style {:width "7%" :text-align :center}
|
||||
:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :middle
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
"•"]
|
||||
[text/text {:style {:max-width "36.5%"}
|
||||
:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :middle
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
subtitle-secondary]]
|
||||
(if (string? subtitle)
|
||||
[text/text {:weight :regular
|
||||
:color :secondary
|
||||
:ellipsize-mode :tail
|
||||
:secondary-color colors/neutral-50
|
||||
:number-of-lines subtitle-max-lines
|
||||
:size text-size}
|
||||
subtitle]
|
||||
subtitle))]
|
||||
|
||||
title
|
||||
(if (string? title)
|
||||
[text/text {:weight (or title-text-weight :regular)
|
||||
:number-of-lines 1
|
||||
:style {:color text-color}
|
||||
:title-accessibility-label title-accessibility-label
|
||||
:ellipsize-mode :tail
|
||||
:size (or text-size (size->single-title-size size))}
|
||||
title]
|
||||
title))])
|
||||
|
||||
(defn left-side [props]
|
||||
[rn/view {:style {:flex-direction :row
|
||||
;; Occupy only content width, never grow, but shrink if need be
|
||||
:flex-grow 0
|
||||
:flex-shrink 1
|
||||
:padding-right 16
|
||||
:align-items (or (:left-side-alignment props) :center)}}
|
||||
[icon-column props]
|
||||
[title-column props]])
|
||||
|
||||
(defn right-side [{:keys [chevron active disabled accessory accessory-text accessory-style animated-accessory?]}]
|
||||
(when (or chevron accessory)
|
||||
[rn/view {:style (merge {:align-items :center
|
||||
:justify-content :flex-end
|
||||
:flex-direction :row
|
||||
;; Grow to occupy full space, shrink when need be, but always maitaining 16px left gutter
|
||||
:flex-grow 1
|
||||
:flex-shrink 0
|
||||
:margin-left 16
|
||||
;; When the left-side leaves no room for right-side, the rendered element is pushed out. A flex-basis ensures that there is some room reserved.
|
||||
;; The number 80px was determined by trial and error.
|
||||
:flex-basis 80}
|
||||
accessory-style)}
|
||||
[rn/view {:style (:tiny spacing/padding-horizontal)}
|
||||
(case accessory
|
||||
:radio [controls/radio {:value active :disabled disabled}]
|
||||
:checkbox [(if animated-accessory?
|
||||
controls/animated-checkbox
|
||||
controls/checkbox)
|
||||
{:value active :disabled disabled}]
|
||||
:switch [controls/switch {:value active :disabled disabled}]
|
||||
:text [text/text {:color :secondary
|
||||
:ellipsize-mode :middle
|
||||
:number-of-lines 1}
|
||||
accessory-text]
|
||||
accessory)]
|
||||
(when (and chevron platform/ios?)
|
||||
[rn/view {:style {:padding-right (:tiny spacing/spacing)}}
|
||||
(quo2.icons/icon :main-icons/next {:container-style {:opacity 0.4
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
:resize-mode :center
|
||||
:color (:icon-02 @quo.colors/theme)})])]))
|
||||
|
||||
(defn list-item
|
||||
[{:keys [theme accessory disabled subtitle-max-lines icon icon-container-style
|
||||
left-side-alignment icon-color icon-bg-color title-column-style
|
||||
title subtitle subtitle-secondary active on-press on-long-press chevron size text-size
|
||||
accessory-text accessibility-label title-accessibility-label accessory-style
|
||||
haptic-feedback text-color active-background passive-background haptic-type error animated animated-accessory? title-text-weight container-style
|
||||
active-background-enabled background-color container-padding-horizontal container-padding-vertical]
|
||||
:or {subtitle-max-lines 1
|
||||
theme :main
|
||||
haptic-feedback true
|
||||
animated platform/ios?
|
||||
active-background-enabled true
|
||||
haptic-type :selection}}]
|
||||
(let [theme (if disabled :disabled theme)
|
||||
icon-color (or icon-color (:icon-color (themes theme)))
|
||||
icon-bg-color (or icon-bg-color (:icon-bg-color (themes theme)))
|
||||
optional-haptic (fn []
|
||||
(when haptic-feedback
|
||||
(haptic/trigger haptic-type)))
|
||||
component (cond
|
||||
(and (not on-press)
|
||||
(not on-long-press))
|
||||
rn/view
|
||||
animated animated/pressable
|
||||
:else gh/touchable-highlight)]
|
||||
[rn/view {:background-color (cond (not= background-color nil)
|
||||
background-color
|
||||
(and (= accessory :radio) active)
|
||||
active-background
|
||||
:else
|
||||
passive-background)}
|
||||
[component
|
||||
(merge {:type :list-item
|
||||
:disabled disabled
|
||||
:bg-color (when active-background-enabled active-background)
|
||||
:accessibility-label accessibility-label}
|
||||
(when on-press
|
||||
{:on-press (fn []
|
||||
(optional-haptic)
|
||||
(on-press))})
|
||||
(when on-long-press
|
||||
{:on-long-press (fn []
|
||||
(optional-haptic)
|
||||
(on-long-press))}))
|
||||
[container {:size size :container-style container-style :container-padding-vertical container-padding-vertical :container-padding-horizontal container-padding-horizontal}
|
||||
[left-side {:icon-color icon-color
|
||||
:text-color (if on-press
|
||||
text-color
|
||||
(:text-color (themes :main)))
|
||||
:left-side-alignment left-side-alignment
|
||||
:icon-bg-color icon-bg-color
|
||||
:title-accessibility-label title-accessibility-label
|
||||
:icon icon
|
||||
:icon-container-style icon-container-style
|
||||
:title title
|
||||
:title-text-weight title-text-weight
|
||||
:size size
|
||||
:text-size text-size
|
||||
:subtitle subtitle
|
||||
:subtitle-max-lines subtitle-max-lines
|
||||
:subtitle-secondary subtitle-secondary
|
||||
:right-side-present? (or accessory chevron)
|
||||
:title-column-style title-column-style}]
|
||||
[right-side {:chevron chevron
|
||||
:active active
|
||||
:disabled disabled
|
||||
:on-press on-press
|
||||
:accessory-text accessory-text
|
||||
:animated-accessory? animated-accessory?
|
||||
:accessory-style accessory-style
|
||||
:accessory accessory}]]]
|
||||
(when error
|
||||
[tooltip/tooltip (merge {:bottom-value 0}
|
||||
(when accessibility-label
|
||||
{:accessibility-label (str (name accessibility-label) "-error")}))
|
||||
[text/text {:color :negative
|
||||
:size :small}
|
||||
error]])]))
|
||||
@@ -1,77 +0,0 @@
|
||||
(ns quo2.components.loaders.skeleton
|
||||
(:require [react-native.core :as rn]
|
||||
[react-native.masked-view :as masked-view]
|
||||
[reagent.core :as reagent]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(def message-skeleton-height 54)
|
||||
|
||||
(def avatar-skeleton-size 32)
|
||||
|
||||
(def message-content-width [{:author 80
|
||||
:message 249}
|
||||
{:author 124
|
||||
:message 156}
|
||||
{:author 96
|
||||
:message 212}
|
||||
{:author 112
|
||||
:message 144}])
|
||||
|
||||
;; Standlone message skeleton
|
||||
(defn message-skeleton []
|
||||
[:f>
|
||||
(fn []
|
||||
(let [color (colors/theme-colors colors/neutral-5 colors/neutral-70)
|
||||
loading-color (colors/theme-colors colors/neutral-10 colors/neutral-60)
|
||||
content-width (rand-nth message-content-width)
|
||||
author-width (content-width :author)
|
||||
message-width (content-width :message)
|
||||
{window-width :width} (rn/use-window-dimensions)
|
||||
translate-x (reanimated/use-shared-value (- window-width))
|
||||
animated-gradient-style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateX translate-x}]}
|
||||
{:width window-width
|
||||
:height "100%"})]
|
||||
(reanimated/animate-shared-value-with-repeat translate-x window-width 1000 :linear (- 1) false)
|
||||
[masked-view/masked-view
|
||||
{:style {:height message-skeleton-height}
|
||||
:maskElement (reagent/as-element
|
||||
[rn/view {:style {:height message-skeleton-height
|
||||
:flex-direction :row
|
||||
:padding-vertical 11
|
||||
:background-color :transparent
|
||||
:padding-left 21}}
|
||||
[rn/view {:style {:height avatar-skeleton-size
|
||||
:width avatar-skeleton-size
|
||||
:border-radius (/ avatar-skeleton-size 2)
|
||||
:background-color color
|
||||
:overflow :hidden}}]
|
||||
[rn/view {:style {:padding-left 8
|
||||
:background-color :transparent}}
|
||||
[rn/view {:style {:height 8
|
||||
:width author-width
|
||||
:border-radius 6
|
||||
:background-color color
|
||||
:margin-bottom 8
|
||||
:overflow :hidden}}]
|
||||
[rn/view {:style {:height 16
|
||||
:width message-width
|
||||
:border-radius 6
|
||||
:overflow :hidden
|
||||
:background-color color}}]]])}
|
||||
[rn/view {:style {:flex 1
|
||||
:background-color color}}
|
||||
[reanimated/linear-gradient {:colors [color color loading-color color color]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 1 :y 0}
|
||||
:style animated-gradient-style}]]]))])
|
||||
|
||||
(defn skeleton [parent-height]
|
||||
(let [number-of-skeletons (int (Math/floor (/ parent-height message-skeleton-height)))]
|
||||
[rn/view {:style {:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)
|
||||
:flex 1}}
|
||||
(for [n (range number-of-skeletons)]
|
||||
[message-skeleton {:key n}])]))
|
||||
@@ -1,11 +1,10 @@
|
||||
(ns quo2.components.markdown.text
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.theme :as theme]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn text-style [{:keys [size align weight style]}]
|
||||
(defn text-style [{:keys [size align weight style secondary-color]}]
|
||||
(merge (case (or weight :regular)
|
||||
:regular typography/font-regular
|
||||
:medium typography/font-medium
|
||||
@@ -24,7 +23,8 @@
|
||||
{:text-align (or align :auto)}
|
||||
(if (:color style)
|
||||
style
|
||||
(assoc style :color (if (= (theme/get-theme) :dark) colors/white colors/neutral-100)))))
|
||||
(assoc style :color (or secondary-color
|
||||
(colors/theme-colors colors/neutral-100 colors/white))))))
|
||||
|
||||
(defn text []
|
||||
(let [this (reagent/current-component)
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
(ns quo2.components.markdown.text-input
|
||||
(:require [clojure.spec.alpha :as s]
|
||||
[reagent.core :as reagent]
|
||||
[oops.core :refer [ocall]]
|
||||
[quo.react-native :as rn]
|
||||
;; TODO(Ferossgp): Move icon component to lib
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[quo.components.tooltip :as tooltip]
|
||||
[quo.platform :as platform]
|
||||
[quo.design-system.typography :as typography]
|
||||
[quo.design-system.spacing :as spacing]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.components.text :as text]))
|
||||
|
||||
;; NOTE(Ferossgp): Refactor with hooks when available
|
||||
;; We track all currently mounted text input refs
|
||||
;; in a ref-to-defaultValue map
|
||||
;; so that we can clear them (restore their default values)
|
||||
;; when global react-navigation's onWillBlur event is invoked
|
||||
(defonce text-input-refs (atom {}))
|
||||
|
||||
(s/def ::multiline boolean?)
|
||||
(s/def ::secure-text-entry boolean?)
|
||||
(s/def ::show-cancel boolean?)
|
||||
(s/def ::label (s/nilable (s/or :string string? :component vector?)))
|
||||
(s/def ::cancel-label (s/nilable string?))
|
||||
(s/def ::default-value (s/nilable string?))
|
||||
(s/def ::placeholder (s/nilable string?))
|
||||
(s/def ::keyboard-type (s/nilable (s/or :string string? :keyword keyword?))) ; TODO: make set
|
||||
(s/def ::accessibility-label (s/nilable (s/or :string string? :keyword keyword?)))
|
||||
(s/def ::on-focus fn?)
|
||||
(s/def ::on-blur fn?)
|
||||
(s/def ::on-press fn?)
|
||||
|
||||
(s/def ::accessory (s/keys :opt-un [::on-press
|
||||
::icon
|
||||
::component]))
|
||||
(s/def ::after (s/nilable ::accessory))
|
||||
(s/def ::before (s/nilable ::accessory))
|
||||
|
||||
(s/def ::style (s/nilable map?))
|
||||
(s/def ::input-style ::style)
|
||||
(s/def ::container-style ::style)
|
||||
|
||||
(s/def ::text-input (s/keys :opt-un
|
||||
[::label
|
||||
::multiline
|
||||
::error
|
||||
::style
|
||||
::input-style
|
||||
::keyboard-type
|
||||
::before
|
||||
::after
|
||||
::cancel-label
|
||||
::on-focus
|
||||
::on-blur
|
||||
::container-style
|
||||
::show-cancel
|
||||
::accessibility-label
|
||||
::bottom-value
|
||||
::secure-text-entry]))
|
||||
|
||||
(defn check-spec [spec prop]
|
||||
(if (s/valid? spec prop)
|
||||
true
|
||||
(do
|
||||
(s/explain spec prop)
|
||||
false)))
|
||||
|
||||
(def height 44) ; 22 line-height + 11*2 vertical padding
|
||||
(def multiline-height 88) ; 3 * 22 three line-height + 11* vertical padding
|
||||
|
||||
(defn label-style []
|
||||
{:margin-bottom (:tiny spacing/spacing)})
|
||||
|
||||
(defn text-input-row-style []
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(defn text-input-view-style [style]
|
||||
(merge {:border-radius 8
|
||||
:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center
|
||||
:background-color (:ui-01 @colors/theme)}
|
||||
style))
|
||||
|
||||
(defn text-input-style [multiline input-style monospace before after]
|
||||
(merge (if monospace
|
||||
typography/monospace
|
||||
typography/font-regular)
|
||||
{:padding-top 11
|
||||
:padding-bottom 11
|
||||
:font-size 15
|
||||
:margin 0
|
||||
:text-align-vertical :center
|
||||
:flex 1
|
||||
:color (:text-01 @colors/theme)
|
||||
:height height}
|
||||
(when-not before
|
||||
{:padding-left (:base spacing/spacing)})
|
||||
(when-not after
|
||||
{:padding-right (:base spacing/spacing)})
|
||||
(when multiline
|
||||
{:text-align-vertical :top
|
||||
:line-height 22
|
||||
:height multiline-height})
|
||||
input-style))
|
||||
|
||||
(defn cancel-style []
|
||||
{:margin-left (:tiny spacing/spacing)
|
||||
:padding-left (:tiny spacing/spacing)
|
||||
:justify-content :center
|
||||
:align-self :stretch})
|
||||
|
||||
(defn accessory-style []
|
||||
(merge (:base spacing/padding-horizontal)
|
||||
{:flex 1
|
||||
:justify-content :center}))
|
||||
|
||||
(defn accessory-element [{:keys [icon component icon-opts style accessibility-label on-press]}]
|
||||
(let [el (if on-press
|
||||
rn/touchable-opacity
|
||||
rn/view)]
|
||||
[el (merge {:style {:align-self :stretch}}
|
||||
(when on-press
|
||||
{:on-press on-press}))
|
||||
[rn/view (merge {:style (merge (accessory-style)
|
||||
style)}
|
||||
(when accessibility-label
|
||||
{:accessibility-label accessibility-label}))
|
||||
(cond
|
||||
icon
|
||||
[icons/icon icon (merge {:color (:icon-01 @colors/theme)}
|
||||
icon-opts)]
|
||||
component
|
||||
component
|
||||
|
||||
:else
|
||||
nil)]]))
|
||||
|
||||
(defn text-input-raw []
|
||||
(let [focused (reagent/atom nil)
|
||||
visible (reagent/atom false)
|
||||
ref (atom nil)
|
||||
blur (fn []
|
||||
(some-> @ref (ocall "blur")))]
|
||||
(fn [{:keys [label multiline error style input-style keyboard-type before after
|
||||
cancel-label on-focus on-blur show-cancel accessibility-label
|
||||
bottom-value secure-text-entry container-style get-ref on-cancel
|
||||
monospace auto-complete-type auto-correct]
|
||||
:or {cancel-label "Cancel"}
|
||||
:as props}]
|
||||
{:pre [(check-spec ::text-input props)]}
|
||||
(let [show-cancel (if (nil? show-cancel)
|
||||
;; Enabled by default on iOs and disabled on Android
|
||||
platform/ios?
|
||||
show-cancel)
|
||||
after (cond
|
||||
(and secure-text-entry @visible)
|
||||
{:icon :main-icons/hide
|
||||
:on-press #(reset! visible false)}
|
||||
|
||||
(and secure-text-entry (not @visible))
|
||||
{:icon :main-icons/show
|
||||
:on-press #(reset! visible true)}
|
||||
|
||||
:else after)
|
||||
secure (boolean (and secure-text-entry (not @visible))) ; must be a boolean to work on iOS
|
||||
auto-complete (cond
|
||||
(= keyboard-type :visible-password)
|
||||
:off
|
||||
|
||||
secure-text-entry
|
||||
:password
|
||||
|
||||
:else
|
||||
auto-complete-type)
|
||||
auto-correct (and (not= keyboard-type :visible-password) (not secure-text-entry) auto-correct)
|
||||
on-cancel (fn []
|
||||
(when on-cancel
|
||||
(on-cancel))
|
||||
(blur))
|
||||
keyboard-type (cond
|
||||
(and platform/ios? (= keyboard-type :visible-password))
|
||||
:default
|
||||
|
||||
; the correct approach on Android would be keep secure-text-entry on set keyboard type
|
||||
; to visible-password. But until https://github.com/facebook/react-native/issues/27946
|
||||
; is solved that's the second best way.
|
||||
(and platform/android? secure-text-entry)
|
||||
:default
|
||||
|
||||
:else
|
||||
keyboard-type)]
|
||||
[rn/view {:style container-style}
|
||||
(when label
|
||||
[text/text {:style (label-style)}
|
||||
label])
|
||||
[rn/view {:style (text-input-row-style)}
|
||||
[rn/view {:style (text-input-view-style style)
|
||||
:important-for-accessibility (if secure-text-entry
|
||||
:no-hide-descendants
|
||||
:auto)}
|
||||
(when before
|
||||
[accessory-element before])
|
||||
[rn/text-input
|
||||
(merge {:style (text-input-style multiline input-style monospace before after)
|
||||
:ref (fn [r]
|
||||
(reset! ref r)
|
||||
(when get-ref (get-ref r)))
|
||||
:placeholder-text-color (:text-02 @colors/theme)
|
||||
:underline-color-android :transparent
|
||||
:auto-capitalize :none
|
||||
:secure-text-entry secure
|
||||
:auto-correct auto-correct
|
||||
:auto-complete-type auto-complete
|
||||
:on-focus (fn [evt]
|
||||
(when on-focus (on-focus evt))
|
||||
(when show-cancel
|
||||
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets)))
|
||||
(reset! focused true))
|
||||
:on-blur (fn [evt]
|
||||
(when on-blur (on-blur evt))
|
||||
(when show-cancel
|
||||
(rn/configure-next (:ease-in-ease-out rn/layout-animation-presets)))
|
||||
(reset! focused false))
|
||||
:keyboard-type keyboard-type}
|
||||
(when (and platform/ios? (not after))
|
||||
{:clear-button-mode :while-editing})
|
||||
(dissoc props
|
||||
:style :keyboard-type :on-focus :on-blur
|
||||
:secure-text-entry :ref :get-ref :auto-correct :auto-complete-type))]
|
||||
(when after
|
||||
[accessory-element after])]
|
||||
(when (and show-cancel
|
||||
(not multiline)
|
||||
@focused)
|
||||
[rn/touchable-opacity {:style (cancel-style)
|
||||
:on-press on-cancel}
|
||||
[text/text {:color :link} cancel-label]])
|
||||
(when error
|
||||
[tooltip/tooltip (merge {:bottom-value (if bottom-value bottom-value 0)}
|
||||
(when accessibility-label
|
||||
{:accessibility-label (str (name accessibility-label) "-error")}))
|
||||
[text/text {:color :negative
|
||||
:align :center
|
||||
:size :small}
|
||||
error]])]]))))
|
||||
|
||||
;; TODO(Ferossgp): Refactor me when hooks available
|
||||
(defn text-input [{:keys [preserve-input?]
|
||||
:as props}]
|
||||
(if preserve-input?
|
||||
[text-input-raw props]
|
||||
(let [id (random-uuid)]
|
||||
(reagent/create-class
|
||||
{:component-will-unmount
|
||||
(fn []
|
||||
(swap! text-input-refs dissoc id))
|
||||
:reagent-render
|
||||
(fn [{:keys [get-ref default-value]
|
||||
:as props}]
|
||||
[text-input-raw (merge props
|
||||
{:get-ref (fn [r]
|
||||
;; Store input and its defaultValue
|
||||
;; one we receive a non-nil ref
|
||||
(when r
|
||||
(swap! text-input-refs assoc id {:ref r :value default-value}))
|
||||
(when get-ref (get-ref r)))})])}))))
|
||||
@@ -1,39 +0,0 @@
|
||||
(ns quo2.components.messages.author.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:flex 1
|
||||
:flex-wrap :wrap
|
||||
:height 18
|
||||
:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(defn ens-text []
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white)})
|
||||
|
||||
(defn nickname-text []
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white)})
|
||||
|
||||
(def middle-dot-nickname
|
||||
{:color colors/neutral-50
|
||||
:margin-horizontal 4})
|
||||
|
||||
(def chat-key-text
|
||||
{:color colors/neutral-50
|
||||
:margin-left 8})
|
||||
|
||||
(def middle-dot-chat-key
|
||||
{:color colors/neutral-50
|
||||
:margin-left 4})
|
||||
|
||||
(defn profile-name-text [nickname?]
|
||||
{:color (if nickname?
|
||||
(colors/theme-colors colors/neutral-60 colors/neutral-40)
|
||||
(colors/theme-colors colors/neutral-100 colors/white))})
|
||||
|
||||
(def icon-container
|
||||
{:margin-left 4})
|
||||
|
||||
(defn time-text [ens?]
|
||||
{:color colors/neutral-50
|
||||
:margin-left (if ens? 8 4)})
|
||||
@@ -1,88 +0,0 @@
|
||||
(ns quo2.components.messages.author.view
|
||||
(:require
|
||||
[quo2.components.messages.author.style :as style]
|
||||
[react-native.core :as rn]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.icon :as icons]
|
||||
[status-im.utils.utils :as utils]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(def middle-dot "·")
|
||||
|
||||
(defn display-name [{:keys [profile-name nickname ens-name text-style]}]
|
||||
(let [ens? (-> ens-name string/blank? not)
|
||||
nickname? (-> nickname string/blank? not)]
|
||||
(if ens?
|
||||
[text/text (merge {:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
:style (style/ens-text)}
|
||||
text-style)
|
||||
ens-name]
|
||||
[:<>
|
||||
(if nickname?
|
||||
[text/text (merge {:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
:style (style/nickname-text)}
|
||||
text-style)
|
||||
nickname]
|
||||
[text/text (merge {:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
:style (style/profile-name-text nickname?)}
|
||||
text-style)
|
||||
profile-name])])))
|
||||
|
||||
(defn author [{:keys [profile-name nickname chat-key ens-name time-str contact? verified? untrustworthy?]}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [ens? (-> ens-name string/blank? not)
|
||||
nickname? (-> nickname string/blank? not)]
|
||||
[rn/view {:style style/container}
|
||||
(if ens?
|
||||
[text/text {:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
:style (style/ens-text)}
|
||||
ens-name]
|
||||
[:<>
|
||||
(when nickname?
|
||||
[:<>
|
||||
[text/text {:weight :semi-bold
|
||||
:size :paragraph-2
|
||||
:style (style/nickname-text)}
|
||||
nickname]
|
||||
[text/text {:size :paragraph-2
|
||||
:style style/middle-dot-nickname}
|
||||
middle-dot]])
|
||||
[text/text {:weight (if nickname? :medium :semi-bold)
|
||||
:size :paragraph-2
|
||||
:style (style/profile-name-text nickname?)}
|
||||
profile-name]])
|
||||
(when contact?
|
||||
[icons/icon :main-icons2/contact
|
||||
{:size 12
|
||||
:no-color true
|
||||
:container-style style/icon-container}])
|
||||
(cond
|
||||
verified?
|
||||
[icons/icon :main-icons2/verified
|
||||
{:size 12
|
||||
:no-color true
|
||||
:container-style style/icon-container}]
|
||||
untrustworthy?
|
||||
[icons/icon :main-icons2/untrustworthy
|
||||
{:size 12
|
||||
:no-color true
|
||||
:container-style style/icon-container}])
|
||||
(when-not ens?
|
||||
[text/text {:monospace true
|
||||
:size :paragraph-2
|
||||
:style style/chat-key-text}
|
||||
(utils/get-shortened-address chat-key)])
|
||||
(when-not ens?
|
||||
[text/text {:monospace true
|
||||
:size :paragraph-2
|
||||
:style style/middle-dot-chat-key}
|
||||
middle-dot])
|
||||
[text/text {:monospace true
|
||||
:size :paragraph-2
|
||||
:style (style/time-text ens?)}
|
||||
time-str]]))])
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns quo2.components.messages.system-message
|
||||
(:require [quo2.components.avatars.icon-avatar :as icon-avatar]
|
||||
(:require [react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[quo2.theme :as theme]
|
||||
[quo2.components.avatars.icon-avatar :as icon-avatar]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[utils.string :as utils]))
|
||||
[utils :as utils]))
|
||||
|
||||
(def themes-landed {:pinned colors/primary-50-opa-5
|
||||
:added colors/primary-50-opa-5
|
||||
@@ -60,19 +60,19 @@
|
||||
:flex-direction :row}
|
||||
[rn/view {:align-items :center
|
||||
:flex-direction :row}
|
||||
[sm-icon {:icon :main-icons/delete
|
||||
[sm-icon {:icon :main-icons/delete16
|
||||
:color :danger
|
||||
:opacity 5}]
|
||||
[text/text {:size :paragraph-2
|
||||
:style {:color (get-color :text)
|
||||
:margin-right 5}}
|
||||
(or (get labels label) label (:message-deleted labels))]
|
||||
(or label (:message-deleted labels))]
|
||||
[sm-timestamp timestamp-str]]])
|
||||
|
||||
(defmethod sm-render :added [{:keys [state mentions timestamp-str labels]}]
|
||||
[rn/view {:align-items :center
|
||||
:flex-direction :row}
|
||||
[sm-icon {:icon :main-icons/add-user
|
||||
[sm-icon {:icon :main-icons/add-user16
|
||||
:color :primary
|
||||
:opacity (if (= state :landed) 0 5)}]
|
||||
[sm-user-avatar (:image (first mentions))]
|
||||
@@ -94,7 +94,7 @@
|
||||
[rn/view {:flex-direction :row
|
||||
:flex 1
|
||||
:align-items :center}
|
||||
[sm-icon {:icon :main-icons/pin
|
||||
[sm-icon {:icon :main-icons/pin16
|
||||
:color :primary
|
||||
:opacity (if (= state :landed) 0 5)}]
|
||||
[rn/view {:flex-direction :column
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
:icon-color-anim reanimated shared value
|
||||
"
|
||||
[{:keys [icon new-notifications? notification-indicator counter-label
|
||||
on-press pass-through? icon-color-anim accessibility-label test-ID]}]
|
||||
on-press pass-through? icon-color-anim accessibility-label]}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [icon-animated-style (reanimated/apply-animations-to-style
|
||||
@@ -40,8 +40,7 @@
|
||||
:height 40
|
||||
:border-radius 10})]
|
||||
[rn/touchable-without-feedback
|
||||
{:test-ID test-ID
|
||||
:on-press on-press
|
||||
{:on-press on-press
|
||||
:on-press-in #(toggle-background-color background-color false pass-through?)
|
||||
:on-press-out #(toggle-background-color background-color true pass-through?)
|
||||
:accessibility-label accessibility-label}
|
||||
|
||||
@@ -14,35 +14,31 @@
|
||||
:customization-color customization-color}]))
|
||||
|
||||
(defn floating-shell-button
|
||||
"[floating-shell-button dynamic-buttons style opacity-anim pointer-anim]
|
||||
dynamic-buttons {:button-type {:on-press on-press :count count}}
|
||||
style override style
|
||||
opacity-anim reanimated value (optional)"
|
||||
([dynamic-button style]
|
||||
(floating-shell-button dynamic-button style nil))
|
||||
([dynamic-buttons style opacity-anim]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [original-style (merge {:flex-direction :row
|
||||
:margin-horizontal 12
|
||||
:pointer-events :box-none} style)
|
||||
animated-style (reanimated/apply-animations-to-style
|
||||
(if opacity-anim
|
||||
{:opacity opacity-anim} {})
|
||||
original-style)]
|
||||
[reanimated/view {:style animated-style}
|
||||
;; Left Section
|
||||
[rn/view {:style {:flex 1}}
|
||||
[dynamic-button-view :search dynamic-buttons {:position :absolute
|
||||
:right 8}]]
|
||||
;; Mid Section (jump-to)
|
||||
[dynamic-button-view :jump-to dynamic-buttons nil]
|
||||
"[floating-shell-button dynamic-buttons style]
|
||||
dynamic-buttons
|
||||
{:button-type {:on-press on-press :count count}}"
|
||||
[dynamic-buttons style opacity-anim pointer-anim]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [original-style (merge {:flex-direction :row
|
||||
:margin-horizontal 12} style)
|
||||
animated-style (reanimated/apply-animations-to-style
|
||||
{:opacity opacity-anim
|
||||
:pointer-events pointer-anim}
|
||||
original-style)]
|
||||
[reanimated/view {:style animated-style}
|
||||
;; Left Section
|
||||
[rn/view {:style {:flex 1}}
|
||||
[dynamic-button-view :search dynamic-buttons {:position :absolute
|
||||
:right 8}]]
|
||||
;; Mid Section (jump-to)
|
||||
[dynamic-button-view :jump-to dynamic-buttons nil]
|
||||
;; Right Section
|
||||
[rn/view {:style {:flex 1}}
|
||||
[rn/view {:style {:position :absolute
|
||||
:flex-direction :row
|
||||
:right 0}}
|
||||
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
|
||||
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
|
||||
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
|
||||
[dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))]))
|
||||
[rn/view {:style {:flex 1}}
|
||||
[rn/view {:style {:position :absolute
|
||||
:flex-direction :row
|
||||
:right 0}}
|
||||
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
|
||||
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
|
||||
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
|
||||
[dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))])
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[clojure.string :as string]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]))
|
||||
[clojure.string :as string]))
|
||||
|
||||
(def ^:private centrify-style
|
||||
{:display :flex
|
||||
@@ -14,10 +12,12 @@
|
||||
|
||||
(def ^:private align-left (assoc centrify-style :align-items :flex-start))
|
||||
|
||||
(def ^:private icon-styles (assoc centrify-style :width 32 :height 32 :border-radius 10))
|
||||
|
||||
(defn- big? [size] (= size :big))
|
||||
|
||||
(defn- icon-props [color size]
|
||||
(merge {:size 20
|
||||
(merge {:size 20
|
||||
:container-style {:width (if (big? size)
|
||||
20
|
||||
16)
|
||||
@@ -28,35 +28,34 @@
|
||||
{:color color}
|
||||
{:no-color true})))
|
||||
|
||||
(defn left-section-view [{:keys [on-press icon accessibility-label type] :or {type :grey}}
|
||||
put-middle-section-on-left?]
|
||||
[rn/view {:style (when put-middle-section-on-left? {:margin-right 5})}
|
||||
[button/button {:on-press on-press
|
||||
:icon true
|
||||
:type type
|
||||
:size 32
|
||||
:accessibility-label accessibility-label}
|
||||
icon]])
|
||||
(defn render-left-section [{:keys [on-press icon
|
||||
icon-color icon-background-color]}
|
||||
put-middle-section-on-left?]
|
||||
[rn/view {:style (merge
|
||||
icon-styles
|
||||
{:background-color icon-background-color
|
||||
:width 32
|
||||
:height 32}
|
||||
(when put-middle-section-on-left? {:margin-right 5}))}
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[icons/icon icon (icon-props icon-color :big)]]])
|
||||
|
||||
(defn- mid-section-comp
|
||||
[{:keys [description-img description-user-icon horizontal-description?
|
||||
text-secondary-color align-mid? text-color icon main-text type description]}]
|
||||
[rn/view {:style (assoc centrify-style
|
||||
:flex-direction :row
|
||||
:margin-horizontal 2)}
|
||||
[{:keys [description-user-icon horizontal-description? text-secondary-color align-mid? text-color icon main-text type description]}]
|
||||
[rn/view {:style (assoc
|
||||
centrify-style
|
||||
:flex-direction :row
|
||||
:margin-horizontal 2)}
|
||||
(when (or (and (not horizontal-description?)
|
||||
align-mid?
|
||||
(not= :text-with-description type))
|
||||
(and (or description-img description-user-icon)
|
||||
(and description-user-icon
|
||||
(not icon)))
|
||||
(if description-img
|
||||
[rn/view {:margin-right 8}
|
||||
[description-img]]
|
||||
[rn/image {:source {:uri description-user-icon}
|
||||
:style {:width 32
|
||||
:height 32
|
||||
:border-radius 32
|
||||
:margin-right 8}}]))
|
||||
[rn/image {:source {:uri description-user-icon}
|
||||
:style {:width 32
|
||||
:height 32
|
||||
:border-radius 32
|
||||
:margin-right 8}}])
|
||||
[rn/view {:style {:flex-direction (if horizontal-description?
|
||||
:row
|
||||
:column)}}
|
||||
@@ -74,69 +73,76 @@
|
||||
horizontal-description? (assoc :margin-left 4 :margin-top 2))}
|
||||
description])]])
|
||||
|
||||
(defn- mid-section-view
|
||||
(defn- render-mid-section
|
||||
[{:keys [horizontal-description? one-icon-align-left? type left-align?
|
||||
main-text right-icon main-text-icon-color left-icon on-press avatar] :as props}]
|
||||
(let [text-color (if (colors/dark?) colors/neutral-5 colors/neutral-95)
|
||||
text-secondary-color (if (colors/dark?) colors/neutral-40 colors/neutral-50)
|
||||
main-text right-icon main-text-icon-color left-icon] :as props}]
|
||||
(let [text-color (if (colors/dark?) colors/neutral-5 colors/neutral-95)
|
||||
text-secondary-color (if (colors/dark?) colors/neutral-40 colors/neutral-50)
|
||||
component-instance [mid-section-comp (assoc props :text-secondary-color text-secondary-color)]]
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[rn/view {:style (merge
|
||||
(if left-align?
|
||||
align-left
|
||||
centrify-style)
|
||||
{:flex 1
|
||||
:margin-left 4
|
||||
:text-align-vertical :center})}
|
||||
(case type
|
||||
:text-only [text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:color text-color}}
|
||||
main-text]
|
||||
:user-avatar [rn/view {:style (assoc centrify-style :flex-direction :row)}
|
||||
[user-avatar/user-avatar avatar]
|
||||
[text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:padding-horizontal 4
|
||||
:color text-color}}
|
||||
main-text]]
|
||||
:text-with-two-icons [rn/view {:style (assoc centrify-style :flex-direction :row)}
|
||||
[icons/icon left-icon
|
||||
(icon-props main-text-icon-color :big)]
|
||||
[text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:padding-horizontal 4
|
||||
:color text-color}}
|
||||
main-text]
|
||||
[icons/icon right-icon
|
||||
(icon-props main-text-icon-color :big)]]
|
||||
:text-with-one-icon [rn/view {:style {:flex-direction :row}}
|
||||
(if one-icon-align-left?
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
(when horizontal-description?
|
||||
[icons/icon left-icon
|
||||
(icon-props main-text-icon-color :big)])
|
||||
component-instance]
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
component-instance
|
||||
(when horizontal-description?
|
||||
[icons/icon left-icon
|
||||
(icon-props main-text-icon-color :big)])])]
|
||||
:text-with-description component-instance)]]))
|
||||
[rn/view {:style (merge
|
||||
(if left-align?
|
||||
align-left
|
||||
centrify-style)
|
||||
{:flex 1
|
||||
:margin-left 4
|
||||
:text-align-vertical :center})}
|
||||
(case type
|
||||
:text-only [text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:color text-color}}
|
||||
main-text]
|
||||
:text-with-two-icons [rn/view {:style (assoc centrify-style :flex-direction :row)}
|
||||
[icons/icon left-icon
|
||||
(icon-props main-text-icon-color :big)]
|
||||
[text/text {:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:style {:padding-horizontal 4
|
||||
:color text-color}}
|
||||
main-text]
|
||||
|
||||
(defn- right-section-view [right-section-buttons]
|
||||
[rn/view {:style (assoc centrify-style
|
||||
:flex-direction :row
|
||||
:flex 1
|
||||
:justify-content :flex-end)}
|
||||
[icons/icon right-icon
|
||||
(icon-props main-text-icon-color :big)]]
|
||||
:text-with-one-icon [rn/view {:style {:flex-direction :row}}
|
||||
(if one-icon-align-left?
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
(when horizontal-description?
|
||||
[icons/icon left-icon
|
||||
(icon-props main-text-icon-color :big)])
|
||||
component-instance]
|
||||
[rn/view {:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
component-instance
|
||||
(when horizontal-description?
|
||||
[icons/icon left-icon
|
||||
(icon-props main-text-icon-color :big)])])]
|
||||
:text-with-description component-instance)]))
|
||||
|
||||
(defn- right-section-icon
|
||||
[{:keys [background-color icon icon-color push-to-the-left?] :or {push-to-the-left? false}}]
|
||||
[rn/view {:style (assoc
|
||||
icon-styles
|
||||
:background-color background-color
|
||||
:width 32
|
||||
:height 32
|
||||
:margin-right (if push-to-the-left? 8 0))}
|
||||
[icons/icon icon (icon-props icon-color :big)]])
|
||||
|
||||
(defn- render-right-section [right-section-buttons]
|
||||
[rn/view {:style (assoc
|
||||
centrify-style
|
||||
:flex-direction :row
|
||||
:flex 1
|
||||
:justify-content :flex-end)}
|
||||
(let [last-icon-index (-> right-section-buttons count dec)]
|
||||
(map-indexed (fn [index {:keys [icon on-press type] :or {type :grey}}]
|
||||
(map-indexed (fn [index {:keys [icon background-color icon-color on-press]}]
|
||||
^{:key index}
|
||||
[rn/view {:style {:margin-right (if (not= index last-icon-index) 8 0)}}
|
||||
[button/button {:on-press on-press :icon true :type type :size 32}
|
||||
icon]])
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[right-section-icon
|
||||
{:icon icon
|
||||
:background-color background-color
|
||||
:icon-color icon-color
|
||||
:push-to-the-left? (not= index last-icon-index)}]])
|
||||
right-section-buttons))])
|
||||
|
||||
(defn page-nav
|
||||
@@ -148,7 +154,7 @@
|
||||
:page-nav-color color
|
||||
:page-nav-background-uri image-uri
|
||||
:mid-section
|
||||
{:type one-of :text-only :text-with-two-icons :text-with-one-icon :text-with-description :user-avatar
|
||||
{:type one-of :text-only :text-with-two-icons :text-with-one-icon :text-with-description
|
||||
:icon icon
|
||||
:main-text string
|
||||
:left-icon icon
|
||||
@@ -157,19 +163,16 @@
|
||||
:description-color color
|
||||
:description-icon icon
|
||||
:description-user-icon icon
|
||||
:description-img a render prop which will be used in place of :description-user-icon
|
||||
:main-text-icon-color color
|
||||
}
|
||||
:left-section
|
||||
{:type button-type
|
||||
:on-press event
|
||||
{:on-press event
|
||||
:icon icon
|
||||
:icon-color color
|
||||
:icon-background-color color
|
||||
}
|
||||
:right-section-buttons vector of
|
||||
{:type button-type
|
||||
:on-press event
|
||||
{:on-press event
|
||||
:icon icon
|
||||
:icon-color color
|
||||
:icon-background-color color
|
||||
@@ -186,35 +189,32 @@
|
||||
mid-section-props
|
||||
{:type (:type mid-section)
|
||||
:horizontal-description? horizontal-description?
|
||||
:description-img (:description-img mid-section)
|
||||
:main-text (:main-text mid-section)
|
||||
:main-text-icon-color (:main-text-icon-color mid-section)
|
||||
:one-icon-align-left? one-icon-align-left?
|
||||
:right-icon (:right-icon mid-section)
|
||||
:icon (:icon mid-section)
|
||||
:left-icon (:left-icon mid-section)
|
||||
:avatar (:avatar mid-section)}]
|
||||
:left-icon (:left-icon mid-section)}]
|
||||
[rn/view {:style (cond-> {:display :flex
|
||||
:flex-direction :row
|
||||
;; iPhone 11 Pro's height in Figma divided by Component height 56/1125
|
||||
:align-items :center
|
||||
:padding-horizontal 20
|
||||
:height 56
|
||||
:justify-content :space-between}
|
||||
page-nav-background-uri (assoc :background-color page-nav-color)
|
||||
page-nav-color (assoc :background page-nav-background-uri))}
|
||||
[rn/view {:style {:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center}}
|
||||
[left-section-view left-section put-middle-section-on-left?]
|
||||
(render-left-section left-section put-middle-section-on-left?)
|
||||
(when put-middle-section-on-left?
|
||||
[mid-section-view (assoc mid-section-props
|
||||
:left-align? true
|
||||
:description (:description mid-section)
|
||||
:description-color (:description-color mid-section)
|
||||
:description-icon (:description-icon mid-section)
|
||||
:align-mid? align-mid?
|
||||
:description-user-icon (:description-user-icon mid-section))])]
|
||||
[render-mid-section (assoc mid-section-props
|
||||
:left-align? true
|
||||
:description (:description mid-section)
|
||||
:description-color (:description-color mid-section)
|
||||
:description-icon (:description-icon mid-section)
|
||||
:align-mid? align-mid?
|
||||
:description-user-icon (:description-user-icon mid-section))])]
|
||||
(when-not put-middle-section-on-left?
|
||||
[mid-section-view mid-section-props])
|
||||
[right-section-view right-section-buttons]]))
|
||||
[render-mid-section mid-section-props])
|
||||
(render-right-section right-section-buttons)]))
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
(ns quo2.components.navigation.top-nav
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.counter.counter :as counter]
|
||||
[quo2.components.buttons.button :as quo2.button]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[react-native.hole-view :as hole-view]))
|
||||
|
||||
(defn- get-button-common-props [type]
|
||||
(let [default? (= type :default)
|
||||
dark? (colors/dark?)]
|
||||
{:icon true
|
||||
:size 32
|
||||
:style {:margin-left 12}
|
||||
:type (if default?
|
||||
(if dark? :grey :dark-grey)
|
||||
type)
|
||||
:override-background-color (when (and dark? default?)
|
||||
colors/neutral-90)}))
|
||||
|
||||
(defn- base-button [icon on-press accessibility-label button-common-props]
|
||||
[quo2.button/button
|
||||
(merge
|
||||
{:on-press on-press
|
||||
:accessibility-label accessibility-label}
|
||||
button-common-props)
|
||||
icon])
|
||||
|
||||
(defn top-nav
|
||||
"[top-nav opts]
|
||||
opts
|
||||
{:type :default/:blurred/:shell
|
||||
:new-notifications? true/false
|
||||
:notification-indicator :unread-dot/:counter
|
||||
:open-profile fn
|
||||
:open-search fn
|
||||
:open-scanner fn
|
||||
:show-qr fn
|
||||
:open-activity-center fn
|
||||
:style override-style
|
||||
:avatar user-avatar
|
||||
:counter-label number}
|
||||
"
|
||||
[{:keys [type new-notifications? notification-indicator open-profile open-search
|
||||
open-scanner show-qr open-activity-center style avatar counter-label]}]
|
||||
(let [button-common-props (get-button-common-props type)]
|
||||
[rn/view {:style (merge
|
||||
{:height 56}
|
||||
style)}
|
||||
;; Left Section
|
||||
[rn/touchable-without-feedback {:on-press open-profile}
|
||||
[rn/view {:style {:position :absolute
|
||||
:left 20
|
||||
:top 12}}
|
||||
[user-avatar/user-avatar
|
||||
(merge
|
||||
{:ring? true
|
||||
:status-indicator? true
|
||||
:size :small}
|
||||
avatar)]]]
|
||||
;; Right Section
|
||||
[rn/view {:style {:position :absolute
|
||||
:right 20
|
||||
:top 12
|
||||
:flex-direction :row}}
|
||||
[base-button :i/search open-search :open-search-button button-common-props]
|
||||
[base-button :i/scan open-scanner :open-scanner-button button-common-props]
|
||||
[base-button :i/qr-code show-qr :show-qr-button button-common-props]
|
||||
[rn/view ;; Keep view instead of "[:<>" to make sure relative
|
||||
;; position is calculated from this view instead of its parent
|
||||
[hole-view/hole-view {:key new-notifications? ;; Key is required to force removal of holes
|
||||
:holes (cond
|
||||
(not new-notifications?) ;; No new notifications, remove holes
|
||||
[]
|
||||
|
||||
(= notification-indicator :unread-dot)
|
||||
[{:x 37 :y -3 :width 10 :height 10 :borderRadius 5}]
|
||||
|
||||
:else
|
||||
[{:x 33 :y -7 :width 18 :height 18 :borderRadius 7}])}
|
||||
[base-button :i/activity-center open-activity-center
|
||||
:open-activity-center-button button-common-props]]
|
||||
(when new-notifications?
|
||||
(if (= notification-indicator :counter)
|
||||
[counter/counter {:outline false
|
||||
:override-text-color colors/white
|
||||
:override-bg-color colors/primary-50
|
||||
:style {:position :absolute
|
||||
:left 34
|
||||
:top -6}}
|
||||
counter-label]
|
||||
[rn/view {:style {:width 8
|
||||
:height 8
|
||||
:border-radius 4
|
||||
:top -2
|
||||
:left 38
|
||||
:position :absolute
|
||||
:background-color colors/primary-50}}]))]]]))
|
||||
@@ -1,76 +0,0 @@
|
||||
(ns quo2.components.notifications.activity-log.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:flex-grow 1
|
||||
:align-items :flex-start
|
||||
:padding-top 8
|
||||
:padding-horizontal 12
|
||||
:padding-bottom 12})
|
||||
|
||||
(def icon
|
||||
{:height 32
|
||||
:width 32
|
||||
:border-radius 100
|
||||
:margin-top 10
|
||||
:border-width 1
|
||||
:border-color colors/white-opa-5
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def message-title
|
||||
{:color colors/white-opa-40
|
||||
:margin-bottom 2})
|
||||
|
||||
(def message-body
|
||||
{:color colors/white})
|
||||
|
||||
(def message-container
|
||||
{:border-radius 12
|
||||
:margin-top 12
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 8
|
||||
:background-color colors/white-opa-5})
|
||||
|
||||
(def buttons-container
|
||||
{:margin-top 12
|
||||
:flex-direction :row
|
||||
:align-items :flex-start})
|
||||
|
||||
(def status
|
||||
{:margin-top 12
|
||||
:align-items :flex-start
|
||||
:flex 1})
|
||||
|
||||
(defn title [replying?]
|
||||
{:color colors/white
|
||||
:flex-shrink 1
|
||||
:max-width (when-not replying? "60%")})
|
||||
|
||||
(def timestamp
|
||||
{:text-transform :none
|
||||
:flex-grow 1
|
||||
:margin-left 8
|
||||
:color colors/neutral-40})
|
||||
|
||||
(def unread-dot
|
||||
{:background-color colors/primary-50
|
||||
:border-radius 4
|
||||
:width 8
|
||||
:height 8})
|
||||
|
||||
(def unread-dot-container
|
||||
{:margin-left 8
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 7})
|
||||
|
||||
(def context-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :flex-start
|
||||
:flex-wrap :wrap})
|
||||
|
||||
(def top-section-container
|
||||
{:align-items :center
|
||||
:flex-direction :row})
|
||||
@@ -1,179 +0,0 @@
|
||||
(ns quo2.components.notifications.activity-log.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.tags.status-tags :as status-tags]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.notifications.activity-log.style :as style]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.i18n.i18n :as i18n]))
|
||||
|
||||
(def ^:private max-reply-length
|
||||
280)
|
||||
|
||||
(defn- valid-reply?
|
||||
[reply]
|
||||
(<= (count reply) max-reply-length))
|
||||
|
||||
(defn- activity-reply-text-input
|
||||
[reply-input on-update-reply]
|
||||
[rn/view
|
||||
[rn/view {:style {:margin-top 16
|
||||
:margin-bottom 8
|
||||
:flex-direction :row}}
|
||||
[text/text {:weight :medium
|
||||
:style {:flex-grow 1
|
||||
:color colors/neutral-40}}
|
||||
(i18n/label :t/your-answer)]
|
||||
[text/text {:style {:flex-shrink 1
|
||||
:color (if (valid-reply? @reply-input)
|
||||
colors/neutral-40
|
||||
colors/danger-60)}}
|
||||
(str (count @reply-input) "/" max-reply-length)]]
|
||||
[rn/view
|
||||
;; TODO(@ilmotta): Replace with quo2 component when available.
|
||||
;; https://github.com/status-im/status-mobile/issues/14364
|
||||
[quo/text-input
|
||||
{:on-change-text #(do (reset! reply-input %)
|
||||
(when on-update-reply
|
||||
(on-update-reply %)))
|
||||
:auto-capitalize :none
|
||||
:auto-focus true
|
||||
:accessibility-label :identity-verification-reply-text-input
|
||||
:placeholder (i18n/label :t/type-something)
|
||||
:return-key-type :none
|
||||
:multiline false
|
||||
:auto-correct false}]]])
|
||||
|
||||
(defn- activity-icon
|
||||
[icon]
|
||||
[rn/view {:style style/icon}
|
||||
[icon/icon icon {:color colors/white}]])
|
||||
|
||||
(defn- activity-context
|
||||
[context replying?]
|
||||
(let [first-line-offset (if replying? 4 0)
|
||||
gap-between-lines 4]
|
||||
(into [rn/view {:style (assoc style/context-container :margin-top first-line-offset)}]
|
||||
(mapcat (fn [detail]
|
||||
^{:key (hash detail)}
|
||||
(if (string? detail)
|
||||
(map (fn [s]
|
||||
[rn/view {:style {:margin-right 4
|
||||
:margin-top 0}}
|
||||
[text/text {:size :paragraph-2
|
||||
:style {:color colors/white}}
|
||||
s]])
|
||||
(string/split detail #"\s+"))
|
||||
[[rn/view {:margin-right 4
|
||||
:margin-top gap-between-lines}
|
||||
detail]]))
|
||||
context))))
|
||||
|
||||
(defn- activity-message
|
||||
[{:keys [title body]}]
|
||||
[rn/view {:style style/message-container}
|
||||
(when title
|
||||
[text/text {:size :paragraph-2
|
||||
:accessibility-label :activity-message-title
|
||||
:style style/message-title}
|
||||
title])
|
||||
(if (string? body)
|
||||
[text/text {:style style/message-body
|
||||
:accessibility-label :activity-message-body
|
||||
:size :paragraph-1}
|
||||
body]
|
||||
body)])
|
||||
|
||||
(defn- activity-buttons
|
||||
[button-1 button-2 replying? reply-input]
|
||||
(let [size (if replying? 40 24)
|
||||
common-style (when replying?
|
||||
{:padding-vertical 9
|
||||
:flex-grow 1
|
||||
:flex-basis 0})]
|
||||
[rn/view style/buttons-container
|
||||
(when button-1
|
||||
[button/button (-> button-1
|
||||
(assoc :size size)
|
||||
(update :style merge common-style {:margin-right 8}))
|
||||
(:label button-1)])
|
||||
(when button-2
|
||||
[button/button (-> button-2
|
||||
(assoc :size size)
|
||||
(assoc :disabled (and replying? (not (valid-reply? @reply-input))))
|
||||
(update :style merge common-style))
|
||||
(:label button-2)])]))
|
||||
|
||||
(defn- activity-status
|
||||
[status]
|
||||
[rn/view {:style style/status
|
||||
:accessibility-label :activity-status}
|
||||
[status-tags/status-tag {:size :small
|
||||
:label (:label status)
|
||||
:status status}]])
|
||||
|
||||
(defn- activity-title
|
||||
[title replying?]
|
||||
[text/text {:weight :semi-bold
|
||||
:accessibility-label :activity-title
|
||||
:style (style/title replying?)
|
||||
:size (if replying? :heading-2 :paragraph-1)}
|
||||
title])
|
||||
|
||||
(defn- activity-timestamp
|
||||
[timestamp]
|
||||
[text/text {:size :label
|
||||
:accessibility-label :activity-timestamp
|
||||
:style style/timestamp}
|
||||
timestamp])
|
||||
|
||||
(defn- activity-unread-dot
|
||||
[]
|
||||
[rn/view {:accessibility-label :activity-unread-indicator
|
||||
:style style/unread-dot-container}
|
||||
[rn/view {:style style/unread-dot}]])
|
||||
|
||||
(defn- footer
|
||||
[_]
|
||||
(let [reply-input (reagent/atom "")]
|
||||
(fn [{:keys [replying? on-update-reply status button-1 button-2]}]
|
||||
[:<>
|
||||
(when replying?
|
||||
[activity-reply-text-input reply-input on-update-reply])
|
||||
(cond (some? status)
|
||||
[activity-status status]
|
||||
|
||||
(or button-1 button-2)
|
||||
[activity-buttons button-1 button-2 replying? reply-input])])))
|
||||
|
||||
(defn view
|
||||
[{:keys [icon
|
||||
message
|
||||
context
|
||||
timestamp
|
||||
title
|
||||
replying?
|
||||
unread?]
|
||||
:as props}]
|
||||
[rn/view {:accessibility-label :activity
|
||||
:style style/container}
|
||||
(when-not replying?
|
||||
[activity-icon icon])
|
||||
[rn/view {:style {:padding-left (when-not replying? 8)
|
||||
:flex 1}}
|
||||
[rn/view
|
||||
[rn/view {:style style/top-section-container}
|
||||
[activity-title title replying?]
|
||||
(when-not replying?
|
||||
[activity-timestamp timestamp])
|
||||
(when (and unread? (not replying?))
|
||||
[activity-unread-dot])]
|
||||
(when context
|
||||
[activity-context context replying?])]
|
||||
(when message
|
||||
[activity-message message])
|
||||
[footer props]]])
|
||||
@@ -0,0 +1,157 @@
|
||||
(ns quo2.components.notifications.activity-logs
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.tags.status-tags :as status-tags]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn- activity-icon
|
||||
[icon]
|
||||
[rn/view {:height 32
|
||||
:width 32
|
||||
:border-radius 100
|
||||
:margin-top 10
|
||||
:border-width 1
|
||||
:border-color colors/white-opa-5
|
||||
:flex-direction :column
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[icon/icon icon {:color colors/white}]])
|
||||
|
||||
(defn- activity-unread-dot
|
||||
[]
|
||||
[rn/view {:margin-left 14
|
||||
:margin-right 6
|
||||
:background-color colors/primary-50
|
||||
:width 8
|
||||
:height 8
|
||||
:border-radius 4}])
|
||||
|
||||
(defn- activity-context
|
||||
[context]
|
||||
(let [margin-top 4]
|
||||
(into [rn/view {:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:flex-wrap :wrap
|
||||
:margin-top (+ 4 (- margin-top))}]
|
||||
(map-indexed (fn [index detail]
|
||||
^{:key index}
|
||||
[rn/view {:margin-right 4
|
||||
:margin-top margin-top}
|
||||
(if (string? detail)
|
||||
[text/text {:size :paragraph-2}
|
||||
detail]
|
||||
detail)])
|
||||
context))))
|
||||
|
||||
(defn- activity-message
|
||||
[{:keys [title body]}]
|
||||
[rn/view {:border-radius 12
|
||||
:margin-top 12
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 8
|
||||
:background-color colors/white-opa-5
|
||||
:flex 1
|
||||
:flex-direction :column}
|
||||
(when title
|
||||
[text/text {:size :paragraph-2
|
||||
:style {:color colors/white-opa-40}}
|
||||
title])
|
||||
(if (string? body)
|
||||
[text/text {:style {:color colors/white}
|
||||
:size :paragraph-1}
|
||||
body]
|
||||
body)])
|
||||
|
||||
(defn- activity-buttons
|
||||
[button-1 button-2]
|
||||
(let [size 24
|
||||
common-style {:padding-top 3
|
||||
:padding-right 8
|
||||
:padding-bottom 4
|
||||
:padding-left 8}]
|
||||
[rn/view {:margin-top 12
|
||||
:flex 1
|
||||
:flex-direction :row
|
||||
:align-items :flex-start}
|
||||
(when button-1
|
||||
[button/button (-> button-1
|
||||
(assoc :size size)
|
||||
(assoc-in [:style :margin-right] 8)
|
||||
(update :style merge common-style))
|
||||
(:label button-1)])
|
||||
(when button-2
|
||||
[button/button (-> button-2
|
||||
(assoc :size size)
|
||||
(update :style merge common-style))
|
||||
(:label button-2)])]))
|
||||
|
||||
(defn- activity-status
|
||||
[status]
|
||||
[rn/view {:margin-top 12
|
||||
:align-items :flex-start
|
||||
:flex 1}
|
||||
[status-tags/status-tag {:size :small
|
||||
:label (:label status)
|
||||
:status status}]])
|
||||
|
||||
(defn- activity-title
|
||||
[title]
|
||||
[text/text {:weight :semi-bold
|
||||
:style {:color colors/white}
|
||||
:size :paragraph-1}
|
||||
title])
|
||||
|
||||
(defn- activity-timestamp
|
||||
[timestamp]
|
||||
[rn/view {:margin-left 8}
|
||||
[text/text {:size :label
|
||||
:style {:text-transform :none
|
||||
:color colors/neutral-40}}
|
||||
timestamp]])
|
||||
|
||||
(defn activity-log
|
||||
[{:keys [button-1
|
||||
button-2
|
||||
icon
|
||||
message
|
||||
status
|
||||
context
|
||||
timestamp
|
||||
title
|
||||
unread?]}]
|
||||
[rn/view {:flex-direction :row
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:padding-top 8
|
||||
:padding-horizontal 12
|
||||
:padding-bottom 12
|
||||
:background-color (when unread?
|
||||
colors/primary-50-opa-10)}
|
||||
[activity-icon icon]
|
||||
[rn/view {:flex-direction :column
|
||||
:padding-left 8
|
||||
:flex 1}
|
||||
[rn/view {:flex 1
|
||||
:align-items :center
|
||||
:flex-direction :row}
|
||||
[rn/view {:flex 1
|
||||
:align-items :center
|
||||
:flex-direction :row}
|
||||
[rn/view {:flex-shrink 1}
|
||||
[activity-title title]]
|
||||
[activity-timestamp timestamp]]
|
||||
(when unread?
|
||||
[activity-unread-dot])]
|
||||
(when context
|
||||
[activity-context context])
|
||||
(when message
|
||||
[activity-message message])
|
||||
(cond
|
||||
(some? status)
|
||||
[activity-status status]
|
||||
|
||||
(or button-1 button-2)
|
||||
[activity-buttons button-1 button-2])]])
|
||||
@@ -10,8 +10,6 @@
|
||||
:position :absolute
|
||||
:right 22
|
||||
:border-radius 6
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/primary-50 colors/primary-60)}
|
||||
style)}
|
||||
[rn/text {:style (merge typography/font-medium typography/label {:color colors/white :text-align :center})} count]]))
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
(ns quo2.components.selectors.--tests--.selectors-component-spec
|
||||
(:require ["@testing-library/react-native" :as rtl]
|
||||
[quo2.components.selectors.selectors :as selectors]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn render-toggle
|
||||
([]
|
||||
(render-toggle {}))
|
||||
([opts]
|
||||
(rtl/render (reagent/as-element [selectors/toggle opts]))))
|
||||
|
||||
(defn render-checkbox
|
||||
([]
|
||||
(render-checkbox {}))
|
||||
([opts]
|
||||
(rtl/render (reagent/as-element [selectors/checkbox opts]))))
|
||||
|
||||
(defn render-checkbox-prefill
|
||||
([]
|
||||
(render-checkbox-prefill {}))
|
||||
([opts]
|
||||
(rtl/render (reagent/as-element [selectors/checkbox-prefill opts]))))
|
||||
|
||||
(defn render-radio
|
||||
([]
|
||||
(render-radio {}))
|
||||
([opts]
|
||||
(rtl/render (reagent/as-element [selectors/radio opts]))))
|
||||
|
||||
(js/global.test "default render of toggle component"
|
||||
(fn []
|
||||
(render-toggle)
|
||||
(-> (js/expect (rtl/screen.getByTestId "toggle-component"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "toggle component on change is working"
|
||||
(let [mock-fn (js/jest.fn)]
|
||||
(fn []
|
||||
(render-toggle {:on-change mock-fn})
|
||||
(rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component"))
|
||||
(-> (js/expect mock-fn)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
|
||||
(js/global.test "default render of radio component"
|
||||
(fn []
|
||||
(render-radio)
|
||||
(-> (js/expect (rtl/screen.getByTestId "radio-component"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "radio component on change is working"
|
||||
(let [mock-fn (js/jest.fn)]
|
||||
(fn []
|
||||
(render-radio {:on-change mock-fn})
|
||||
(rtl/fireEvent.press (rtl/screen.getByTestId "radio-component"))
|
||||
(-> (js/expect mock-fn)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
|
||||
(js/global.test "default render of checkbox component"
|
||||
(fn []
|
||||
(render-checkbox)
|
||||
(-> (js/expect (rtl/screen.getByTestId "checkbox-component"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "checkbox component on change is working"
|
||||
(let [mock-fn (js/jest.fn)]
|
||||
(fn []
|
||||
(render-checkbox {:on-change mock-fn})
|
||||
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component"))
|
||||
(-> (js/expect mock-fn)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
|
||||
(js/global.test "default render of checkbox-prefill component"
|
||||
(fn []
|
||||
(render-checkbox-prefill)
|
||||
(-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(js/global.test "checkbox-prefill component on change is working"
|
||||
(let [mock-fn (js/jest.fn)]
|
||||
(fn []
|
||||
(render-checkbox-prefill {:on-change mock-fn})
|
||||
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component"))
|
||||
(-> (js/expect mock-fn)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
@@ -43,8 +43,7 @@
|
||||
(colors/alpha colors/neutral-20 (if disabled? 0.3 1))
|
||||
(colors/alpha colors/neutral-70 (if disabled? 0.3 1))))})
|
||||
:accessibility-label (str "checkbox-" (if @checked? "on" "off"))
|
||||
:accessibility-role :checkbox
|
||||
:testID "checkbox-prefill-component"}
|
||||
:accessibility-role :checkbox}
|
||||
(when @checked?
|
||||
[rn/view {:style
|
||||
{:height 20
|
||||
@@ -83,8 +82,7 @@
|
||||
:border-color (if @checked? :none
|
||||
(get-color @checked? disabled? blurred-background?))}
|
||||
:accessibility-label (str "checkbox-" (if @checked? "on" "off"))
|
||||
:accessibility-role :checkbox
|
||||
:testID "checkbox-component"}
|
||||
:accessibility-role :checkbox}
|
||||
(when @checked?
|
||||
[rn/view {:style
|
||||
{:height 20
|
||||
@@ -110,8 +108,7 @@
|
||||
(colors/theme-colors colors/white
|
||||
(colors/alpha colors/neutral-80 0.4)))})
|
||||
:accessibility-label (str "radio-" (if @checked? "on" "off"))
|
||||
:accessibility-role :checkbox
|
||||
:testID "radio-component"}
|
||||
:accessibility-role :checkbox}
|
||||
|
||||
[rn/view {:style
|
||||
{:margin-left :auto
|
||||
@@ -136,8 +133,7 @@
|
||||
:border-radius 20
|
||||
:background-color (get-color @checked? disabled? blurred-background?)})
|
||||
:accessibility-label (str "toggle-" (if @checked? "on" "off"))
|
||||
:accessibility-role :checkbox
|
||||
:testID "toggle-component"}
|
||||
:accessibility-role :checkbox}
|
||||
[rn/view {:style
|
||||
{:margin-left (if @checked? 12 2)
|
||||
:height 16
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
[react-native.core :as rn]
|
||||
[quo2.components.tabs.tab :as tab]
|
||||
[reagent.core :as reagent]
|
||||
[utils.number :as utils.number]
|
||||
[utils.collection :as utils.collection]
|
||||
[utils :as utils]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.notifications.notification-dot :refer [notification-dot]]
|
||||
[react-native.masked-view :as masked-view]
|
||||
@@ -12,29 +11,26 @@
|
||||
|
||||
(def default-tab-size 32)
|
||||
|
||||
(defn indicator []
|
||||
[rn/view {:position :absolute
|
||||
:z-index 1
|
||||
:right -2
|
||||
:top -2
|
||||
:width 10
|
||||
:height 10
|
||||
:border-radius 5
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
|
||||
[notification-dot]])
|
||||
|
||||
(defn tabs [{:keys [default-active on-change style]}]
|
||||
(let [active-tab-id (reagent/atom default-active)]
|
||||
(fn [{:keys [data size] :or {size default-tab-size}}]
|
||||
[rn/view (merge {:flex-direction :row} style)
|
||||
(doall
|
||||
(for [{:keys [label id notification-dot? accessibility-label]} data]
|
||||
(for [{:keys [label id new-info accessibility-label]} data]
|
||||
^{:key id}
|
||||
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
|
||||
(when notification-dot?
|
||||
[indicator])
|
||||
(when new-info
|
||||
[rn/view {:position :absolute
|
||||
:z-index 1
|
||||
:right -2
|
||||
:top -2
|
||||
:width 10
|
||||
:height 10
|
||||
:border-radius 5
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
|
||||
[notification-dot]])
|
||||
[tab/tab
|
||||
{:id id
|
||||
:size size
|
||||
@@ -54,7 +50,7 @@
|
||||
;; Truncate to avoid unnecessary rendering.
|
||||
(if (> fade-percentage 0.99)
|
||||
0.99
|
||||
(utils.number/naive-round fade-percentage 2))))
|
||||
(utils/naive-round fade-percentage 2))))
|
||||
|
||||
(defn scrollable-tabs
|
||||
"Just like the component `tabs`, displays horizontally scrollable tabs with
|
||||
@@ -124,7 +120,7 @@
|
||||
:scroll-on-press?
|
||||
:size)
|
||||
(when scroll-on-press?
|
||||
{:initial-scroll-index (utils.collection/first-index #(= @active-tab-id (:id %)) data)})
|
||||
{:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)})
|
||||
{:ref #(reset! flat-list-ref %)
|
||||
:extra-data (str @active-tab-id)
|
||||
:horizontal true
|
||||
@@ -158,7 +154,7 @@
|
||||
:on-press (fn [id]
|
||||
(reset! active-tab-id id)
|
||||
(when scroll-on-press?
|
||||
(.scrollToIndex ^js @flat-list-ref
|
||||
(.scrollToIndex @flat-list-ref
|
||||
#js {:animated true
|
||||
:index index
|
||||
:viewPosition 0.5}))
|
||||
|
||||
@@ -104,12 +104,11 @@
|
||||
|
||||
(defn tag
|
||||
[_ _]
|
||||
(fn [{:keys [locked tokens size background-color on-press]
|
||||
(fn [{:keys [locked tokens size background-color]
|
||||
:or {size 24}}]
|
||||
[base-tag/base-tag {:background-color background-color
|
||||
:size size
|
||||
:type :permission
|
||||
:on-press on-press}
|
||||
:type :permission}
|
||||
[rn/view {:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :flex-end}
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
quo2.components.community.community-list-view
|
||||
quo2.components.community.community-view
|
||||
quo2.components.community.discover-card
|
||||
quo2.components.community.token-gating
|
||||
quo2.components.counter.counter
|
||||
quo2.components.dividers.divider-label
|
||||
quo2.components.dividers.date
|
||||
quo2.components.dividers.new-messages
|
||||
quo2.components.drawers.action-drawers
|
||||
quo2.components.dropdowns.dropdown
|
||||
@@ -30,19 +28,14 @@
|
||||
quo2.components.messages.gap
|
||||
quo2.components.messages.system-message
|
||||
quo2.components.reactions.reaction
|
||||
quo2.components.notifications.activity-log.view
|
||||
quo2.components.notifications.activity-logs
|
||||
quo2.components.notifications.info-count
|
||||
quo2.components.notifications.notification-dot
|
||||
quo2.components.tags.tags
|
||||
quo2.components.tags.context-tags
|
||||
quo2.components.tabs.tabs
|
||||
quo2.components.tabs.account-selector
|
||||
quo2.components.navigation.floating-shell-button
|
||||
quo2.components.tags.status-tags
|
||||
quo2.components.navigation.page-nav
|
||||
quo2.components.selectors.disclaimer
|
||||
quo2.components.selectors.selectors
|
||||
quo2.components.loaders.skeleton))
|
||||
quo2.components.list-items.index
|
||||
quo2.components.list-items.list-item))
|
||||
|
||||
(def button quo2.components.buttons.button/button)
|
||||
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
|
||||
@@ -59,18 +52,9 @@
|
||||
(def system-message quo2.components.messages.system-message/system-message)
|
||||
(def reaction quo2.components.reactions.reaction/reaction)
|
||||
(def tags quo2.components.tags.tags/tags)
|
||||
(def user-avatar-tag quo2.components.tags.context-tags/user-avatar-tag)
|
||||
(def context-tag quo2.components.tags.context-tags/context-tag)
|
||||
(def group-avatar-tag quo2.components.tags.context-tags/group-avatar-tag)
|
||||
(def tabs quo2.components.tabs.tabs/tabs)
|
||||
(def scrollable-tabs quo2.components.tabs.tabs/scrollable-tabs)
|
||||
(def account-selector quo2.components.tabs.account-selector/account-selector)
|
||||
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
|
||||
(def status-tag quo2.components.tags.status-tags/status-tag)
|
||||
(def page-nav quo2.components.navigation.page-nav/page-nav)
|
||||
(def disclaimer quo2.components.selectors.disclaimer/disclaimer)
|
||||
(def checkbox quo2.components.selectors.selectors/checkbox)
|
||||
(def skeleton quo2.components.loaders.skeleton/skeleton)
|
||||
|
||||
;;;; AVATAR
|
||||
(def account-avatar quo2.components.avatars.account-avatar/account-avatar)
|
||||
@@ -88,21 +72,20 @@
|
||||
(def community-stats quo2.components.community.community-view/community-stats)
|
||||
(def community-tags quo2.components.community.community-view/community-tags)
|
||||
(def community-title quo2.components.community.community-view/community-title)
|
||||
(def permission-tag-container quo2.components.community.community-view/permission-tag-container)
|
||||
(def discover-card quo2.components.community.discover-card/discover-card)
|
||||
(def token-gating quo2.components.community.token-gating/token-gating)
|
||||
|
||||
;;;; DIVIDERS
|
||||
(def divider-label quo2.components.dividers.divider-label/divider-label)
|
||||
(def new-messages quo2.components.dividers.new-messages/new-messages)
|
||||
(def divider-date quo2.components.dividers.date/date)
|
||||
|
||||
;;;; LIST ITEMS
|
||||
(def channel-list-item quo2.components.list-items.channel/list-item)
|
||||
(def menu-item quo2.components.list-items.menu-item/menu-item)
|
||||
(def preview-list quo2.components.list-items.preview-list/preview-list)
|
||||
(def index quo2.components.list-items.index/index)
|
||||
(def list-item quo2.components.list-items.list-item/list-item)
|
||||
|
||||
;;;; NOTIFICATIONS
|
||||
(def activity-log quo2.components.notifications.activity-log.view/view)
|
||||
(def activity-log quo2.components.notifications.activity-logs/activity-log)
|
||||
(def info-count quo2.components.notifications.info-count/info-count)
|
||||
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
|
||||
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
|
||||
@@ -1,4 +0,0 @@
|
||||
(ns quo2.core-spec
|
||||
(:require [quo2.components.selectors.--tests--.selectors-component-spec]
|
||||
[quo2.components.counter.--tests--.counter-component-spec]
|
||||
[quo2.components.drawers.--tests--.action-drawers-component-spec]))
|
||||
@@ -91,6 +91,11 @@
|
||||
(def white-opa-90 (alpha white 0.9))
|
||||
(def white-opa-95 (alpha white 0.95))
|
||||
|
||||
;;;;Black
|
||||
|
||||
;;Solid
|
||||
(def black "#000000")
|
||||
|
||||
;;;;Primary
|
||||
|
||||
;;Solid
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
(ns react-native.core
|
||||
(:require [reagent.core :as reagent]
|
||||
["react-native" :as react-native]
|
||||
["@react-native-community/blur" :as blur]
|
||||
[react-native.flat-list :as flat-list]
|
||||
[react-native.section-list :as section-list]
|
||||
[react-native.platform :as platform]))
|
||||
[react-native.flat-list :as flat-list]))
|
||||
|
||||
(def app-state ^js (.-AppState ^js react-native))
|
||||
(def blur-view (reagent/adapt-react-class (.-BlurView blur)))
|
||||
|
||||
(def view (reagent/adapt-react-class (.-View ^js react-native)))
|
||||
(def scroll-view (reagent/adapt-react-class (.-ScrollView ^js react-native)))
|
||||
(def image (reagent/adapt-react-class (.-Image ^js react-native)))
|
||||
(def text (reagent/adapt-react-class (.-Text ^js react-native)))
|
||||
(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native)))
|
||||
(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native)))
|
||||
|
||||
(def touchable-opacity (reagent/adapt-react-class (.-TouchableOpacity ^js react-native)))
|
||||
(def touchable-highlight (reagent/adapt-react-class (.-TouchableHighlight ^js react-native)))
|
||||
@@ -21,8 +17,6 @@
|
||||
|
||||
(def flat-list flat-list/flat-list)
|
||||
|
||||
(def section-list section-list/section-list)
|
||||
|
||||
(def activity-indicator (reagent/adapt-react-class (.-ActivityIndicator ^js react-native)))
|
||||
|
||||
(def modal (reagent/adapt-react-class (.-Modal ^js react-native)))
|
||||
@@ -54,19 +48,3 @@
|
||||
|
||||
(defn get-window []
|
||||
(js->clj (.get (.-Dimensions ^js react-native) "window") :keywordize-keys true))
|
||||
|
||||
(def status-bar (.-StatusBar ^js react-native))
|
||||
|
||||
(defn hw-back-add-listener [callback]
|
||||
(.addEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
|
||||
|
||||
(defn hw-back-remove-listener [callback]
|
||||
(.removeEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
|
||||
|
||||
(def keyboard-avoiding-view-class (reagent/adapt-react-class (.-KeyboardAvoidingView react-native)))
|
||||
|
||||
(defn keyboard-avoiding-view [props & children]
|
||||
(into [keyboard-avoiding-view-class
|
||||
(merge (when platform/ios? {:behavior :padding})
|
||||
props)]
|
||||
children))
|
||||
|
||||
@@ -27,9 +27,6 @@
|
||||
(defn show-overlay [comp]
|
||||
(.showOverlay Navigation (clj->js comp)))
|
||||
|
||||
(defn pop-to-root [tab]
|
||||
(.popToRoot Navigation (clj->js tab)))
|
||||
|
||||
(defn dissmiss-overlay [comp]
|
||||
(.catch (.dismissOverlay Navigation comp) #()))
|
||||
|
||||
|
||||
@@ -5,9 +5,5 @@
|
||||
|
||||
(def os (when platform (.-OS ^js platform)))
|
||||
|
||||
(def version (when platform (.-Version ^js platform)))
|
||||
|
||||
(def android? (= os "android"))
|
||||
(def ios? (= os "ios"))
|
||||
|
||||
(def low-device? (and android? (< version 29)))
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
(:require ["react-native" :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.string :as string]
|
||||
["react-native-linear-gradient" :default LinearGradient]
|
||||
["react-native-reanimated" :default reanimated
|
||||
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe)]))
|
||||
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring Easing Keyframe)]))
|
||||
|
||||
;; Animated Components
|
||||
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
|
||||
@@ -13,8 +12,6 @@
|
||||
(def image (reagent/adapt-react-class (.-Image reanimated)))
|
||||
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
|
||||
|
||||
(def linear-gradient (create-animated-component LinearGradient))
|
||||
|
||||
;; Hooks
|
||||
(def use-shared-value useSharedValue)
|
||||
(def use-animated-style useAnimatedStyle)
|
||||
@@ -24,7 +21,6 @@
|
||||
(def with-delay withDelay)
|
||||
(def with-spring withSpring)
|
||||
(def key-frame Keyframe)
|
||||
(def with-repeat withRepeat)
|
||||
|
||||
;; Easings
|
||||
(def bezier (.-bezier ^js Easing))
|
||||
@@ -72,7 +68,3 @@
|
||||
(defn animate-shared-value-with-delay [anim val duration easing delay]
|
||||
(set-shared-value anim (with-delay delay (with-timing val (js-obj "duration" duration
|
||||
"easing" (get easings easing))))))
|
||||
|
||||
(defn animate-shared-value-with-repeat [anim val duration easing number-of-repetitions reverse?]
|
||||
(set-shared-value anim (with-repeat (with-timing val (js-obj "duration" duration
|
||||
"easing" (get easings easing))) number-of-repetitions reverse?)))
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
(defn consumer [component]
|
||||
[consumer-raw
|
||||
(fn [^js insets]
|
||||
(fn [insets]
|
||||
(reagent/as-element
|
||||
[component (js->clj insets :keywordize-keys true)]))])
|
||||
|
||||
|
||||