Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c265891a4 | ||
|
|
bc14b9c9e1 | ||
|
|
f0fd1c3966 | ||
|
|
93b2a5de30 | ||
|
|
506c0c6136 | ||
|
|
2d499a8f72 |
@@ -100,8 +100,9 @@ Statusgo.xcframework
|
||||
|
||||
#ios
|
||||
/ios/Pods/
|
||||
/ios/logs/
|
||||
/ios/StatusIm.xcworkspace
|
||||
/ios/react-native-xcode.log
|
||||
/ios/set_xcode_version.log
|
||||
.ruby-version
|
||||
status-e2e/
|
||||
|
||||
@@ -182,4 +183,4 @@ test/appium/tests/users.py
|
||||
/.calva/
|
||||
|
||||
## component-tests
|
||||
*.log
|
||||
*.log
|
||||
@@ -28,4 +28,12 @@
|
||||
<item name="android:textColorPrimary">@color/alert_text</item>
|
||||
<item name="android:background">@color/alert_background</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.FullScreenDialog">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
@@ -63,9 +63,6 @@ pipeline {
|
||||
steps {
|
||||
script { api = ios.bundle() }
|
||||
}
|
||||
post {
|
||||
failure { archiveArtifacts 'ios/logs/*' }
|
||||
}
|
||||
}
|
||||
stage('Parallel Upload') {
|
||||
parallel {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.9'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent {
|
||||
|
||||
@@ -116,20 +116,6 @@ deref'ed atoms.
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-90)})
|
||||
```
|
||||
|
||||
### Custom Colors
|
||||
|
||||
The Status designs have a lot of customization of user and group colors with components and pages. For consistency it is best to use `customization-color` as the prop key on pages and components. This will help easily identify what pages and components in the application are using customized colors.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(defn community-card [{keys [custom-color]}]
|
||||
...)
|
||||
|
||||
;; good
|
||||
(defn community-card [{keys [customization-color]}]
|
||||
...)
|
||||
```
|
||||
|
||||
### Using TODOs comments
|
||||
|
||||
_TODO_ comments are used extensively in the codebase, but prefer to use them
|
||||
|
||||
@@ -123,7 +123,6 @@ def build_ios_adhoc(readonly: false, pr_build: false)
|
||||
export_method: 'ad-hoc',
|
||||
output_name: 'StatusIm',
|
||||
output_directory: 'status-ios',
|
||||
buildlog_path: 'ios/logs',
|
||||
export_options: {
|
||||
signingStyle: 'manual',
|
||||
provisioningProfiles: {
|
||||
@@ -163,7 +162,6 @@ def build_ios_e2e
|
||||
# 3. directory where to up StatusIm.app
|
||||
derived_data_path: 'status-ios',
|
||||
output_name: 'StatusIm.app',
|
||||
buildlog_path: 'ios/logs',
|
||||
# -------------------------------------
|
||||
# Normal stuff
|
||||
scheme: 'StatusIm',
|
||||
@@ -241,7 +239,6 @@ platform :ios do
|
||||
clean: true,
|
||||
export_method: 'app-store',
|
||||
output_directory: 'status-ios',
|
||||
buildlog_path: 'ios/logs',
|
||||
include_symbols: false,
|
||||
export_options: {
|
||||
"combileBitcode": true,
|
||||
|
||||
@@ -392,6 +392,7 @@ PODS:
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.10)
|
||||
- secp256k1 (0.1.6)
|
||||
- ShowTime (2.5.3)
|
||||
- SQLCipher (3.4.2):
|
||||
- SQLCipher/standard (= 3.4.2)
|
||||
- SQLCipher/common (3.4.2)
|
||||
@@ -472,6 +473,7 @@ DEPENDENCIES:
|
||||
- RNShare (from `../node_modules/react-native-share`)
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
- secp256k1 (from `https://github.com/status-im/secp256k1.swift.git`)
|
||||
- ShowTime
|
||||
- SQLCipher (~> 3.0)
|
||||
- SSZipArchive (= 2.4.3)
|
||||
- TouchID (from `../node_modules/react-native-touch-id`)
|
||||
@@ -485,6 +487,7 @@ SPEC REPOS:
|
||||
- libwebp
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- ShowTime
|
||||
- SQLCipher
|
||||
- SSZipArchive
|
||||
- TOCropViewController
|
||||
@@ -645,7 +648,7 @@ SPEC CHECKSUMS:
|
||||
FBLazyVector: 352a8ca9bbc8e2f097d680747a8c97ecef12d469
|
||||
FBReactNativeSpec: 7dfb84f624136a45727c813ed21d130cd3e61beb
|
||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
||||
glog: 997518ea2aa2d8cd5df9797b641b758d52ecf2bc
|
||||
glog: 36ce0530c6d2c3a5a4326885ef4069564887a1db
|
||||
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
|
||||
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
|
||||
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
|
||||
@@ -710,12 +713,13 @@ SPEC CHECKSUMS:
|
||||
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
|
||||
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
|
||||
secp256k1: f61d67e6fdcb85fd727acf1bf35ace6036db540c
|
||||
ShowTime: 06cc9dc79886274b21041fe19b79c9eff59b9714
|
||||
SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990
|
||||
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
|
||||
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
|
||||
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
|
||||
Yoga: 0276e9f20976c8568e107cfc1163a8629051adc0
|
||||
|
||||
PODFILE CHECKSUM: ca5d07911eadc1267649ecc15379e5127a0cc839
|
||||
PODFILE CHECKSUM: 06348d9065f85ab25a2c9560c69af5425c37e29e
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
||||
@@ -526,7 +526,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
|
||||
};
|
||||
0F876BD5356F61BF142A01A0 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -584,7 +584,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./logs/react-native-xcode.log 2>&1";
|
||||
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
|
||||
};
|
||||
3AAD2AD724A3A60E0075D594 /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -598,7 +598,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./logs/set_xcode_version.log 2>&1";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
|
||||
};
|
||||
3C1038075AE5E6FB86AC2319 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@@ -678,7 +678,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
shellPath = "/usr/bin/env sh";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./logs/set_xcode_version.log 2>&1";
|
||||
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
|
||||
};
|
||||
E732E3E1B024946173BF6D3D /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Description
|
||||
|
||||
This directory is the destination of logs created by Fastlane and React Native Xcode script.
|
||||
|
||||
# Logs
|
||||
|
||||
* `react-native-xcode.log` - Output from `node_modules/react-native/scripts/react-native-xcode.sh`.
|
||||
- Created by redirecting output of `shellScript` in `ios/StatusIm.xcodeproj/project.pbxproj`.
|
||||
* `Status PR-StatusImPR.log - Created by [Fastlane Gym](https://docs.fastlane.tools/actions/gym/).
|
||||
- Configred via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
|
||||
|
||||
# CI
|
||||
|
||||
These log files are uploaded to Jenkins as CI job artifacts on failure using `archiveArtifacts`.
|
||||
@@ -1139,6 +1139,11 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||
executeRunnableStatusGoMethod(() -> Statusgo.generateAlias(seed), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void emojiHash(final String publicKey, final Callback callback) throws JSONException {
|
||||
executeRunnableStatusGoMethod(() -> Statusgo.emojiHash(publicKey), callback);
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public String identicon(final String seed) {
|
||||
return Statusgo.identicon(seed);
|
||||
|
||||
@@ -866,6 +866,12 @@ RCT_EXPORT_METHOD(generateAliasAsync:(NSString *)publicKey
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(emojiHash:(NSString *)publicKey
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
NSString *result = StatusgoEmojiHash(publicKey);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(identicon:(NSString *)publicKey) {
|
||||
return StatusgoIdenticon(publicKey);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ in mkShell {
|
||||
|
||||
buildInputs = with pkgs; lib.unique ([
|
||||
# core utilities that should always be present in a shell
|
||||
bash curl wget file unzip flock procps
|
||||
bash curl wget file unzip flock
|
||||
git gnumake jq ncurses gnugrep parallel
|
||||
lsof # used in start-react-native.sh
|
||||
# build specific utilities
|
||||
@@ -22,7 +22,7 @@ in mkShell {
|
||||
# other nice to have stuff
|
||||
yarn nodejs python27
|
||||
] # and some special cases
|
||||
++ lib.optionals stdenv.isDarwin [ cocoapods clang tcl ]
|
||||
++ lib.optionals stdenv.isDarwin [ cocoapods clang ]
|
||||
++ lib.optionals (!stdenv.isDarwin) [ gcc8 ]
|
||||
);
|
||||
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
"react-native-linear-gradient": "^2.5.6",
|
||||
"react-native-lottie-splash-screen": "^1.0.1",
|
||||
"react-native-mail": "^6.1.1",
|
||||
"react-native-modal": "^13.0.1",
|
||||
"react-native-navigation": "^7.27.1",
|
||||
"react-native-navigation-bar-color": "^2.0.2",
|
||||
"react-native-orientation-locker": "^1.5.0",
|
||||
"react-native-permissions": "^2.1.5",
|
||||
"react-native-randombytes": "^3.6.1",
|
||||
|
||||
|
Before Width: | Height: | Size: 898 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 591 B |
|
Before Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 864 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 927 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 768 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 539 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 788 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
@@ -1,10 +0,0 @@
|
||||
import { useDerivedValue } from 'react-native-reanimated';
|
||||
|
||||
export function infoLayout(input, isTop) {
|
||||
return useDerivedValue(
|
||||
function () {
|
||||
'worklet'
|
||||
return isTop ? input.value : -input.value
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import {useAnimatedScrollHandler} from "react-native-reanimated";
|
||||
|
||||
export function useAnimatedScrollHandlerWorklet(scrollY) {
|
||||
return useAnimatedScrollHandler((event) => {
|
||||
scrollY.value = event.contentOffset.y;
|
||||
})
|
||||
}
|
||||
@@ -147,10 +147,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
|
||||
:SvgXml #js {:render identity}
|
||||
:default #js {:render identity}})
|
||||
(def react-native-webview #js {:default {}})
|
||||
(def react-native-audio-toolkit
|
||||
#js
|
||||
{:MediaStates {}
|
||||
:PlaybackCategories {}})
|
||||
(def react-native-audio-toolkit #js {:MediaStates {}})
|
||||
(def net-info #js {})
|
||||
(def touchid #js {})
|
||||
(def react-native-image-viewing #js {:default {}})
|
||||
@@ -355,6 +352,11 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
|
||||
(def worklet-factory
|
||||
#js {:applyAnimationsToStyle (fn [])})
|
||||
|
||||
(def shell-worklets #js {})
|
||||
|
||||
(def bottom-sheet #js {})
|
||||
(def record-audio-worklets #js {})
|
||||
|
||||
;; Update i18n_resources.cljs
|
||||
(defn mock
|
||||
[module]
|
||||
@@ -402,12 +404,10 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
|
||||
"@react-native-async-storage/async-storage" async-storage
|
||||
"react-native-svg" react-native-svg
|
||||
"react-native-orientation-locker" react-native-orientation-locker
|
||||
"../src/js/worklets/core.js" worklet-factory
|
||||
"../src/js/worklets/shell.js" #js {}
|
||||
"../src/js/worklets/bottom_sheet.js" #js {}
|
||||
"../src/js/worklets/record_audio.js" #js {}
|
||||
"../src/js/worklets/scroll_view.js" #js {}
|
||||
"../src/js/worklets/lightbox.js" #js {}
|
||||
"../src/js/worklet_factory.js" worklet-factory
|
||||
"../src/js/shell_worklets.js" shell-worklets
|
||||
"../src/js/bottom_sheet.js" bottom-sheet
|
||||
"../src/js/record_audio_worklets.js" record-audio-worklets
|
||||
"./fleets.js" default-fleets
|
||||
"@walletconnect/client" wallet-connect-client
|
||||
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
(ns quo2.components.avatars.user-avatar
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :refer [dark?]]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
|
||||
(def sizes
|
||||
{:big {:outer 80
|
||||
:inner 72
|
||||
:status-indicator 20
|
||||
:status-indicator-border 4
|
||||
:font-size :heading-1}
|
||||
:medium {:outer 48
|
||||
:inner 44
|
||||
:status-indicator 12
|
||||
:status-indicator-border 2
|
||||
:font-size :paragraph-1}
|
||||
:small {:outer 32
|
||||
:inner 28
|
||||
:status-indicator 12
|
||||
:status-indicator-border 2
|
||||
:font-size :paragraph-2}
|
||||
:xs {:outer 24
|
||||
:inner 24
|
||||
:status-indicator 0
|
||||
:status-indicator-border 0
|
||||
:font-size :paragraph-2}
|
||||
:xxs {:outer 20
|
||||
:inner 20
|
||||
:status-indicator 0
|
||||
:status-indicator-border 0
|
||||
:font-size :label}
|
||||
:xxxs {:outer 16
|
||||
:inner 16
|
||||
:status-indicator 0
|
||||
:status-indicator-border 0
|
||||
:font-size :label}})
|
||||
|
||||
(defn dot-indicator
|
||||
[{:keys [size online? ring? dark?]}]
|
||||
(let [dimensions (get-in sizes [size :status-indicator])
|
||||
border-width (get-in sizes [size :status-indicator-border])
|
||||
right (case size
|
||||
:big 2
|
||||
:medium 0
|
||||
:small -2
|
||||
0)
|
||||
bottom (case size
|
||||
:big (if ring? -1 2)
|
||||
:medium (if ring? 0 -2)
|
||||
:small -2
|
||||
0)]
|
||||
[rn/view
|
||||
{:style {:background-color (if online?
|
||||
colors/success-50
|
||||
colors/neutral-40)
|
||||
:width dimensions
|
||||
:height dimensions
|
||||
:border-width border-width
|
||||
:border-radius dimensions
|
||||
:border-color (if dark?
|
||||
colors/neutral-100
|
||||
colors/white)
|
||||
:position :absolute
|
||||
:bottom bottom
|
||||
:right right}}]))
|
||||
|
||||
(defn initials-style
|
||||
[inner-dimensions outer-dimensions]
|
||||
{:position :absolute
|
||||
:top (/ (- outer-dimensions inner-dimensions) 2)
|
||||
:left (/ (- outer-dimensions inner-dimensions) 2)
|
||||
:width inner-dimensions
|
||||
:height inner-dimensions
|
||||
:border-radius inner-dimensions
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/custom-color-by-theme :turquoise 50 60)})
|
||||
|
||||
(defn outer-styles
|
||||
[outer-dimensions]
|
||||
{:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:border-radius outer-dimensions})
|
||||
|
||||
(def one-initial-letter-sizes #{:xs :xxs :xxxs})
|
||||
(def valid-ring-sizes #{:big :medium :small})
|
||||
|
||||
(defn initials-avatar
|
||||
[{:keys [full-name size inner-dimensions outer-dimensions]}]
|
||||
(let [amount-initials (if (one-initial-letter-sizes size) 1 2)
|
||||
initials (as-> full-name $
|
||||
(string/split $ " ")
|
||||
(map (comp string/upper-case first) $)
|
||||
(take amount-initials $)
|
||||
(string/join $))
|
||||
font-size (get-in sizes [size :font-size])]
|
||||
[rn/view {:style (initials-style inner-dimensions outer-dimensions)}
|
||||
[text/text
|
||||
{:style {:color colors/white-opa-70}
|
||||
:weight :semi-bold
|
||||
:size font-size}
|
||||
initials]]))
|
||||
|
||||
(defn user-avatar
|
||||
"If no `profile-picture` is given, draws the initials based on the `full-name` and
|
||||
uses `ring-background` to display the ring behind the initials when given. Otherwise,
|
||||
shows the profile picture which already comes with the ring drawn over it."
|
||||
[{:keys [full-name status-indicator? online? size profile-picture ring-background]
|
||||
:or {status-indicator? true
|
||||
online? true
|
||||
size :big}}]
|
||||
(let [full-name (or full-name "empty name")
|
||||
draw-ring? (and ring-background (valid-ring-sizes size))
|
||||
outer-dimensions (get-in sizes [size :outer])
|
||||
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
|
||||
[rn/view
|
||||
{:style (outer-styles outer-dimensions)
|
||||
:accessibility-label :user-avatar}
|
||||
;; The `profile-picture` already has the ring in it
|
||||
(when-let [image (or profile-picture ring-background)]
|
||||
[fast-image/fast-image
|
||||
{:style (outer-styles outer-dimensions)
|
||||
:source image}])
|
||||
(when-not profile-picture
|
||||
[initials-avatar
|
||||
{:full-name full-name
|
||||
:size size
|
||||
:inner-dimensions inner-dimensions
|
||||
:outer-dimensions outer-dimensions}])
|
||||
(when status-indicator?
|
||||
[dot-indicator
|
||||
{:size size
|
||||
:online? online?
|
||||
:ring? draw-ring?
|
||||
:dark? (dark?)}])]))
|
||||
@@ -1,129 +0,0 @@
|
||||
(ns quo2.components.avatars.user-avatar.component-spec
|
||||
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defonce mock-picture (js/require "../resources/images/mock2/user_picture_male4.png"))
|
||||
|
||||
(h/describe "user avatar"
|
||||
(h/test "Default render"
|
||||
(h/render [user-avatar/user-avatar])
|
||||
(h/is-truthy (h/get-by-label-text :user-avatar))
|
||||
(h/is-truthy (h/get-by-text "EN")))
|
||||
|
||||
(h/describe "Profile picture"
|
||||
(h/test "Renders"
|
||||
(h/render
|
||||
[user-avatar/user-avatar {:profile-picture mock-picture}])
|
||||
(h/is-truthy (h/get-by-label-text :profile-picture)))
|
||||
|
||||
(h/test "Renders even if `:full-name` is passed"
|
||||
(h/render
|
||||
[user-avatar/user-avatar
|
||||
{:profile-picture mock-picture
|
||||
:full-name "New User1"}])
|
||||
(h/is-truthy (h/get-by-label-text :profile-picture))
|
||||
(h/is-null (h/query-by-label-text :initials-avatar)))
|
||||
|
||||
(h/describe "Status indicator"
|
||||
(h/test "Render"
|
||||
(h/render
|
||||
[user-avatar/user-avatar
|
||||
{:profile-picture mock-picture
|
||||
:status-indicator? true}])
|
||||
(h/is-truthy (h/get-by-label-text :profile-picture))
|
||||
(h/is-truthy (h/get-by-label-text :status-indicator)))
|
||||
|
||||
(h/test "Do not render"
|
||||
(h/render
|
||||
[user-avatar/user-avatar
|
||||
{:profile-picture mock-picture
|
||||
:status-indicator? false}])
|
||||
(h/is-truthy (h/get-by-label-text :profile-picture))
|
||||
(h/is-null (h/query-by-label-text :status-indicator)))))
|
||||
|
||||
(h/describe "Initials Avatar"
|
||||
(h/describe "Render initials"
|
||||
(letfn [(user-avatar-component [size]
|
||||
[user-avatar/user-avatar
|
||||
{:full-name "New User"
|
||||
:size size}])]
|
||||
(h/describe "Two letters"
|
||||
(h/test "Size :big"
|
||||
(h/render (user-avatar-component :big))
|
||||
(h/is-truthy (h/get-by-text "NU")))
|
||||
|
||||
(h/test "Size :medium"
|
||||
(h/render (user-avatar-component :medium))
|
||||
(h/is-truthy (h/get-by-text "NU")))
|
||||
|
||||
(h/test "Size :small"
|
||||
(h/render (user-avatar-component :small))
|
||||
(h/is-truthy (h/get-by-text "NU"))))
|
||||
|
||||
(h/describe "One letter"
|
||||
(h/test "Size :xs"
|
||||
(h/render (user-avatar-component :xs))
|
||||
(h/is-truthy (h/get-by-text "N")))
|
||||
|
||||
(h/test "Size :xxs"
|
||||
(h/render (user-avatar-component :xxs))
|
||||
(h/is-truthy (h/get-by-text "N")))
|
||||
|
||||
(h/test "Size :xxxs"
|
||||
(h/render (user-avatar-component :xxxs))
|
||||
(h/is-truthy (h/get-by-text "N"))))))
|
||||
|
||||
(h/describe "Render ring"
|
||||
(letfn [(user-avatar-component [size]
|
||||
[user-avatar/user-avatar
|
||||
{:full-name "New User"
|
||||
:ring-background mock-picture
|
||||
:size size}])]
|
||||
(h/describe "Passed and drawn"
|
||||
(h/test "Size :big"
|
||||
(h/render (user-avatar-component :big))
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-truthy (h/get-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :medium"
|
||||
(h/render (user-avatar-component :medium))
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-truthy (h/get-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :small"
|
||||
(h/render (user-avatar-component :small))
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-truthy (h/get-by-label-text :ring-background))))
|
||||
|
||||
(h/describe "Passed and not drawn (because of invalid size for ring)"
|
||||
(h/test "Size :xs"
|
||||
(h/render (user-avatar-component :xs))
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-null (h/query-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :xxs"
|
||||
(h/render (user-avatar-component :xxs))
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-null (h/query-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :xxxs"
|
||||
(h/render (user-avatar-component :xxxs))
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-null (h/query-by-label-text :ring-background))))))
|
||||
|
||||
(h/describe "Status indicator"
|
||||
(h/test "Render"
|
||||
(h/render
|
||||
[user-avatar/user-avatar
|
||||
{:full-name "Test User"
|
||||
:status-indicator? true}])
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-truthy (h/get-by-label-text :status-indicator)))
|
||||
|
||||
(h/test "Do not render"
|
||||
(h/render
|
||||
[user-avatar/user-avatar
|
||||
{:full-name "Test User"
|
||||
:status-indicator? false}])
|
||||
(h/is-truthy (h/get-by-label-text :initials-avatar))
|
||||
(h/is-null (h/query-by-label-text :status-indicator))))))
|
||||
@@ -1,83 +0,0 @@
|
||||
(ns quo2.components.avatars.user-avatar.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def sizes
|
||||
{:big {:outer 80
|
||||
:inner 72
|
||||
:status-indicator 20
|
||||
:status-indicator-border 4
|
||||
:font-size :heading-1}
|
||||
:medium {:outer 48
|
||||
:inner 44
|
||||
:status-indicator 12
|
||||
:status-indicator-border 2
|
||||
:font-size :paragraph-1}
|
||||
:small {:outer 32
|
||||
:inner 28
|
||||
:status-indicator 12
|
||||
:status-indicator-border 2
|
||||
:font-size :paragraph-2}
|
||||
:xs {:outer 24
|
||||
:inner 24
|
||||
:status-indicator 0
|
||||
:status-indicator-border 0
|
||||
:font-size :paragraph-2}
|
||||
:xxs {:outer 20
|
||||
:inner 20
|
||||
:status-indicator 0
|
||||
:status-indicator-border 0
|
||||
:font-size :label}
|
||||
:xxxs {:outer 16
|
||||
:inner 16
|
||||
:status-indicator 0
|
||||
:status-indicator-border 0
|
||||
:font-size :label}})
|
||||
|
||||
(defn outer
|
||||
[size]
|
||||
(let [dimensions (get-in sizes [size :outer])]
|
||||
{:width dimensions
|
||||
:height dimensions
|
||||
:border-radius dimensions}))
|
||||
|
||||
(defn initials-avatar
|
||||
[size draw-ring? customization-color]
|
||||
(let [outer-dimensions (get-in sizes [size :outer])
|
||||
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
|
||||
{:position :absolute
|
||||
:top (/ (- outer-dimensions inner-dimensions) 2)
|
||||
:left (/ (- outer-dimensions inner-dimensions) 2)
|
||||
:width inner-dimensions
|
||||
:height inner-dimensions
|
||||
:border-radius inner-dimensions
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/custom-color-by-theme customization-color 50 60)}))
|
||||
|
||||
(def initials-avatar-text
|
||||
{:color colors/white-opa-70})
|
||||
|
||||
(defn dot
|
||||
[size online? ring?]
|
||||
(let [background (if online? colors/success-50 colors/neutral-40)
|
||||
dimensions (get-in sizes [size :status-indicator])
|
||||
border-width (get-in sizes [size :status-indicator-border])
|
||||
right (case size
|
||||
:big 2
|
||||
:medium 0
|
||||
:small -2
|
||||
0)
|
||||
bottom (case size
|
||||
:big (if ring? -1 2)
|
||||
:medium (if ring? 0 -2)
|
||||
:small -2
|
||||
0)]
|
||||
{:position :absolute
|
||||
:bottom bottom
|
||||
:right right
|
||||
:width dimensions
|
||||
:height dimensions
|
||||
:border-width border-width
|
||||
:border-radius dimensions
|
||||
:border-color (colors/theme-colors colors/white colors/neutral-100)
|
||||
:background-color background}))
|
||||
@@ -1,61 +0,0 @@
|
||||
(ns quo2.components.avatars.user-avatar.view
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.avatars.user-avatar.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
|
||||
(defn- extract-initials
|
||||
[full-name amount-initials]
|
||||
(let [upper-case-first-letter (comp string/upper-case first)
|
||||
names-list (string/split full-name " ")]
|
||||
(->> names-list
|
||||
(map upper-case-first-letter)
|
||||
(take amount-initials)
|
||||
(string/join))))
|
||||
|
||||
(defn initials-avatar
|
||||
[{:keys [full-name size draw-ring? customization-color]}]
|
||||
(let [font-size (get-in style/sizes [size :font-size])
|
||||
amount-initials (if (#{:xs :xxs :xxxs} size) 1 2)]
|
||||
[rn/view
|
||||
{:accessibility-label :initials-avatar
|
||||
:style (style/initials-avatar size draw-ring? customization-color)}
|
||||
[text/text
|
||||
{:style style/initials-avatar-text
|
||||
:size font-size
|
||||
:weight :semi-bold}
|
||||
(extract-initials full-name amount-initials)]]))
|
||||
|
||||
(def valid-ring-sizes #{:big :medium :small})
|
||||
|
||||
(defn user-avatar
|
||||
"If no `profile-picture` is given, draws the initials based on the `full-name` and
|
||||
uses `ring-background` to display the ring behind the initials when given. Otherwise,
|
||||
shows the `profile-picture` which already comes with the ring drawn."
|
||||
[{:keys [full-name status-indicator? online? size profile-picture ring-background
|
||||
customization-color]
|
||||
:or {status-indicator? true
|
||||
online? true
|
||||
size :big
|
||||
customization-color :turquoise}}]
|
||||
(let [full-name (or full-name "empty name")
|
||||
draw-ring? (and ring-background (valid-ring-sizes size))
|
||||
outer-styles (style/outer size)]
|
||||
[rn/view {:style outer-styles :accessibility-label :user-avatar}
|
||||
;; The `profile-picture` already has the ring in it
|
||||
(when-let [image (or profile-picture ring-background)]
|
||||
[fast-image/fast-image
|
||||
{:accessibility-label (if draw-ring? :ring-background :profile-picture)
|
||||
:style outer-styles
|
||||
:source image}])
|
||||
(when-not profile-picture
|
||||
[initials-avatar
|
||||
{:full-name full-name
|
||||
:size size
|
||||
:draw-ring? draw-ring?
|
||||
:customization-color customization-color}])
|
||||
(when status-indicator?
|
||||
[rn/view
|
||||
{:accessibility-label :status-indicator
|
||||
:style (style/dot size online? draw-ring?)}])]))
|
||||
@@ -204,7 +204,7 @@
|
||||
[button opts \"label\"]
|
||||
opts
|
||||
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
|
||||
:danger/:photo-bg/:blur-bg/:blur-bg-outline/:shell/:community
|
||||
:danger/:photo-bg/:blur-bg/:blur-bg-ouline/:shell/:community
|
||||
:size 40/32/24
|
||||
:icon true/false
|
||||
:community-color '#FFFFFF'
|
||||
@@ -213,14 +213,14 @@
|
||||
:after :icon-keyword}
|
||||
|
||||
only icon
|
||||
[button {:icon true} :i/close-circle]"
|
||||
[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
|
||||
override-theme override-background-color
|
||||
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
|
||||
on-long-press accessibility-label icon icon-no-color style test-ID]
|
||||
:or {type :primary
|
||||
size 40}}
|
||||
children]
|
||||
@@ -275,8 +275,7 @@
|
||||
(community-themed? type community-color)
|
||||
(merge
|
||||
{:background-color community-color}
|
||||
(when (= state :pressed) {:opacity 0.9})))
|
||||
inner-style)}
|
||||
(when (= state :pressed) {:opacity 0.9}))))}
|
||||
(when above
|
||||
[rn/view
|
||||
[quo2.icons/icon above
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn community-card-view-item
|
||||
[{:keys [name description locked images cover
|
||||
status tokens tags width]} on-press]
|
||||
[{:keys [name description locked images
|
||||
status tokens cover tags width]} on-press]
|
||||
[rn/touchable-without-feedback
|
||||
{:accessibility-label :community-card-item
|
||||
:on-press on-press}
|
||||
@@ -18,16 +18,16 @@
|
||||
:on-press on-press}
|
||||
[rn/view
|
||||
{:flex 1}
|
||||
[rn/view (style/community-cover-container 60)
|
||||
[rn/view (style/community-cover-container 40)
|
||||
[rn/image
|
||||
{:source cover
|
||||
:style
|
||||
{:flex 1
|
||||
:border-top-right-radius 20
|
||||
:border-top-left-radius 20}}]]
|
||||
{:flex 1
|
||||
:border-radius 20}}]]
|
||||
[rn/view (style/card-view-content-container 12)
|
||||
[rn/view (style/card-view-chat-icon 48)
|
||||
[icon/community-icon {:images images} 48]]
|
||||
|
||||
(when (= status :gated)
|
||||
[rn/view (style/permission-tag-styles)
|
||||
[community-view/permission-tag-container
|
||||
|
||||
@@ -78,42 +78,42 @@
|
||||
[props
|
||||
{:keys [name
|
||||
muted?
|
||||
unviewed-messages-count
|
||||
unviewed-mentions-count
|
||||
unread-messages?
|
||||
unread-mentions-count
|
||||
status
|
||||
images
|
||||
community-icon
|
||||
tokens
|
||||
locked?
|
||||
style]}]
|
||||
locked?]}]
|
||||
[rn/touchable-highlight
|
||||
(merge {:underlay-color (colors/theme-colors
|
||||
colors/neutral-5
|
||||
colors/neutral-95)
|
||||
:style {:border-radius 12}}
|
||||
props)
|
||||
[rn/view (merge (style/membership-info-container) style)
|
||||
[community-icon/community-icon
|
||||
{:images images} 32]
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:margin-left 12
|
||||
:justify-content :center}
|
||||
[text/text
|
||||
{:accessibility-label :chat-name-text
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
name]]
|
||||
[rn/view {:flex 1}
|
||||
[rn/view (style/membership-info-container)
|
||||
[community-icon/community-icon
|
||||
{:images community-icon} 32]
|
||||
[rn/view
|
||||
{:flex 1
|
||||
:margin-left 12
|
||||
:justify-content :center}
|
||||
[text/text
|
||||
{:accessibility-label :chat-name-text
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:weight :semi-bold
|
||||
:size :paragraph-1}
|
||||
name]]
|
||||
|
||||
[rn/view
|
||||
{:justify-content :center
|
||||
:margin-right 16}
|
||||
(if (= status :gated)
|
||||
[community-view/permission-tag-container
|
||||
{:locked? locked?
|
||||
:tokens tokens}]
|
||||
[notification-view
|
||||
{:muted? muted?
|
||||
:unread-mentions-count unviewed-mentions-count
|
||||
:unread-messages? (pos? unviewed-messages-count)}])]]])
|
||||
[rn/view
|
||||
{:justify-content :center
|
||||
:margin-right 16}
|
||||
(if (= status :gated)
|
||||
[community-view/permission-tag-container
|
||||
{:locked? locked?
|
||||
:tokens tokens}]
|
||||
[notification-view
|
||||
{:muted? muted?
|
||||
:unread-mentions-count unread-mentions-count
|
||||
:unread-messages? unread-messages?}])]]]])
|
||||
|
||||
@@ -42,15 +42,16 @@
|
||||
(defn community-tags
|
||||
[tags]
|
||||
[rn/view (style/community-tags-container)
|
||||
(for [{:keys [name emoji]} tags]
|
||||
^{:key name}
|
||||
(for [{:keys [id tag-label resource]} tags]
|
||||
^{:key id}
|
||||
[rn/view {:margin-right 8}
|
||||
[tag/tag
|
||||
{:size 24
|
||||
:label name
|
||||
{:id id
|
||||
:size 24
|
||||
:label tag-label
|
||||
:type :emoji
|
||||
:labelled? true
|
||||
:resource emoji}]])])
|
||||
:resource resource}]])])
|
||||
|
||||
(defn community-title
|
||||
[{:keys [title description size] :or {size :small}}]
|
||||
@@ -81,5 +82,6 @@
|
||||
colors/neutral-80)
|
||||
:locked? locked?
|
||||
:tokens tokens
|
||||
|
||||
:size 24
|
||||
:on-press on-press}])
|
||||
|
||||
@@ -92,7 +92,6 @@
|
||||
colors/neutral-90)}
|
||||
{:flex-direction :row
|
||||
:margin-horizontal 20
|
||||
:margin-vertical 8
|
||||
:height 56
|
||||
:padding-right 12})
|
||||
[card-title-and-description title description]
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
:shadow-radius radius
|
||||
:shadow-opacity 1
|
||||
:shadow-color colors/shadow
|
||||
:elevation 1
|
||||
:border-radius radius
|
||||
:justify-content :space-between
|
||||
:elevation 2
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)})
|
||||
@@ -57,18 +57,14 @@
|
||||
|
||||
(defn card-view-content-container
|
||||
[padding-horizontal]
|
||||
{:position :absolute
|
||||
:top 40
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:height 20
|
||||
:padding-horizontal padding-horizontal
|
||||
:border-top-right-radius 16
|
||||
:border-top-left-radius 16
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)})
|
||||
{:flex 1
|
||||
:height 20
|
||||
:padding-left padding-horizontal
|
||||
:padding-right padding-horizontal
|
||||
:border-radius 16
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-90)})
|
||||
|
||||
(defn card-view-chat-icon
|
||||
[icon-size]
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
(ns quo2.components.counter.--tests--.counter-component-spec
|
||||
(:require [quo2.components.counter.counter :as counter]
|
||||
[test-helpers.component :as h]))
|
||||
(:require ["@testing-library/react-native" :as rtl]
|
||||
[quo2.components.counter.counter :as counter]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(h/describe "counter component"
|
||||
(h/test "default render of counter component"
|
||||
(h/render [counter/counter {} nil])
|
||||
(-> (h/expect (h/get-by-test-id :counter-component))
|
||||
(h/is-truthy)))
|
||||
(defn render-counter
|
||||
([]
|
||||
(render-counter {} nil))
|
||||
([opts value]
|
||||
(rtl/render (reagent/as-element [counter/counter opts value]))))
|
||||
|
||||
(h/test "renders counter with a string value"
|
||||
(h/render [counter/counter {} "1"])
|
||||
(-> (h/expect (h/get-by-text "1"))
|
||||
(h/is-truthy)))
|
||||
(js/global.test "default render of counter component"
|
||||
(fn []
|
||||
(render-counter)
|
||||
(-> (js/expect (rtl/screen.getByTestId "counter-component"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(h/test "renders counter with an integer value"
|
||||
(h/render [counter/counter {} 1])
|
||||
(-> (h/expect (h/get-by-text "1"))
|
||||
(h/is-truthy)))
|
||||
(js/global.test "renders counter with a string value"
|
||||
(fn []
|
||||
(render-counter {} "1")
|
||||
(-> (js/expect (rtl/screen.getByText "1"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(h/test "renders counter with max value 99+ by default"
|
||||
(h/render [counter/counter {} 100])
|
||||
(-> (h/expect (h/get-by-text "99+"))
|
||||
(h/is-truthy)))
|
||||
(js/global.test "renders counter with an integer value"
|
||||
(fn []
|
||||
(render-counter {} 1)
|
||||
(-> (js/expect (rtl/screen.getByText "1"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(h/test "renders counter with custom max value when set to 150"
|
||||
(h/render [counter/counter {:max-value 150} 151])
|
||||
(-> (h/expect (h/get-by-text "150+"))
|
||||
(h/is-truthy))))
|
||||
(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))))
|
||||
@@ -1,10 +1,8 @@
|
||||
(ns quo2.components.counter.counter
|
||||
(:require
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]
|
||||
[utils.number :as utils-number]))
|
||||
(:require [quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def themes
|
||||
{:light {:default colors/primary-50
|
||||
@@ -21,9 +19,9 @@
|
||||
(get-in themes [(theme/get-theme) key]))
|
||||
|
||||
(defn counter
|
||||
[{:keys [type override-text-color override-bg-color style accessibility-label max-value]
|
||||
:or {max-value 99}}
|
||||
value]
|
||||
"type: default, secondary, grey, outline
|
||||
value: integer"
|
||||
[{:keys [type override-text-color override-bg-color style accessibility-label]} value]
|
||||
(let [type (or type :default)
|
||||
text-color (or override-text-color
|
||||
(if (or
|
||||
@@ -31,9 +29,11 @@
|
||||
(= type :default))
|
||||
colors/white
|
||||
colors/neutral-100))
|
||||
value (utils-number/parse-int value)
|
||||
label (if (> value max-value)
|
||||
(str max-value "+")
|
||||
value (if (integer? value)
|
||||
value
|
||||
(js/parseInt value))
|
||||
label (if (> value 99)
|
||||
"99+"
|
||||
(str value))
|
||||
width (case (count label)
|
||||
1 16
|
||||
@@ -59,7 +59,7 @@
|
||||
(or override-bg-color
|
||||
(get-color type)))
|
||||
|
||||
(> value max-value)
|
||||
(> value 99)
|
||||
(assoc :padding-left 0.5))}
|
||||
[text/text
|
||||
{:weight :medium
|
||||
|
||||
@@ -4,24 +4,22 @@
|
||||
(def outer-container {:height 216})
|
||||
|
||||
(def top-card
|
||||
{:flex 1
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:background-color colors/neutral-80})
|
||||
{:flex 1
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-radius 20
|
||||
:background-color colors/neutral-80})
|
||||
|
||||
(def bottom-card
|
||||
{:position :absolute
|
||||
:top 80
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-top-left-radius 20
|
||||
:border-top-right-radius 20
|
||||
:background-color (colors/alpha colors/white 0.05)})
|
||||
{:position :absolute
|
||||
:top 80
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-radius 20
|
||||
:background-color (colors/alpha colors/white 0.05)})
|
||||
|
||||
(def bottom-container
|
||||
{:flex-direction :row
|
||||
|
||||
@@ -39,14 +39,13 @@
|
||||
children))
|
||||
|
||||
(defn card
|
||||
[{:keys [on-press style heading gap accessibility-label top?]} children]
|
||||
[{:keys [on-press style heading gap top?]} children]
|
||||
[rn/touchable-highlight
|
||||
{:accessibility-label accessibility-label
|
||||
:on-press on-press
|
||||
:border-radius 20
|
||||
:style style
|
||||
:underlay-color (:background-color style)}
|
||||
[rn/view
|
||||
{:on-press on-press
|
||||
:border-radius 20
|
||||
:style style
|
||||
:underlay-color (:background-color style)}
|
||||
[rn/view {}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:style (style/heading-text gap)
|
||||
@@ -61,11 +60,9 @@
|
||||
opts
|
||||
{:container-style style-object
|
||||
:top-card { :on-press event
|
||||
:heading string
|
||||
:accessibility-label keyword}
|
||||
:heading string}
|
||||
:bottom-card { :on-press event
|
||||
:heading string
|
||||
:accessibility-label keyword}}
|
||||
:heading string}}
|
||||
child-1 string, keyword or hiccup
|
||||
child-2 string, keyword or hiccup
|
||||
"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns quo2.components.inputs.input.style
|
||||
(ns quo2.components.input.style
|
||||
(:require [quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns quo2.components.inputs.input.view
|
||||
(ns quo2.components.input.view
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.inputs.input.style :as style]
|
||||
[quo2.components.input.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]))
|
||||
@@ -1,29 +0,0 @@
|
||||
(ns quo2.components.inputs.profile-input.component-spec
|
||||
(:require [quo2.components.inputs.profile-input.view :as profile-input]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "Profile Input"
|
||||
(h/test "renders user avatar with placeholder name if no value is specified"
|
||||
(h/render [profile-input/profile-input
|
||||
{:placeholder "Your Name"}])
|
||||
(-> (js/expect (h/get-by-text "YN"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "renders user avatar with full name if a value is specified"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [profile-input/profile-input
|
||||
{:on-change event
|
||||
:placeholder "Your Name"
|
||||
:image-picker-props {:full-name "Test Name"}}])
|
||||
(h/fire-event :change (h/get-by-text "TN"))
|
||||
(-> (js/expect (h/get-by-text "TN"))
|
||||
(.toBeTruthy))))
|
||||
|
||||
(h/test "on press event fires"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [profile-input/profile-input
|
||||
{:placeholder "Your Name"
|
||||
:on-press event}])
|
||||
(h/fire-event :press (h/get-by-label-text :select-profile-picture-button))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
@@ -1,29 +0,0 @@
|
||||
(ns quo2.components.inputs.profile-input.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn container
|
||||
[customization-color]
|
||||
{:background-color (colors/custom-color customization-color 50 40)
|
||||
:padding-horizontal 12
|
||||
:padding-top 12
|
||||
:padding-bottom 10
|
||||
:border-radius 16
|
||||
:height 102
|
||||
:flex 1})
|
||||
|
||||
(def button
|
||||
{:position :absolute
|
||||
:top 23
|
||||
:bottom 0
|
||||
:left 33
|
||||
:right 0
|
||||
:width 24
|
||||
:height 24
|
||||
:border-radius 24})
|
||||
|
||||
(def button-inner {:border-radius 24})
|
||||
|
||||
(def input-container
|
||||
{:flex-direction :row
|
||||
:margin-top 4
|
||||
:align-items :center})
|
||||
@@ -1,51 +0,0 @@
|
||||
(ns quo2.components.inputs.profile-input.view
|
||||
(:require
|
||||
[quo2.components.buttons.button :as buttons]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.inputs.profile-input.style :as style]
|
||||
[quo2.components.inputs.title-input.view :as title-input]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hole-view :as hole-view]))
|
||||
|
||||
(defn profile-input
|
||||
[{:keys [customization-color
|
||||
placeholder
|
||||
on-press
|
||||
title-input-props
|
||||
image-picker-props]}]
|
||||
(let [full-name (:full-name image-picker-props)]
|
||||
[rn/view
|
||||
{:style (style/container customization-color)}
|
||||
[rn/view
|
||||
[hole-view/hole-view
|
||||
{:holes [{:x 33
|
||||
:y 23
|
||||
:width 24
|
||||
:height 24
|
||||
:borderRadius 12}]}
|
||||
[user-avatar/user-avatar
|
||||
(merge image-picker-props
|
||||
{:customization-color customization-color
|
||||
:full-name (if (seq full-name)
|
||||
full-name
|
||||
placeholder)
|
||||
:status-indicator? false
|
||||
:size :medium})]]
|
||||
[buttons/button
|
||||
{:accessibility-label :select-profile-picture-button
|
||||
:type :grey
|
||||
:override-theme :dark
|
||||
:override-background-color (colors/alpha colors/white 0.05)
|
||||
:on-press on-press
|
||||
:icon-size 20
|
||||
:width 24
|
||||
:size 24
|
||||
:icon :i/camera
|
||||
:style style/button
|
||||
:inner-style style/button-inner} :i/camera]]
|
||||
[rn/view {:style style/input-container}
|
||||
[title-input/title-input
|
||||
(merge title-input-props
|
||||
{:placeholder placeholder
|
||||
:customization-color customization-color})]]]))
|
||||
@@ -1,40 +0,0 @@
|
||||
(ns quo2.components.inputs.title-input.component-spec
|
||||
(:require [quo2.components.inputs.title-input.view :as title-input]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "profile: title-input"
|
||||
(h/test "renders empty"
|
||||
(h/render [title-input/title-input
|
||||
{:value ""
|
||||
:on-change-text (h/mock-fn)}])
|
||||
(-> (js/expect (h/get-by-label-text :profile-title-input))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "empty text renders with max length digits and 00"
|
||||
(h/render [title-input/title-input
|
||||
{:value ""
|
||||
:max-length 24
|
||||
:on-change-text (h/mock-fn)}])
|
||||
(-> (js/expect (h/get-by-text "00"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (h/get-by-text "/24"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "renders with max length digits and character count"
|
||||
(h/render [title-input/title-input
|
||||
{:default-value "abc"
|
||||
:max-length 24
|
||||
:on-change-text (h/mock-fn)} "abc"])
|
||||
(-> (js/expect (h/get-by-text "03"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (h/get-by-text "/24"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "text updates on change"
|
||||
(let [on-change-text (h/mock-fn)]
|
||||
(h/render [title-input/title-input
|
||||
{:value "mock text"
|
||||
:on-change-text on-change-text}])
|
||||
(h/fire-event :change-text (h/get-by-label-text :profile-title-input) "mock-text-new")
|
||||
(-> (js/expect on-change-text)
|
||||
(.toHaveBeenCalled)))))
|
||||
@@ -1,52 +0,0 @@
|
||||
(ns quo2.components.inputs.title-input.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn get-focused-placeholder-color
|
||||
[blur?]
|
||||
(if blur?
|
||||
(colors/theme-colors colors/neutral-80-opa-20 (colors/alpha colors/white 0.2))
|
||||
(colors/theme-colors colors/neutral-30 colors/neutral-60)))
|
||||
|
||||
(defn get-placeholder-color
|
||||
[blur?]
|
||||
(if blur?
|
||||
(colors/theme-colors colors/neutral-80-opa-40 (colors/alpha colors/white 0.3))
|
||||
(colors/theme-colors colors/neutral-40 colors/neutral-50)))
|
||||
|
||||
(defn- get-disabled-color
|
||||
[blur?]
|
||||
(if blur?
|
||||
(colors/theme-colors colors/neutral-80-opa-40 (colors/alpha colors/white 0.3))
|
||||
(colors/theme-colors colors/neutral-40 colors/neutral-50)))
|
||||
|
||||
(defn- get-char-count-color
|
||||
[blur?]
|
||||
(if blur?
|
||||
(colors/theme-colors colors/neutral-80-opa-40 (colors/alpha colors/white 0.4))
|
||||
(colors/theme-colors colors/neutral-40 colors/neutral-50)))
|
||||
|
||||
(defn get-selection-color
|
||||
[customization-color blur?]
|
||||
(if blur?
|
||||
(colors/theme-colors colors/neutral-100 colors/white)
|
||||
(colors/custom-color customization-color (if colors/dark? 60 50))))
|
||||
|
||||
(def text-input-container {:flex 1})
|
||||
|
||||
(defn title-text
|
||||
[disabled? blur?]
|
||||
{:text-align-vertical :bottom
|
||||
:color (when disabled? (get-disabled-color blur?))})
|
||||
|
||||
(defn char-count
|
||||
[blur?]
|
||||
{:color (get-char-count-color blur?)})
|
||||
|
||||
(def container
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(def counter-container
|
||||
{:padding-top 8})
|
||||
@@ -1,65 +0,0 @@
|
||||
(ns quo2.components.inputs.title-input.view
|
||||
(:require
|
||||
[quo2.components.inputs.title-input.style :as style]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[reagent.core :as reagent]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn- pad-0
|
||||
[value]
|
||||
(if (<= (count value) 1)
|
||||
(str 0 value)
|
||||
value))
|
||||
|
||||
(defn title-input
|
||||
[{:keys [blur?
|
||||
on-change-text
|
||||
placeholder
|
||||
max-length
|
||||
default-value]
|
||||
:or {max-length 0
|
||||
default-value ""}}]
|
||||
(let [focused? (reagent/atom false)
|
||||
value (reagent/atom default-value)
|
||||
on-change (fn [v]
|
||||
(reset! value v)
|
||||
(when on-change-text
|
||||
(on-change-text v)))]
|
||||
(fn [{:keys [customization-color disabled?]}]
|
||||
[rn/view
|
||||
{:style style/container}
|
||||
[rn/view {:style style/text-input-container}
|
||||
[rn/text-input
|
||||
{:style
|
||||
(text/text-style
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
:style (style/title-text disabled? blur?)})
|
||||
:default-value default-value
|
||||
:accessibility-label :profile-title-input
|
||||
:on-focus #(swap! focused? (fn [] true))
|
||||
:on-blur #(swap! focused? (fn [] false))
|
||||
:input-mode :text
|
||||
:on-change-text on-change
|
||||
:editable (not disabled?)
|
||||
:max-length max-length
|
||||
:placeholder placeholder
|
||||
:selection-color (style/get-selection-color customization-color blur?)
|
||||
:placeholder-text-color (if @focused?
|
||||
(style/get-focused-placeholder-color blur?)
|
||||
(style/get-placeholder-color blur?))}]]
|
||||
[rn/view
|
||||
{:style style/counter-container}
|
||||
[text/text
|
||||
[text/text
|
||||
{:style (style/char-count blur?)
|
||||
:size :paragraph-2}
|
||||
(pad-0
|
||||
(str
|
||||
(count @value)))]
|
||||
[text/text
|
||||
{:style (style/char-count blur?)
|
||||
:size :paragraph-2}
|
||||
(str "/"
|
||||
(pad-0
|
||||
(str max-length)))]]]])))
|
||||
@@ -1,5 +1,5 @@
|
||||
(ns quo2.components.list-items.preview-list
|
||||
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
(:require [quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.icon :as quo2.icons]
|
||||
[quo2.components.markdown.text :as quo2.text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns quo2.components.list-items.user-list
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.foundations.colors :as colors]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns quo2.components.messages.system-message
|
||||
(:require [quo2.components.avatars.icon-avatar :as icon-avatar]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :as theme]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns quo2.components.navigation.page-nav
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
@@ -30,7 +30,7 @@
|
||||
{:no-color true})))
|
||||
|
||||
(defn left-section-view
|
||||
[{:keys [on-press icon accessibility-label type icon-override-theme] :or {type :grey}}
|
||||
[{: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
|
||||
@@ -38,8 +38,7 @@
|
||||
:icon true
|
||||
:type type
|
||||
:size 32
|
||||
:accessibility-label accessibility-label
|
||||
:override-theme icon-override-theme}
|
||||
:accessibility-label accessibility-label}
|
||||
icon]])
|
||||
|
||||
(defn- mid-section-comp
|
||||
@@ -149,20 +148,10 @@
|
||||
:flex-direction :row
|
||||
:justify-content :flex-end)}
|
||||
(let [last-icon-index (-> right-section-buttons count dec)]
|
||||
(map-indexed (fn [index
|
||||
{:keys [icon on-press type style icon-override-theme]
|
||||
:or {type :grey}}]
|
||||
(map-indexed (fn [index {:keys [icon on-press type style] :or {type :grey}}]
|
||||
^{:key index}
|
||||
[rn/view
|
||||
{:style (assoc style
|
||||
:margin-right
|
||||
(if (= index last-icon-index) 0 8))}
|
||||
[button/button
|
||||
{:on-press on-press
|
||||
:icon true
|
||||
:type type
|
||||
:size 32
|
||||
:override-theme icon-override-theme}
|
||||
[rn/view {:style (merge {:margin-right (if (not= index last-icon-index) 8 0)} style)}
|
||||
[button/button {:on-press on-press :icon true :type type :size 32}
|
||||
icon]])
|
||||
right-section-buttons))])
|
||||
|
||||
@@ -190,14 +179,16 @@
|
||||
:left-section
|
||||
{:type button-type
|
||||
:on-press event
|
||||
:icon icon
|
||||
:icon-override-theme :light/:dark
|
||||
:icon icon
|
||||
:icon-color color
|
||||
:icon-background-color color
|
||||
}
|
||||
:right-section-buttons vector of
|
||||
{:type button-type
|
||||
:on-press event
|
||||
:icon icon
|
||||
:icon-override-theme :light/:dark
|
||||
:icon-color color
|
||||
:icon-background-color color
|
||||
}
|
||||
}
|
||||
"
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
[quo2.components.notifications.activity-log.style :as style]
|
||||
[quo2.components.tags.status-tags :as status-tags]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[utils.i18n :as i18n]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]))
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn- activity-reply-text-input
|
||||
[{:keys [on-update-reply max-reply-length valid-reply?]} reply-input]
|
||||
@@ -37,7 +37,7 @@
|
||||
(when on-update-reply
|
||||
(on-update-reply %)))
|
||||
:auto-capitalize :none
|
||||
:auto-focus false
|
||||
:auto-focus true
|
||||
:accessibility-label :identity-verification-reply-text-input
|
||||
:placeholder (i18n/label :t/type-something)
|
||||
:return-key-type :none
|
||||
@@ -129,20 +129,19 @@
|
||||
(-> button
|
||||
(assoc :size size)
|
||||
(assoc :type subtype)
|
||||
(assoc :disabled (and replying? disable-when (disable-when @reply-input)))
|
||||
(assoc :disabled (and replying? (disable-when @reply-input)))
|
||||
(update :style merge common-style {:margin-right 8}))
|
||||
label]))
|
||||
|
||||
(defmethod footer-item-view :status
|
||||
[{:keys [label subtype blur?]} _ _]
|
||||
[{:keys [label subtype]} _ _]
|
||||
[status-tags/status-tag
|
||||
{:size :small
|
||||
:label label
|
||||
:status {:type subtype}
|
||||
:blur? blur?}])
|
||||
:status {:type subtype}}])
|
||||
|
||||
(defn- footer
|
||||
[_]
|
||||
[_ _]
|
||||
(let [reply-input (reagent/atom "")]
|
||||
(fn [{:keys [replying? items] :as props}]
|
||||
[:<>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
(ns quo2.components.onboarding.small-option-card.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def main-variant-height 335)
|
||||
(def icon-variant-height 56)
|
||||
|
||||
(def text-container {:flex 1})
|
||||
|
||||
(def title
|
||||
@@ -44,10 +41,12 @@
|
||||
|
||||
(def touchable-overlay {:border-radius 16})
|
||||
|
||||
(defn card-container
|
||||
[main-variant?]
|
||||
(when main-variant? {:height 343}))
|
||||
|
||||
(defn card
|
||||
[height]
|
||||
[main-variant?]
|
||||
{:background-color colors/white-opa-5
|
||||
:border-radius 16
|
||||
:height height})
|
||||
|
||||
(def main-variant-extra-space {:height 8})
|
||||
:height (if main-variant? 335 56)})
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
:subtitle subtitle}]])
|
||||
|
||||
(defn- main-variant
|
||||
[{:keys [title subtitle image max-height]}]
|
||||
[{:keys [title subtitle image]}]
|
||||
[rn/view {:style style/main-variant}
|
||||
[rn/view {:style style/main-variant-text-container}
|
||||
[texts
|
||||
@@ -43,32 +43,24 @@
|
||||
:subtitle subtitle}]]
|
||||
[fast-image/fast-image
|
||||
{:accessibility-label :small-option-card-main-image
|
||||
:style {:flex 1 :max-height max-height}
|
||||
:style {:flex 1}
|
||||
:resize-mode :contain
|
||||
:source image}]])
|
||||
|
||||
(defn small-option-card
|
||||
"Variants: `:main` or `:icon`"
|
||||
[{:keys [variant title subtitle image max-height on-press]
|
||||
[{:keys [variant title subtitle image on-press]
|
||||
:or {variant :main}}]
|
||||
(let [main-variant? (= variant :main)
|
||||
card-component (if main-variant? main-variant icon-variant)
|
||||
card-height (cond
|
||||
(not main-variant?) style/icon-variant-height
|
||||
max-height (min max-height style/main-variant-height)
|
||||
:else style/main-variant-height)]
|
||||
[rn/view
|
||||
[rn/touchable-highlight
|
||||
{:accessibility-label :small-option-card
|
||||
:style style/touchable-overlay
|
||||
:active-opacity 1
|
||||
:underlay-color colors/white-opa-5
|
||||
:on-press on-press}
|
||||
[rn/view {:style (style/card card-height)}
|
||||
card-component (if main-variant? main-variant icon-variant)]
|
||||
[rn/touchable-highlight
|
||||
{:accessibility-label :small-option-card
|
||||
:style style/touchable-overlay
|
||||
:active-opacity 1
|
||||
:underlay-color colors/white-opa-5
|
||||
:on-press on-press}
|
||||
[rn/view {:style (style/card-container main-variant?)}
|
||||
[rn/view {:style (style/card main-variant?)}
|
||||
[card-component
|
||||
{:title title
|
||||
:subtitle subtitle
|
||||
:image image
|
||||
:max-height max-height}]]]
|
||||
(when main-variant?
|
||||
[rn/view {:style style/main-variant-extra-space}])]))
|
||||
{:title title
|
||||
:subtitle subtitle
|
||||
:image image}]]]]))
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn card-container
|
||||
[customization-color padding-bottom]
|
||||
{:flex-direction :column
|
||||
:padding-horizontal 12
|
||||
:padding-top 12
|
||||
:padding-bottom padding-bottom
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:background-color (colors/custom-color customization-color 50 40)})
|
||||
[customization-color]
|
||||
{:flex-direction :column
|
||||
:padding 12
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:background-color (colors/custom-color customization-color 50 40)})
|
||||
|
||||
(def card-header
|
||||
{:flex-direction :row
|
||||
@@ -18,23 +16,25 @@
|
||||
(def name-container
|
||||
{:flex-direction :row
|
||||
:margin-top 8
|
||||
:margin-bottom 2
|
||||
:align-items :center
|
||||
:padding-right 12})
|
||||
|
||||
(def user-name
|
||||
{:color colors/white})
|
||||
{:margin-right 4
|
||||
:color colors/white})
|
||||
|
||||
(def emoji-hash
|
||||
{:margin-top 12})
|
||||
{:margin-top 10})
|
||||
|
||||
(def user-hash
|
||||
{:margin-top 2
|
||||
:color colors/white-opa-60})
|
||||
{:color colors/white-opa-60})
|
||||
|
||||
(def sign-button
|
||||
{:margin-top 14})
|
||||
|
||||
(def keycard-icon
|
||||
{:margin-left 4
|
||||
:color colors/white-opa-40})
|
||||
{:color colors/white-opa-40})
|
||||
|
||||
(def option-button
|
||||
{:background-color colors/white-opa-5
|
||||
:margin-left 8})
|
||||
{:background-color colors/white-opa-5})
|
||||
|
||||
@@ -1,80 +1,63 @@
|
||||
(ns quo2.components.profile.profile-card.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[react-native.core :as rn]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.tags.tag :as tag]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.profile.profile-card.style :as style]))
|
||||
(:require
|
||||
[quo2.components.profile.profile-card.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
|
||||
(defn profile-card
|
||||
[{:keys [key-card? profile-picture name hash customization-color
|
||||
emoji-hash on-options-press show-emoji-hash? padding-bottom
|
||||
show-options-button? show-user-hash? show-logged-in? on-card-press]
|
||||
:or {show-emoji-hash? false
|
||||
show-user-hash? false
|
||||
customization-color :turquoise
|
||||
show-options-button? false
|
||||
show-logged-in? false
|
||||
key-card? false}}]
|
||||
[rn/touchable-without-feedback
|
||||
{:on-press on-card-press
|
||||
:flex 1
|
||||
:accessibility-label :profile-card}
|
||||
[{:keys [show-sign-profile? key-card? profile-picture name hash customization-color sign-label
|
||||
emoji-hash on-press-dots on-press-sign show-emoji-hash?]
|
||||
:or {show-sign-profile? false
|
||||
show-emoji-hash? false
|
||||
customization-color :turquoise
|
||||
key-card? false}}]
|
||||
[rn/view
|
||||
{:style (style/card-container customization-color)}
|
||||
[rn/view
|
||||
(style/card-container
|
||||
customization-color
|
||||
(or padding-bottom (if show-emoji-hash? 12 10)))
|
||||
[rn/view
|
||||
{:style style/card-header}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name name
|
||||
:profile-picture profile-picture
|
||||
:override-theme :dark
|
||||
:size :medium
|
||||
:status-indicator? false}]
|
||||
[rn/view {:flex-direction :row}
|
||||
(when show-logged-in?
|
||||
[tag/tag
|
||||
{:type :icon
|
||||
:size 32
|
||||
:blurred? true
|
||||
:labelled? true
|
||||
:resource :main-icons2/check
|
||||
:accessibility-label :logged-in-tag
|
||||
:icon-color colors/success-50
|
||||
:override-theme :dark
|
||||
:label (i18n/label :t/logged-in)}])
|
||||
(when show-options-button?
|
||||
[button/button
|
||||
{:size 32
|
||||
:type :blur-bg
|
||||
:icon true
|
||||
:override-theme :dark
|
||||
:style style/option-button
|
||||
:on-press on-options-press
|
||||
:accessibility-label :profile-card-options}
|
||||
:i/options])]]
|
||||
[rn/view
|
||||
{:style style/name-container}
|
||||
{:style style/card-header}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name name
|
||||
:profile-picture profile-picture
|
||||
:override-theme :dark
|
||||
:size :medium
|
||||
:status-indicator? false}]
|
||||
[button/button
|
||||
{:size 32
|
||||
:type :blur-bg
|
||||
:icon true
|
||||
:override-theme :dark
|
||||
:style style/option-button
|
||||
:on-press on-press-dots}
|
||||
:i/options]]
|
||||
[rn/view
|
||||
{:style style/name-container}
|
||||
[text/text
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
:number-of-lines 1
|
||||
:style style/user-name} name]
|
||||
(when key-card?
|
||||
(icon/icon
|
||||
:i/keycard
|
||||
style/keycard-icon))]
|
||||
[text/text
|
||||
{:weight :monospace
|
||||
:number-of-lines 1
|
||||
:style style/user-hash} hash]
|
||||
(when (and show-emoji-hash? emoji-hash)
|
||||
[text/text
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
{:weight :monospace
|
||||
:number-of-lines 1
|
||||
:style style/user-name} name]
|
||||
(when key-card?
|
||||
(icon/icon
|
||||
:i/keycard
|
||||
style/keycard-icon))]
|
||||
(when show-user-hash?
|
||||
[text/text
|
||||
{:weight :monospace
|
||||
:number-of-lines 1
|
||||
:style style/user-hash} hash])
|
||||
(when (and show-emoji-hash? emoji-hash)
|
||||
[text/text
|
||||
{:weight :monospace
|
||||
:number-of-lines 1
|
||||
:style style/emoji-hash} emoji-hash])]])
|
||||
:style style/emoji-hash} emoji-hash])
|
||||
(when show-sign-profile?
|
||||
[button/button
|
||||
{:on-press on-press-sign
|
||||
:type :community
|
||||
:community-color (colors/custom-color customization-color 60)
|
||||
:community-text-color colors/white
|
||||
:style style/sign-button} sign-label])])
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[quo2.components.profile.select-profile.style :as style]
|
||||
[react-native.core :as rn]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn- on-change-handler
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
:locationY 70}})
|
||||
(-> (h/expect event)
|
||||
(.toHaveBeenCalledTimes 1))))
|
||||
|
||||
@@ -37,23 +36,19 @@
|
||||
(h/render [record-audio/record-audio
|
||||
{:on-reviewing-audio event
|
||||
:record-audio-permission-granted true}])
|
||||
(with-redefs [audio/start-recording (fn [_ on-start _]
|
||||
(on-start))
|
||||
audio/get-recorder-file-path (fn [] "file-path")]
|
||||
(with-redefs [audio/start-recording (fn [_ on-start _]
|
||||
(on-start))]
|
||||
(h/fire-event
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
:locationY 70}})
|
||||
(h/advance-timers-by-time 500)
|
||||
(h/fire-event
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 200}})
|
||||
(h/advance-timers-by-time 250)
|
||||
:locationY 70}})
|
||||
(-> (h/expect event)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
|
||||
@@ -64,40 +59,27 @@
|
||||
:record-audio-permission-granted true}])
|
||||
(with-redefs [audio/start-recording (fn [_ on-start _]
|
||||
(on-start))
|
||||
audio/get-recorder-file-path (fn [] "audio-file-path")
|
||||
audio/get-player-duration (fn [] 5000)]
|
||||
audio/get-recorder-file-path (fn [] "audio-file-path")]
|
||||
(h/fire-event
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
:locationY 70}})
|
||||
(h/advance-timers-by-time 500)
|
||||
(h/fire-event
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 200}})
|
||||
(h/fire-event
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
(h/advance-timers-by-time 500)
|
||||
:locationY 70}})
|
||||
(h/fire-event
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 80
|
||||
:locationY 80
|
||||
:timestamp 200}})
|
||||
(h/advance-timers-by-time 250)
|
||||
:locationY 80}})
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledTimes 1))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledWith {:file-path "audio-file-path"
|
||||
:duration 5000})))))
|
||||
(.toHaveBeenCalledWith "audio-file-path")))))
|
||||
|
||||
(h/test "record-audio on-send works after sliding to the send button"
|
||||
(let [event (js/jest.fn)]
|
||||
@@ -113,8 +95,7 @@
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
:locationY 70}})
|
||||
(h/advance-timers-by-time 500)
|
||||
(h/fire-event
|
||||
:on-responder-move
|
||||
@@ -127,14 +108,11 @@
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 40
|
||||
:locationY 80
|
||||
:timestamp 200}})
|
||||
(h/advance-timers-by-time 250)
|
||||
:locationY 80}})
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledTimes 1))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledWith {:file-path "audio-file-path"
|
||||
:duration 500})))))
|
||||
(.toHaveBeenCalledWith "audio-file-path")))))
|
||||
|
||||
(h/test "record-audio on-cancel works after reviewing audio"
|
||||
(let [event (js/jest.fn)]
|
||||
@@ -147,22 +125,18 @@
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
:locationY 70}})
|
||||
(h/advance-timers-by-time 500)
|
||||
(h/fire-event
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 200}})
|
||||
:locationY 70}})
|
||||
(h/fire-event
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 40
|
||||
:locationY 80
|
||||
:timestamp 200}})
|
||||
(h/advance-timers-by-time 250)
|
||||
:locationY 80}})
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledTimes 1)))))
|
||||
|
||||
@@ -179,8 +153,7 @@
|
||||
:on-start-should-set-responder
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX 70
|
||||
:locationY 70
|
||||
:timestamp 0}})
|
||||
:locationY 70}})
|
||||
(h/advance-timers-by-time 500)
|
||||
(h/fire-event
|
||||
:on-responder-move
|
||||
@@ -193,8 +166,6 @@
|
||||
:on-responder-release
|
||||
(h/get-by-test-id "record-audio")
|
||||
{:nativeEvent {:locationX -10
|
||||
:locationY 70
|
||||
:timestamp 200}})
|
||||
(h/advance-timers-by-time 250)
|
||||
:locationY 70}})
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalledTimes 1))))))
|
||||
|
||||
@@ -4,60 +4,58 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.core :refer [use-effect]]
|
||||
[quo2.components.record-audio.record-audio.helpers :as helpers]))
|
||||
[quo2.components.record-audio.record-audio.helpers :refer
|
||||
[animate-linear-with-delay
|
||||
animate-easing-with-delay
|
||||
animate-linear
|
||||
set-value]]))
|
||||
|
||||
(defn delete-button
|
||||
[recording? ready-to-delete? reviewing-audio? force-show-controls?]
|
||||
[recording? ready-to-delete? reviewing-audio?]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [opacity (reanimated/use-shared-value (if force-show-controls? 1 0))
|
||||
translate-x (reanimated/use-shared-value (if force-show-controls? 35 20))
|
||||
scale (reanimated/use-shared-value (if force-show-controls? 0.75 1))
|
||||
(let [opacity (reanimated/use-shared-value 0)
|
||||
translate-x (reanimated/use-shared-value 20)
|
||||
scale (reanimated/use-shared-value 1)
|
||||
connector-opacity (reanimated/use-shared-value 0)
|
||||
connector-width (reanimated/use-shared-value 24)
|
||||
connector-height (reanimated/use-shared-value 12)
|
||||
border-radius-first-half (reanimated/use-shared-value 8)
|
||||
border-radius-second-half (reanimated/use-shared-value 8)
|
||||
start-x-animation (fn []
|
||||
(helpers/animate-linear-with-delay translate-x 12 50 133.33)
|
||||
(helpers/animate-easing-with-delay connector-opacity 1 0 93.33)
|
||||
(helpers/animate-easing-with-delay connector-width 56 83.33 80)
|
||||
(helpers/animate-easing-with-delay connector-height 56 83.33 80)
|
||||
(helpers/animate-easing-with-delay border-radius-first-half
|
||||
28
|
||||
83.33
|
||||
80)
|
||||
(helpers/animate-easing-with-delay border-radius-second-half
|
||||
28
|
||||
83.33
|
||||
80))
|
||||
(animate-linear-with-delay translate-x 12 50 133.33)
|
||||
(animate-easing-with-delay connector-opacity 1 0 93.33)
|
||||
(animate-easing-with-delay connector-width 56 83.33 80)
|
||||
(animate-easing-with-delay connector-height 56 83.33 80)
|
||||
(animate-easing-with-delay border-radius-first-half 28 83.33 80)
|
||||
(animate-easing-with-delay border-radius-second-half 28 83.33 80))
|
||||
reset-x-animation (fn []
|
||||
(helpers/animate-linear translate-x 0 100)
|
||||
(helpers/set-value connector-opacity 0)
|
||||
(helpers/set-value connector-width 24)
|
||||
(helpers/set-value connector-height 12)
|
||||
(helpers/set-value border-radius-first-half 8)
|
||||
(helpers/set-value border-radius-second-half 16))
|
||||
(animate-linear translate-x 0 100)
|
||||
(set-value connector-opacity 0)
|
||||
(set-value connector-width 24)
|
||||
(set-value connector-height 12)
|
||||
(set-value border-radius-first-half 8)
|
||||
(set-value border-radius-second-half 16))
|
||||
fade-in-animation (fn []
|
||||
(helpers/animate-linear translate-x 0 200)
|
||||
(helpers/animate-linear opacity 1 200))
|
||||
(animate-linear translate-x 0 200)
|
||||
(animate-linear opacity 1 200))
|
||||
fade-out-animation (fn []
|
||||
(helpers/animate-linear
|
||||
(animate-linear
|
||||
translate-x
|
||||
(if @reviewing-audio? 35 20)
|
||||
200)
|
||||
(if @reviewing-audio?
|
||||
(helpers/animate-linear scale 0.75 200)
|
||||
(helpers/animate-linear opacity 0 200))
|
||||
(helpers/set-value connector-opacity 0)
|
||||
(helpers/set-value connector-width 24)
|
||||
(helpers/set-value connector-height 12)
|
||||
(helpers/set-value border-radius-first-half 8)
|
||||
(helpers/set-value border-radius-second-half 16))
|
||||
(animate-linear scale 0.75 200)
|
||||
(animate-linear opacity 0 200))
|
||||
(set-value connector-opacity 0)
|
||||
(set-value connector-width 24)
|
||||
(set-value connector-height 12)
|
||||
(set-value border-radius-first-half 8)
|
||||
(set-value border-radius-second-half 16))
|
||||
fade-out-reset-animation (fn []
|
||||
(helpers/animate-linear opacity 0 200)
|
||||
(helpers/animate-linear-with-delay translate-x 20 0 200)
|
||||
(helpers/animate-linear-with-delay scale 1 0 200))]
|
||||
(animate-linear opacity 0 200)
|
||||
(animate-linear-with-delay translate-x 20 0 200)
|
||||
(animate-linear-with-delay scale 1 0 200))]
|
||||
(use-effect (fn []
|
||||
(if @recording?
|
||||
(fade-in-animation)
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.core :refer [use-effect]]
|
||||
[quo2.components.record-audio.record-audio.helpers :as helpers]))
|
||||
[quo2.components.record-audio.record-audio.helpers :refer
|
||||
[animate-linear-with-delay
|
||||
animate-easing-with-delay
|
||||
animate-linear
|
||||
set-value]]))
|
||||
|
||||
(defn lock-button
|
||||
[recording? ready-to-lock? locked?]
|
||||
@@ -18,36 +22,36 @@
|
||||
border-radius-first-half (reanimated/use-shared-value 8)
|
||||
border-radius-second-half (reanimated/use-shared-value 8)
|
||||
start-x-y-animation (fn []
|
||||
(helpers/animate-linear-with-delay translate-x-y 8 50 116.66)
|
||||
(helpers/animate-easing-with-delay connector-opacity 1 0 80)
|
||||
(helpers/animate-easing-with-delay width 56 83.33 63.33)
|
||||
(helpers/animate-easing-with-delay height 56 83.33 63.33)
|
||||
(helpers/animate-easing-with-delay border-radius-first-half
|
||||
28
|
||||
83.33
|
||||
63.33)
|
||||
(helpers/animate-easing-with-delay border-radius-second-half
|
||||
28
|
||||
83.33
|
||||
63.33))
|
||||
(animate-linear-with-delay translate-x-y 8 50 116.66)
|
||||
(animate-easing-with-delay connector-opacity 1 0 80)
|
||||
(animate-easing-with-delay width 56 83.33 63.33)
|
||||
(animate-easing-with-delay height 56 83.33 63.33)
|
||||
(animate-easing-with-delay border-radius-first-half
|
||||
28
|
||||
83.33
|
||||
63.33)
|
||||
(animate-easing-with-delay border-radius-second-half
|
||||
28
|
||||
83.33
|
||||
63.33))
|
||||
reset-x-y-animation (fn []
|
||||
(helpers/animate-linear translate-x-y 0 100)
|
||||
(helpers/set-value connector-opacity 0)
|
||||
(helpers/set-value width 24)
|
||||
(helpers/set-value height 12)
|
||||
(helpers/set-value border-radius-first-half 8)
|
||||
(helpers/set-value border-radius-second-half 16))
|
||||
(animate-linear translate-x-y 0 100)
|
||||
(set-value connector-opacity 0)
|
||||
(set-value width 24)
|
||||
(set-value height 12)
|
||||
(set-value border-radius-first-half 8)
|
||||
(set-value border-radius-second-half 16))
|
||||
fade-in-animation (fn []
|
||||
(helpers/animate-linear translate-x-y 0 220)
|
||||
(helpers/animate-linear opacity 1 220))
|
||||
(animate-linear translate-x-y 0 220)
|
||||
(animate-linear opacity 1 220))
|
||||
fade-out-animation (fn []
|
||||
(helpers/animate-linear translate-x-y 20 200)
|
||||
(helpers/animate-linear opacity 0 200)
|
||||
(helpers/set-value connector-opacity 0)
|
||||
(helpers/set-value width 24)
|
||||
(helpers/set-value height 12)
|
||||
(helpers/set-value border-radius-first-half 8)
|
||||
(helpers/set-value border-radius-second-half 16))]
|
||||
(animate-linear translate-x-y 20 200)
|
||||
(animate-linear opacity 0 200)
|
||||
(set-value connector-opacity 0)
|
||||
(set-value width 24)
|
||||
(set-value height 12)
|
||||
(set-value border-radius-first-half 8)
|
||||
(set-value border-radius-second-half 16))]
|
||||
(use-effect (fn []
|
||||
(if @recording?
|
||||
(fade-in-animation)
|
||||
|
||||