Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd3a1172b3 | ||
|
|
8c9d351f14 | ||
|
|
3e93aba011 | ||
|
|
8d43a6d5be |
@@ -228,8 +228,6 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-netinfo (4.7.0):
|
||||
- React
|
||||
- react-native-orientation-locker (1.5.0):
|
||||
- React-Core
|
||||
- react-native-randombytes (3.6.1):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (2.0.0):
|
||||
@@ -240,7 +238,7 @@ PODS:
|
||||
- React
|
||||
- react-native-status (1.0.0):
|
||||
- React
|
||||
- react-native-status-keycard (2.5.39):
|
||||
- react-native-status-keycard (2.5.38):
|
||||
- Keycard
|
||||
- React
|
||||
- react-native-webview (11.16.0):
|
||||
@@ -435,7 +433,6 @@ DEPENDENCIES:
|
||||
- react-native-lottie-splash-screen (from `../node_modules/react-native-lottie-splash-screen`)
|
||||
- react-native-mail (from `../node_modules/react-native-mail`)
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
|
||||
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- react-native-shake (from `../node_modules/react-native-shake`)
|
||||
@@ -548,8 +545,6 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-mail"
|
||||
react-native-netinfo:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-orientation-locker:
|
||||
:path: "../node_modules/react-native-orientation-locker"
|
||||
react-native-randombytes:
|
||||
:path: "../node_modules/react-native-randombytes"
|
||||
react-native-safe-area-context:
|
||||
@@ -671,13 +666,12 @@ SPEC CHECKSUMS:
|
||||
react-native-lottie-splash-screen: 068688c15dd478301fda00f8d87d7fb7d5b9a93e
|
||||
react-native-mail: 8fdcd3aef007c33a6877a18eb4cf7447a1d4ce4a
|
||||
react-native-netinfo: ddaca8bbb9e6e914b1a23787ccb879bc642931c9
|
||||
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
|
||||
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
|
||||
react-native-safe-area-context: 60f654e00b6cc416573f6d5dbfce3839958eb57a
|
||||
react-native-shake: de052eaa3eadc4a326b8ddd7ac80c06e8d84528c
|
||||
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
|
||||
react-native-status: 21f75d492fd311dc111303da38a7a2b23a8a8466
|
||||
react-native-status-keycard: f1c1227b2d5984c10fb44db68e4bfd2937f31e98
|
||||
react-native-status-keycard: f60ca57d789aad6875c64ece81ab06ef0609e0d3
|
||||
react-native-webview: 28a8636d97ee641f2ee8f20492d7a6c269c1d703
|
||||
React-RCTActionSheet: e911b99f0d6fa7711ffc2f62d236b12a32771835
|
||||
React-RCTAnimation: ad8b853170a059faf31d6add34f67d22391bbe01
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ Generating scripts:
|
||||
- `get_deps.sh` - Calls Gradle to get all the dependencies of sub-projects.
|
||||
- `gradle_parser.awk` - An AWK script that parses above Gradle output.
|
||||
- `url2json.sh` - Converts the list of URLs into a format consumable by Nix.
|
||||
- `add_package.sh` - Allows for adding a missing package manually.
|
||||
|
||||
Finally we have the Nix derivation in `default.nix` which produces a derivation with all of the Gradle project dependencies:
|
||||
```
|
||||
@@ -67,14 +66,9 @@ You can use the `add_package.sh` script to add missing Gradle dependencies:
|
||||
> make shell TARGET=gradle
|
||||
Configuring Nix shell for target 'gradle'...
|
||||
|
||||
[nix-shell:~/work/status-mobile]$ nix/deps/gradle/add_package.sh com.android.tools.build:gradle:3.5.3
|
||||
Changes made:
|
||||
nix/deps/gradle/deps.urls | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
[nix-shell:~/status-mobile]$ nix/deps/gradle/add_package.sh com.android.tools.build:gradle:3.4.0
|
||||
Regenerating Nix files...
|
||||
Successfully added: com.android.tools.build:gradle:3.5.3
|
||||
|
||||
NOTICE: Running 'make nix-update-gradle' in a new shell is recommended.
|
||||
Found 548 direct dependencies...
|
||||
Successfully added: com.android.tools.build:gradle:3.4.0
|
||||
```
|
||||
Keep in mind that the changes made by this script do not affect the already spawned shell.
|
||||
This may take a bit longer than normal `make nix-update-gradle` but should add the missing package.
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script allows for adding a package by providing a Maven full name.
|
||||
# Such name consists of 3 sections separated by the colon character.
|
||||
# Example: com.android.tools.build:gradle:3.5.3
|
||||
|
||||
set -Eeuo pipefail
|
||||
set -Eeu
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: add_package.sh <package>" >&2
|
||||
@@ -22,15 +18,12 @@ source "${GIT_ROOT}/scripts/colors.sh"
|
||||
echo "${1}" | go-maven-resolver >> nix/deps/gradle/deps.urls
|
||||
|
||||
# Remove duplicates and sort.
|
||||
sort -uVo nix/deps/gradle/deps.urls nix/deps/gradle/deps.urls
|
||||
|
||||
echo -e "${GRN}Changes made:${RST}" >&2
|
||||
git diff --stat nix/deps/gradle/deps.urls
|
||||
echo
|
||||
sort -uo nix/deps/gradle/deps.urls nix/deps/gradle/deps.urls
|
||||
|
||||
# Re-generate dependencies JSON.
|
||||
"${GIT_ROOT}/nix/deps/gradle/generate.sh" gen_deps_json
|
||||
|
||||
# Re-generate dependencies list.
|
||||
"${GIT_ROOT}/nix/deps/gradle/generate.sh" gen_deps_list
|
||||
|
||||
echo -e "${GRN}Successfully added:${RST} ${BLD}${1}${RST}" >&2
|
||||
echo
|
||||
echo -e "${YLW}NOTICE:${RST} Running '${BLD}make nix-update-gradle${RST}' in a new shell is recommended."
|
||||
|
||||
@@ -1,44 +1,82 @@
|
||||
{ stdenv, lib, pkgs, fetchurl, writeShellScriptBin }:
|
||||
|
||||
let
|
||||
inherit (lib) concatStrings concatMapStrings mapAttrsToList makeOverridable;
|
||||
inherit (lib)
|
||||
removeSuffix optionalString splitString concatMapStrings
|
||||
attrByPath attrValues last makeOverridable importJSON;
|
||||
|
||||
deps = lib.importJSON ./deps.json;
|
||||
inherit (pkgs) aapt2;
|
||||
|
||||
deps = importJSON ./deps.json;
|
||||
|
||||
# some .jar files have an `-aot` suffix that doesn't work for .pom files
|
||||
getPOM = jarUrl: "${removeSuffix "-aot" jarUrl}.pom";
|
||||
|
||||
script = writeShellScriptBin "create-local-maven-repo" (''
|
||||
mkdir -p $out
|
||||
cd $out
|
||||
'' +
|
||||
# For each dependency in deps.json.
|
||||
(concatMapStrings (dep: concatStrings
|
||||
# And for each file in the 'files' dict of given dependency.
|
||||
(mapAttrsToList (filename: hashes: let
|
||||
# Download given file(POM, JAR, nodeps JAR, or AAR).
|
||||
download = fetchurl {
|
||||
url = "${dep.repo}/${dep.path}/${filename}";
|
||||
inherit (hashes) sha256;
|
||||
};
|
||||
# And symlink it in the correct folder along with SHA1.
|
||||
in ''
|
||||
mkdir -p "${dep.path}"
|
||||
ln -s "${download}" "${dep.path}/${filename}"
|
||||
echo "${hashes.sha1}" > "${dep.path}/${filename}.sha1"
|
||||
# TODO: Generalize this section to not repeat the same code.
|
||||
(concatMapStrings (dep:
|
||||
let
|
||||
url = "${dep.host}/${dep.path}";
|
||||
pom = {
|
||||
sha1 = attrByPath [ "pom" "sha1" ] "" dep;
|
||||
sha256 = attrByPath [ "pom" "sha256" ] "" dep;
|
||||
};
|
||||
pom-download = optionalString (pom.sha256 != "") (
|
||||
fetchurl { url = getPOM url; inherit (pom) sha256; }
|
||||
);
|
||||
jar = {
|
||||
sha1 = attrByPath [ "jar" "sha1" ] "" dep;
|
||||
sha256 = attrByPath [ "jar" "sha256" ] "" dep;
|
||||
};
|
||||
jar-download = optionalString (jar.sha256 != "") (
|
||||
fetchurl { url = "${url}.${dep.type}"; inherit (jar) sha256; }
|
||||
);
|
||||
nodeps = {
|
||||
sha1 = attrByPath [ "nodeps" "sha1" ] "" dep;
|
||||
sha256 = attrByPath [ "nodeps" "sha256" ] "" dep;
|
||||
};
|
||||
nodeps-download = optionalString (nodeps.sha256 != "") (
|
||||
fetchurl { url = "${url}-nodeps.jar"; inherit (nodeps) sha256; }
|
||||
);
|
||||
fileName = last (splitString "/" dep.path);
|
||||
directory = removeSuffix fileName dep.path;
|
||||
in
|
||||
''
|
||||
mkdir -p ${directory}
|
||||
|
||||
${optionalString (pom-download != "") ''
|
||||
ln -s "${pom-download}" "${getPOM dep.path}"
|
||||
''}
|
||||
${optionalString (pom.sha1 != "") ''
|
||||
echo "${pom.sha1}" > "${getPOM dep.path}.sha1"
|
||||
''}
|
||||
${optionalString (jar-download != "") ''
|
||||
ln -s "${jar-download}" "${dep.path}.${dep.type}"
|
||||
''}
|
||||
${optionalString (jar.sha1 != "") ''
|
||||
echo "${jar.sha1}" > "${dep.path}.${dep.type}.sha1"
|
||||
''}
|
||||
${optionalString (nodeps-download != "") ''
|
||||
ln -s "${nodeps-download}" "${dep.path}-nodeps.jar"
|
||||
''}
|
||||
${optionalString (nodeps.sha1 != "") ''
|
||||
echo "${nodeps.sha1}" > "${dep.path}.${dep.type}.sha1"
|
||||
''}
|
||||
'')
|
||||
dep.files)
|
||||
) deps)
|
||||
);
|
||||
deps));
|
||||
|
||||
in makeOverridable stdenv.mkDerivation {
|
||||
name = "status-mobile-maven-deps";
|
||||
|
||||
buildInputs = [ pkgs.aapt2 ];
|
||||
|
||||
buildInputs = [ aapt2 ];
|
||||
phases = [ "buildPhase" "patchPhase" ];
|
||||
buildPhase = "${script}/bin/create-local-maven-repo";
|
||||
# Replace AAPT2 package only with our patched version from overlay.
|
||||
# Patched AAPT2
|
||||
patchPhase = ''
|
||||
aapt2_dir=$out/com/android/tools/build/aapt2/${pkgs.aapt2.version}
|
||||
aapt2_dir=$out/com/android/tools/build/aapt2/${aapt2.version}
|
||||
mkdir -p $aapt2_dir
|
||||
ln -sf ${pkgs.aapt2}/* $aapt2_dir
|
||||
ln -sf ${aapt2}/* $aapt2_dir
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.56/bcprov
|
||||
https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.60/bcprov-jdk15on-1.60.pom
|
||||
https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.32.0/checker-qual-3.32.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.31.0/checker-qual-3.31.0.pom
|
||||
https://repo.maven.apache.org/maven2/org/codehaus/codehaus-parent/4/codehaus-parent-4.pom
|
||||
https://repo.maven.apache.org/maven2/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
|
||||
https://repo.maven.apache.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.pom
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script takes care of generating/updating the maven-sources.nix file
|
||||
# representing the offline Maven repo containing the dependencies
|
||||
# required to build the project
|
||||
|
||||
set -Eeo pipefail
|
||||
# Stop on any failures, including in pipes
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if [[ -z "${IN_NIX_SHELL}" ]]; then
|
||||
echo "Remember to call 'make shell'!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# This script takes care of generating/updating the maven-sources.nix file
|
||||
# representing the offline Maven repo containing the dependencies
|
||||
# required to build the project
|
||||
|
||||
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
|
||||
source "${GIT_ROOT}/scripts/colors.sh"
|
||||
|
||||
@@ -25,43 +27,41 @@ ulimit -n 16384
|
||||
|
||||
# Generate list of Gradle sub-projects.
|
||||
function gen_proj_list() {
|
||||
"${CUR_DIR}/get_projects.sh" | sort -u -o "${PROJ_LIST}"
|
||||
echo -e "Found ${GRN}$(wc -l < "${PROJ_LIST}")${RST} sub-projects..."
|
||||
${CUR_DIR}/get_projects.sh | sort -u -o ${PROJ_LIST}
|
||||
echo -e "Found ${GRN}$(wc -l < ${PROJ_LIST})${RST} sub-projects..."
|
||||
}
|
||||
|
||||
# Check each sub-project in parallel, the ":" is for local deps.
|
||||
function gen_deps_list() {
|
||||
PROJECTS=$(cat "${PROJ_LIST}")
|
||||
# WARNING: The ${PROJECTS[@]} needs to remain unquoted to expand correctly.
|
||||
# shellcheck disable=SC2068
|
||||
"${CUR_DIR}/get_deps.sh" ":" ${PROJECTS[@]} | sort -uV -o "${DEPS_LIST}"
|
||||
echo -e "${CLR}Found ${GRN}$(wc -l < "${DEPS_LIST}")${RST} direct dependencies..."
|
||||
PROJECTS=$(cat ${PROJ_LIST})
|
||||
${CUR_DIR}/get_deps.sh ":" ${PROJECTS[@]} | sort -uV -o ${DEPS_LIST}
|
||||
echo -e "${CLR}Found ${GRN}$(wc -l < ${DEPS_LIST})${RST} direct dependencies..."
|
||||
}
|
||||
|
||||
# Find download URLs for each dependency.
|
||||
function gen_deps_urls() {
|
||||
go-maven-resolver < "${DEPS_LIST}" | sort -uV -o "${DEPS_URLS}"
|
||||
echo -e "${CLR}Found ${GRN}$(wc -l < "${DEPS_URLS}")${RST} dependency URLs..."
|
||||
cat ${DEPS_LIST} | go-maven-resolver | sort -uV -o ${DEPS_URLS}
|
||||
echo -e "${CLR}Found ${GRN}$(wc -l < ${DEPS_URLS})${RST} dependency URLs..."
|
||||
}
|
||||
|
||||
# Generate the JSON that Nix will consume.
|
||||
function gen_deps_json() {
|
||||
# Open the Nix attribute set.
|
||||
echo -n "[" > "${DEPS_JSON}"
|
||||
echo -n "[" > ${DEPS_JSON}
|
||||
|
||||
# Format URLs into a Nix consumable file.
|
||||
URLS=$(cat "${DEPS_URLS}")
|
||||
URLS=$(cat ${DEPS_URLS})
|
||||
# Avoid rate limiting by using 4 of the available threads.
|
||||
parallel --will-cite --keep-order --jobs 4 \
|
||||
"${CUR_DIR}/url2json.sh" \
|
||||
::: "${URLS}" \
|
||||
>> "${DEPS_JSON}"
|
||||
::: ${URLS} \
|
||||
>> ${DEPS_JSON}
|
||||
|
||||
# Drop tailing comma on last object, stupid JSON
|
||||
sed -i '$ s/},/}/' "${DEPS_JSON}"
|
||||
sed -i '$ s/},/}/' ${DEPS_JSON}
|
||||
|
||||
# Close the Nix attribute set
|
||||
echo "]" >> "${DEPS_JSON}"
|
||||
echo "]" >> ${DEPS_JSON}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -74,7 +74,7 @@ cd "${GIT_ROOT}/android"
|
||||
./gradlew --stop >/dev/null
|
||||
|
||||
# A way to run a specific stage of generation
|
||||
if [[ -n "${1}" ]] && type "${1}" > /dev/null; then
|
||||
if [[ -n "${1}" ]] && type ${1} > /dev/null; then
|
||||
${1}; exit 0
|
||||
elif [[ -n "${1}" ]]; then
|
||||
echo "No such function: ${1}"; exit 1
|
||||
@@ -86,6 +86,6 @@ gen_deps_list
|
||||
gen_deps_urls
|
||||
gen_deps_json
|
||||
|
||||
REL_DEPS_JSON=$(realpath --relative-to="${PWD}" "${DEPS_JSON}")
|
||||
REL_DEPS_JSON=$(realpath --relative-to=${PWD} ${DEPS_JSON})
|
||||
echo -e "${CLR}Generated Nix deps file: ${REL_DEPS_JSON#../}"
|
||||
echo -e "${GRN}Done${RST}"
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script generates a list of dependencies for the main project and its
|
||||
# sub-projects defined using Gradle config files. It parses Gradle output of
|
||||
# 'dependencies' and 'buildEnvironment` tasks using AWK.
|
||||
|
||||
set -Eeuo pipefail
|
||||
set -Eeu
|
||||
|
||||
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
|
||||
# Gradle needs to be run in 'android' subfolder.
|
||||
# Gradle needs to be run in 'android' subfolder
|
||||
cd "${GIT_ROOT}/android"
|
||||
|
||||
# Show Gradle log in case of failure.
|
||||
GRADLE_LOG_FILE='/tmp/gradle.log'
|
||||
function show_gradle_log() { cat "${GRADLE_LOG_FILE}" >&2; }
|
||||
trap show_gradle_log ERR
|
||||
AWK_SCRIPT="${GIT_ROOT}/nix/deps/gradle/gradle_parser.awk"
|
||||
|
||||
# Run the gradle command for a project:
|
||||
# - ':buildEnvironment' to get build tools
|
||||
@@ -27,11 +20,16 @@ for i in "${!DEPS[@]}"; do
|
||||
NORMAL_DEPS[${i}]="${DEPS[${i}]}:dependencies"
|
||||
done
|
||||
|
||||
# And clean up the output using AWK script.
|
||||
AWK_SCRIPT="${GIT_ROOT}/nix/deps/gradle/gradle_parser.awk"
|
||||
# And clean up the output by:
|
||||
# - keep only lines that start with \--- or +---
|
||||
# - drop lines that end with (*) or (n) but don't start with (+)
|
||||
# - drop lines that refer to a project
|
||||
# - drop entries starting with `status-im:` like `status-go`
|
||||
# - drop entries that aren't just the name of the dependency
|
||||
# - extract the package name and version, ignoring version range indications,
|
||||
# such as in `com.google.android.gms:play-services-ads:[15.0.1,16.0.0) -> 15.0.1`
|
||||
|
||||
./gradlew --no-daemon --console plain \
|
||||
"${BUILD_DEPS[@]}" \
|
||||
"${NORMAL_DEPS[@]}" \
|
||||
| tee "${GRADLE_LOG_FILE}" \
|
||||
| awk -f "${AWK_SCRIPT}"
|
||||
| awk -f ${AWK_SCRIPT}
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This script generates a list of Gradle sub-projects by parsing the output
|
||||
# of Gradle 'projects' task using grep and sed. It is necessary in order to
|
||||
# collect list of dependencies for main project and its sub-projects.
|
||||
|
||||
set -Eeuo pipefail
|
||||
set -Eeu
|
||||
|
||||
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
|
||||
# Gradle needs to be run in 'android' subfolder.
|
||||
# Gradle needs to be run in 'android' subfolder
|
||||
cd "${GIT_ROOT}/android"
|
||||
|
||||
# Show Gradle log in case of failure.
|
||||
GRADLE_LOG_FILE='/tmp/gradle.log'
|
||||
function show_gradle_log() { cat "${GRADLE_LOG_FILE}" >&2; }
|
||||
trap show_gradle_log ERR
|
||||
|
||||
# Print all our sub-projects
|
||||
./gradlew projects --no-daemon --console plain 2>&1 \
|
||||
| tee "${GRADLE_LOG_FILE}" \
|
||||
| grep "Project ':" \
|
||||
| sed -E "s;^.--- Project '\:([@_a-zA-Z0-9\-]+)';\1;"
|
||||
|
||||
@@ -26,7 +26,6 @@ react-native-lottie-splash-screen
|
||||
react-native-mail
|
||||
react-native-navigation
|
||||
react-native-nfc-manager
|
||||
react-native-orientation-locker
|
||||
react-native-permissions
|
||||
react-native-randombytes
|
||||
react-native-reanimated
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
# a local Maven repository.
|
||||
#
|
||||
|
||||
CUR_DIR=$(cd "${BASH_SOURCE%/*}" && pwd)
|
||||
|
||||
# This defines URLs of Maven repos we know about and use.
|
||||
declare -a REPOS=(
|
||||
"https://repo.maven.apache.org/maven2"
|
||||
@@ -35,87 +37,105 @@ function match_repo_url() {
|
||||
}
|
||||
|
||||
function pom_has_nodeps_jar() {
|
||||
grep '<shadedClassifierName>nodeps</shadedClassifierName>' "${1}" \
|
||||
>/dev/null 2>&1
|
||||
}
|
||||
|
||||
function fetch_and_template_file() {
|
||||
local FILENAME="${1}"
|
||||
local OBJ_URL OBJ_NIX_FETCH_OUT OBJ_NAME OBJ_PATH
|
||||
|
||||
OBJ_URL="${REPO_URL}/${PKG_PATH}/${FILENAME}"
|
||||
if ! OBJ_NIX_FETCH_OUT=$(nix_fetch "${OBJ_URL}"); then
|
||||
echo " ! Failed to fetch: ${OBJ_URL}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OBJ_NAME="${FILENAME}"
|
||||
OBJ_PATH=$(get_nix_path "${OBJ_NIX_FETCH_OUT}")
|
||||
echo -n ",
|
||||
\"${OBJ_NAME}\": {
|
||||
\"sha1\": \"$(get_sha1 "${OBJ_PATH}")\",
|
||||
\"sha256\": \"$(get_nix_sha "${OBJ_NIX_FETCH_OUT}")\"
|
||||
}"
|
||||
grep '<shadedClassifierName>nodeps</shadedClassifierName>' $1 \
|
||||
2>&1 >/dev/null
|
||||
}
|
||||
|
||||
if [[ -z "${1}" ]]; then
|
||||
echo "Required POM URL argument not given!" >&2
|
||||
echo "Required argument not given!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
POM_URL=${1}
|
||||
# Drop the POM extension.
|
||||
PKG_URL_NO_EXT="${POM_URL%.pom}"
|
||||
# Name of package without extension.
|
||||
PKG_NAME="$(basename "${PKG_URL_NO_EXT}")"
|
||||
# Drop the POM extension
|
||||
OBJ_REL_URL=${POM_URL%.pom}
|
||||
|
||||
echo -en "${CLR} - Nix entry for: ${1##*/}\r" >&2
|
||||
|
||||
REPO_URL=$(match_repo_url "${PKG_URL_NO_EXT}")
|
||||
REPO_URL=$(match_repo_url "${OBJ_REL_URL}")
|
||||
|
||||
if [[ -z "${REPO_URL}" ]]; then
|
||||
echo " ! Repo URL not found: %s" "${REPO_URL}" >&2
|
||||
exit 1
|
||||
echo "\r\n ? REPO_URL: ${REPO_URL}" >&2
|
||||
fi
|
||||
# Get the relative path without full URL
|
||||
PKG_PATH="${PKG_URL_NO_EXT#"${REPO_URL}/"}"
|
||||
PKG_PATH="$(dirname "${PKG_PATH}")"
|
||||
OBJ_REL_NAME="${OBJ_REL_URL#${REPO_URL}/}"
|
||||
|
||||
# Both JARs and AARs have a POM
|
||||
POM_NIX_FETCH_OUT=$(nix_fetch "${PKG_URL_NO_EXT}.pom")
|
||||
POM_NIX_FETCH_OUT=$(nix_fetch "${OBJ_REL_URL}.pom")
|
||||
POM_PATH=$(get_nix_path "${POM_NIX_FETCH_OUT}")
|
||||
POM_NAME=$(basename "${PKG_URL_NO_EXT}.pom")
|
||||
if [[ -z "${POM_PATH}" ]]; then
|
||||
echo " ! Failed to fetch: ${PKG_URL_NO_EXT}.pom" >&2
|
||||
echo " ! Failed to fetch: ${OBJ_REL_URL}.pom" >&2
|
||||
exit 1
|
||||
fi
|
||||
POM_SHA256=$(get_nix_sha "${POM_NIX_FETCH_OUT}")
|
||||
POM_SHA1=$(get_sha1 "${POM_PATH}")
|
||||
|
||||
# Identify packaging type, JAR, AAR, bundle, or just POM.
|
||||
OBJ_TYPE=$(grep -oP '<packaging>\K[^<]+' "${POM_PATH}")
|
||||
# Identify packaging type, JAR, AAR, or just POM.
|
||||
OBJ_TYPE_RAW=$(grep -oP '<packaging>\K[^<]+' "${POM_PATH}")
|
||||
# Bundle is a JAR made using maven-bundle-plugin.
|
||||
case "${OBJ_TYPE_RAW}" in
|
||||
''|'bundle') OBJ_TYPE=jar;;
|
||||
'aar.asc') OBJ_TYPE=aar;;
|
||||
*) OBJ_TYPE="${OBJ_TYPE_RAW}"
|
||||
esac
|
||||
|
||||
# Some deps are Eclipse plugins, and we don't need those.
|
||||
if [[ "${OBJ_TYPE}" == "eclipse-plugin" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Some deps are just POMs, in which case there is no JAR to fetch.
|
||||
if [[ "${OBJ_TYPE}" != "pom" ]]; then
|
||||
OBJ_NIX_FETCH_OUT=$(nix_fetch "${OBJ_REL_URL}.${OBJ_TYPE}")
|
||||
# If type was a JAR or other, not getting one is an error.
|
||||
if [[ ${?} -ne 0 ]]; then
|
||||
# POMs without packaging type defined can still include JARs.
|
||||
if [[ "${OBJ_TYPE_RAW}" != "" ]]; then
|
||||
echo " ! Failed to fetch: ${OBJ_REL_URL}.${OBJ_TYPE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
OBJ_PATH=$(get_nix_path "${OBJ_NIX_FETCH_OUT}")
|
||||
OBJ_SHA256=$(get_nix_sha "${OBJ_NIX_FETCH_OUT}")
|
||||
OBJ_SHA1=$(get_sha1 "${OBJ_PATH}")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Some deps include nodeps JARs which include.
|
||||
if pom_has_nodeps_jar "${POM_PATH}"; then
|
||||
NODEPS_NIX_FETCH_OUT=$(nix_fetch "${OBJ_REL_URL}-nodeps.jar")
|
||||
if [[ ${?} -eq 0 ]]; then
|
||||
NODEPS_PATH=$(get_nix_path "${NODEPS_NIX_FETCH_OUT}")
|
||||
NODEPS_SHA256=$(get_nix_sha "${NODEPS_NIX_FETCH_OUT}")
|
||||
NODEPS_SHA1=$(get_sha1 "${NODEPS_PATH}")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Format into a Nix attrset entry
|
||||
echo -ne "
|
||||
{
|
||||
\"path\": \"${PKG_PATH}\",
|
||||
\"repo\": \"${REPO_URL}\",
|
||||
\"files\": {
|
||||
\"${POM_NAME}\": {
|
||||
\"sha1\": \"${POM_SHA1}\",
|
||||
\"sha256\": \"${POM_SHA256}\"
|
||||
}"
|
||||
|
||||
# Some deps are just POMs, in which case there is no JAR to fetch.
|
||||
[[ "${OBJ_TYPE}" == "" ]] && fetch_and_template_file "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" == "jar" ]] && fetch_and_template_file "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" == "bundle" ]] && fetch_and_template_file "${PKG_NAME}.jar"
|
||||
[[ "${OBJ_TYPE}" =~ aar* ]] && fetch_and_template_file "${PKG_NAME}.aar"
|
||||
[[ "${OBJ_TYPE}" == "aar.asc" ]] && fetch_and_template_file "${PKG_NAME}.${OBJ_TYPE}"
|
||||
pom_has_nodeps_jar "${POM_PATH}" && fetch_and_template_file "${PKG_NAME}-nodeps.jar"
|
||||
|
||||
echo -e '\n }\n },'
|
||||
\"path\": \"${OBJ_REL_NAME}\",
|
||||
\"host\": \"${REPO_URL}\",
|
||||
\"type\": \"${OBJ_TYPE}\","
|
||||
if [[ -n "${POM_SHA256}" ]]; then
|
||||
echo -n "
|
||||
\"pom\": {
|
||||
\"sha1\": \"${POM_SHA1}\",
|
||||
\"sha256\": \"${POM_SHA256}\"
|
||||
}";[[ -n "${OBJ_SHA256}" ]] && echo -n ","
|
||||
fi
|
||||
if [[ -n "${OBJ_SHA256}" ]]; then
|
||||
echo -n "
|
||||
\"jar\": {
|
||||
\"sha1\": \"${OBJ_SHA1}\",
|
||||
\"sha256\": \"${OBJ_SHA256}\"
|
||||
}";[[ -n "${NODEPS_SHA256}" ]] && echo -n ","
|
||||
fi
|
||||
if [[ -n "${NODEPS_SHA256}" ]]; then
|
||||
echo -n "
|
||||
\"nodeps\": {
|
||||
\"sha1\": \"${NODEPS_SHA1}\",
|
||||
\"sha256\": \"${NODEPS_SHA256}\"
|
||||
}"
|
||||
fi
|
||||
echo -e "\n },"
|
||||
|
||||
@@ -29,14 +29,7 @@ stdenv.mkDerivation {
|
||||
# maven and google central repositories with our own local directories.
|
||||
# This prevents the builder from downloading Maven artifacts
|
||||
patchGradlePhase = ''
|
||||
gradleConfigs=$(
|
||||
find -L ./node_modules \
|
||||
-name build.gradle -or \
|
||||
-name build.gradle.kts -or \
|
||||
-name settings.gradle -or \
|
||||
-name settings.gradle.kts
|
||||
)
|
||||
for modBuildGradle in $gradleConfigs; do
|
||||
for modBuildGradle in $(find -L ./node_modules -name build.gradle); do
|
||||
relativeToNode=''${modBuildGradle#*node_modules/}
|
||||
moduleName=''${relativeToNode%%/*}
|
||||
if [[ -L ./node_modules/$moduleName ]]; then
|
||||
|
||||
@@ -16,8 +16,7 @@ writeScript "patch-maven-srcs" (''
|
||||
gradleFile="$1"
|
||||
|
||||
# Some of those find something, some don't, that's fine.
|
||||
patchMavenSource "$gradleFile" 'mavenCentral()' 'mavenLocal()'
|
||||
patchMavenSource "$gradleFile" 'google()' 'mavenLocal()'
|
||||
patchMavenSource "$gradleFile" 'jcenter()' 'mavenLocal()'
|
||||
patchMavenSource "$gradleFile" 'gradlePluginPortal()' 'mavenLocal()'
|
||||
patchMavenSource "$gradleFile" 'mavenCentral()' 'mavenLocal()'
|
||||
patchMavenSource "$gradleFile" 'google()' 'mavenLocal()'
|
||||
patchMavenSource "$gradleFile" 'jcenter()' 'mavenLocal()'
|
||||
'')
|
||||
|
||||
|
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: 1.7 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,6 +1,6 @@
|
||||
(ns quo2.components.animated-header-flatlist.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn container-view
|
||||
[view-height]
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
(defn blur-view
|
||||
[animation]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity animation}
|
||||
{:position :absolute
|
||||
:top 0
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
(defn entity-picture
|
||||
[animation]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:width animation
|
||||
:height animation}
|
||||
{:transform [{:scale 1}]
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
(defn header-bottom-part
|
||||
[animation]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:border-top-right-radius animation
|
||||
:border-top-left-radius animation}
|
||||
{:position :absolute
|
||||
@@ -66,9 +66,9 @@
|
||||
|
||||
(defn header-comp
|
||||
[y-animation opacity-animation]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
;; here using `left` won't work on Android, so we are using `translateX`
|
||||
{:transform [{:translateX (ra/use-val 64)} {:translateY y-animation}]
|
||||
{:transform [{:translateX (reanimated/use-shared-value 64)} {:translateY y-animation}]
|
||||
:opacity opacity-animation}
|
||||
{:position :absolute
|
||||
:z-index 3}))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.fast-image :as fast-image]
|
||||
[reagent.core :as reagent]
|
||||
@@ -18,16 +18,16 @@
|
||||
|
||||
(defn interpolate
|
||||
[value input-range output-range]
|
||||
(ra/interpolate value
|
||||
input-range
|
||||
output-range
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"}))
|
||||
(reanimated/interpolate value
|
||||
input-range
|
||||
output-range
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"}))
|
||||
|
||||
(defn scroll-handler
|
||||
[event initial-y scroll-y]
|
||||
(let [current-y (- (oops/oget event "nativeEvent.contentOffset.y") initial-y)]
|
||||
(ra/set-val scroll-y current-y)))
|
||||
(reanimated/set-shared-value scroll-y current-y)))
|
||||
|
||||
(defn header
|
||||
[{:keys [theme-color display-picture-comp cover-uri title-comp]} top-inset scroll-y]
|
||||
@@ -45,9 +45,9 @@
|
||||
{:style {:width "100%"
|
||||
:height cover-height}
|
||||
:source {:uri cover-uri}}])
|
||||
[ra/view {:style (style/header-bottom-part border-animation)}
|
||||
[reanimated/view {:style (style/header-bottom-part border-animation)}
|
||||
[title-comp]]
|
||||
[ra/view {:style (style/entity-picture size-animation)}
|
||||
[reanimated/view {:style (style/entity-picture size-animation)}
|
||||
[display-picture-comp image-animation]]]))
|
||||
|
||||
(defn animated-header-list
|
||||
@@ -64,7 +64,7 @@
|
||||
initial-y (if platform/ios? (- (:top insets)) 0)]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [scroll-y (ra/use-val initial-y)
|
||||
(let [scroll-y (reanimated/use-shared-value initial-y)
|
||||
opacity-animation (interpolate scroll-y
|
||||
[(* threshold 0.33) (* threshold 0.66)]
|
||||
[0 1])
|
||||
@@ -80,14 +80,14 @@
|
||||
{:active-opacity 1
|
||||
:style (style/button-container {:right 20})}
|
||||
[quo/icon :i/options {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
|
||||
[ra/blur-view
|
||||
[reanimated/blur-view
|
||||
{:blurAmount 32
|
||||
:blurType :light
|
||||
:overlayColor (if platform/ios? colors/white-opa-70 :transparent)
|
||||
:style (style/blur-view opacity-animation)}
|
||||
[ra/view {:style (style/header-comp translate-animation title-opacity-animation)}
|
||||
[reanimated/view {:style (style/header-comp translate-animation title-opacity-animation)}
|
||||
[header-comp]]]
|
||||
[ra/flat-list
|
||||
[reanimated/flat-list
|
||||
{:data [nil]
|
||||
:render-fn main-comp
|
||||
:key-fn str
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
(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?)}])]))
|
||||
@@ -0,0 +1,127 @@
|
||||
(ns quo2.components.avatars.user-avatar.component-spec
|
||||
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[status-im2.common.resources :as resources]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defn- test-truthy [element]
|
||||
(.toBeTruthy (js/expect element)))
|
||||
|
||||
(defn- test-null [element]
|
||||
(.toBeNull (js/expect element)))
|
||||
|
||||
(h/describe "user avatar"
|
||||
(h/test "Default render"
|
||||
(h/render [user-avatar/user-avatar])
|
||||
(test-truthy (h/get-by-label-text :user-avatar))
|
||||
(test-truthy (h/get-by-text "EN")))
|
||||
|
||||
(h/describe "Profile picture"
|
||||
(h/test "Renders"
|
||||
(h/render
|
||||
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)}])
|
||||
(test-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 (resources/get-mock-image :user-picture-male4)
|
||||
:full-name "New User1"}])
|
||||
(test-truthy (h/get-by-label-text :profile-picture))
|
||||
(test-null (h/query-by-label-text :initials-avatar)))
|
||||
|
||||
(h/describe "Status indicator"
|
||||
(h/test "Render"
|
||||
(h/render
|
||||
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)
|
||||
:status-indicator? true}])
|
||||
(test-truthy (h/get-by-label-text :profile-picture))
|
||||
(test-truthy (h/get-by-label-text :status-indicator)))
|
||||
|
||||
(h/test "Do not render"
|
||||
(h/render
|
||||
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)
|
||||
:status-indicator? false}])
|
||||
(test-truthy (h/get-by-label-text :profile-picture))
|
||||
(test-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))
|
||||
(test-truthy (h/get-by-text "NU")))
|
||||
|
||||
(h/test "Size :medium"
|
||||
(h/render (user-avatar-component :medium))
|
||||
(test-truthy (h/get-by-text "NU")))
|
||||
|
||||
(h/test "Size :small"
|
||||
(h/render (user-avatar-component :small))
|
||||
(test-truthy (h/get-by-text "NU"))))
|
||||
|
||||
(h/describe "One letter"
|
||||
(h/test "Size :xs"
|
||||
(h/render (user-avatar-component :xs))
|
||||
(test-truthy (h/get-by-text "N")))
|
||||
|
||||
(h/test "Size :xxs"
|
||||
(h/render (user-avatar-component :xxs))
|
||||
(test-truthy (h/get-by-text "N")))
|
||||
|
||||
(h/test "Size :xxxs"
|
||||
(h/render (user-avatar-component :xxxs))
|
||||
(test-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 (resources/get-mock-image :ring)
|
||||
:size size}])]
|
||||
(h/describe "Passed and drawn"
|
||||
(h/test "Size :big"
|
||||
(h/render (user-avatar-component :big))
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-truthy (h/get-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :medium"
|
||||
(h/render (user-avatar-component :medium))
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-truthy (h/get-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :small"
|
||||
(h/render (user-avatar-component :small))
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-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))
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-null (h/query-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :xxs"
|
||||
(h/render (user-avatar-component :xxs))
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-null (h/query-by-label-text :ring-background)))
|
||||
|
||||
(h/test "Size :xxxs"
|
||||
(h/render (user-avatar-component :xxxs))
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-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}])
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-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}])
|
||||
(test-truthy (h/get-by-label-text :initials-avatar))
|
||||
(test-null (h/query-by-label-text :status-indicator))))))
|
||||
@@ -0,0 +1,83 @@
|
||||
(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?]
|
||||
(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 :turquoise 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}))
|
||||
@@ -0,0 +1,56 @@
|
||||
(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?]}]
|
||||
(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?)}
|
||||
[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]
|
||||
: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-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?}])
|
||||
(when status-indicator?
|
||||
[rn/view {:accessibility-label :status-indicator
|
||||
:style (style/dot size online? draw-ring?)}])]))
|
||||
@@ -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
|
||||
|
||||
@@ -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}])
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
"
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn apply-anim
|
||||
[dd-height val]
|
||||
(ra/animate-delay dd-height
|
||||
val
|
||||
0
|
||||
300
|
||||
:easing1))
|
||||
(reanimated/animate-shared-value-with-delay dd-height
|
||||
val
|
||||
300
|
||||
:easing1
|
||||
0))
|
||||
|
||||
(def sizes
|
||||
{:big {:icon-size 20
|
||||
@@ -141,7 +141,7 @@
|
||||
[:f>
|
||||
(fn []
|
||||
(let [open? (reagent/atom false)
|
||||
dd-height (ra/use-val 0)]
|
||||
dd-height (reanimated/use-shared-value 0)]
|
||||
[rn/view {:style {:flex-grow 1}}
|
||||
[dropdown-comp
|
||||
{:items items
|
||||
@@ -155,8 +155,8 @@
|
||||
:default-item default-item
|
||||
:open? open?
|
||||
:dd-height dd-height}]
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:height dd-height}
|
||||
{:height dd-height})}
|
||||
[items-comp
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def header-height 56)
|
||||
@@ -162,7 +162,7 @@
|
||||
border-bottom false}}]
|
||||
(let [status-bar-height (get insets :top 0)
|
||||
height (+ header-height status-bar-height)]
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (header-wrapper-style {:height height
|
||||
:background background
|
||||
:border-bottom border-bottom})}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(ns quo2.components.list-items.preview-list
|
||||
(:require [quo2.components.avatars.user-avatar :as user-avatar]
|
||||
(:require [quo2.components.avatars.user-avatar.view :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 :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.foundations.colors :as colors]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.masked-view :as masked-view]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(def message-skeleton-height 54)
|
||||
@@ -30,12 +30,12 @@
|
||||
author-width (content-width :author)
|
||||
message-width (content-width :message)
|
||||
{window-width :width} (rn/use-window-dimensions)
|
||||
translate-x (ra/use-val (- window-width))
|
||||
animated-gradient-style (ra/apply-animations-to-style
|
||||
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%"})]
|
||||
(ra/animate-repeat translate-x window-width (- 1) false 1000 :linear)
|
||||
(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
|
||||
@@ -70,7 +70,7 @@
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:background-color color}}
|
||||
[ra/linear-gradient
|
||||
[reanimated/linear-gradient
|
||||
{:colors [color color loading-color color color]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 1 :y 0}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns quo2.components.messages.system-message
|
||||
(:require [quo2.components.avatars.icon-avatar :as icon-avatar]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar.view :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 ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[utils.string :as utils]))
|
||||
|
||||
(def themes-landed
|
||||
@@ -176,20 +176,20 @@
|
||||
[{:keys [type style non-pressable? animate-landing? labels on-long-press] :as message}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [sv-color (ra/use-val
|
||||
(let [sv-color (reanimated/use-shared-value
|
||||
(get-color :bg (if animate-landing? :landed :default) type))]
|
||||
(when animate-landing?
|
||||
(ra/animate-delay
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
sv-color
|
||||
(get-color :bg :default type)
|
||||
1000
|
||||
0
|
||||
:linear))
|
||||
[ra/touchable-opacity
|
||||
:linear
|
||||
1000))
|
||||
[reanimated/touchable-opacity
|
||||
{:on-press #(when-not non-pressable?
|
||||
(ra/set-val sv-color (get-color :bg :pressed type)))
|
||||
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
|
||||
:on-long-press on-long-press
|
||||
:style (ra/apply-animations-to-style
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:background-color sv-color}
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.hole-view :as hole-view]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn toggle-background-color
|
||||
[background-color press-out? pass-through?]
|
||||
(ra/set-val
|
||||
(reanimated/set-shared-value
|
||||
background-color
|
||||
(cond
|
||||
press-out? "transparent"
|
||||
@@ -31,14 +31,14 @@
|
||||
on-press pass-through? icon-color-anim accessibility-label test-ID]}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [icon-animated-style (ra/apply-animations-to-style
|
||||
(let [icon-animated-style (reanimated/apply-animations-to-style
|
||||
{:tint-color icon-color-anim}
|
||||
{:width 24
|
||||
:height 24
|
||||
:margin-left 33
|
||||
:margin-top 8})
|
||||
background-color (ra/use-val "transparent")
|
||||
background-animated-style (ra/apply-animations-to-style
|
||||
background-color (reanimated/use-shared-value "transparent")
|
||||
background-animated-style (reanimated/apply-animations-to-style
|
||||
{:background-color background-color}
|
||||
{:width 90
|
||||
:height 40
|
||||
@@ -49,7 +49,7 @@
|
||||
: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}
|
||||
[ra/view {:style background-animated-style}
|
||||
[reanimated/view {:style background-animated-style}
|
||||
;; In android animations are not working for the animated components which are nested by
|
||||
;; hole-view,
|
||||
;; Interestingly this only happens when hole view and blur view are used together
|
||||
@@ -69,10 +69,10 @@
|
||||
|
||||
:else
|
||||
[{:x 47 :y 1 :width 18 :height 18 :borderRadius 7}])}
|
||||
[ra/image
|
||||
[reanimated/image
|
||||
{:style icon-animated-style
|
||||
:source (icons/icon-source (keyword (str icon 24)))}]]
|
||||
[ra/image
|
||||
[reanimated/image
|
||||
{:style icon-animated-style
|
||||
:source (icons/icon-source (keyword (str icon 24)))}])
|
||||
(when new-notifications?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns quo2.components.navigation.floating-shell-button
|
||||
(:require [quo2.components.buttons.dynamic-button :as dynamic-button]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn dynamic-button-view
|
||||
[type dynamic-buttons style]
|
||||
@@ -28,12 +28,12 @@
|
||||
:margin-horizontal 12
|
||||
:pointer-events :box-none}
|
||||
style)
|
||||
animated-style (ra/apply-animations-to-style
|
||||
animated-style (reanimated/apply-animations-to-style
|
||||
(if opacity-anim
|
||||
{:opacity opacity-anim}
|
||||
{})
|
||||
original-style)]
|
||||
[ra/view {:style animated-style}
|
||||
[reanimated/view {:style animated-style}
|
||||
;; Left Section
|
||||
[rn/view {:style {:flex 1}}
|
||||
[dynamic-button-view :search dynamic-buttons
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns quo2.components.navigation.page-nav
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
|
||||
@@ -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 :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.view :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 :as user-avatar]
|
||||
[quo2.components.avatars.user-avatar.view :as user-avatar]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn- on-change-handler
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [quo2.components.icon :as icons]
|
||||
[quo2.components.record-audio.record-audio.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.core :refer [use-effect]]
|
||||
[quo2.components.record-audio.record-audio.helpers :refer
|
||||
[animate-linear-with-delay
|
||||
@@ -14,14 +14,14 @@
|
||||
[recording? ready-to-delete? reviewing-audio?]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [opacity (ra/use-val 0)
|
||||
translate-x (ra/use-val 20)
|
||||
scale (ra/use-val 1)
|
||||
connector-opacity (ra/use-val 0)
|
||||
connector-width (ra/use-val 24)
|
||||
connector-height (ra/use-val 12)
|
||||
border-radius-first-half (ra/use-val 8)
|
||||
border-radius-second-half (ra/use-val 8)
|
||||
(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 []
|
||||
(animate-linear-with-delay translate-x 12 50 133.33)
|
||||
(animate-easing-with-delay connector-opacity 1 0 93.33)
|
||||
@@ -73,14 +73,14 @@
|
||||
(reset-x-animation)))
|
||||
[@ready-to-delete?])
|
||||
[:<>
|
||||
[ra/view {:style (style/delete-button-container opacity)}
|
||||
[ra/view
|
||||
[reanimated/view {:style (style/delete-button-container opacity)}
|
||||
[reanimated/view
|
||||
{:style (style/delete-button-connector connector-opacity
|
||||
connector-width
|
||||
connector-height
|
||||
border-radius-first-half
|
||||
border-radius-second-half)}]]
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (style/delete-button scale translate-x opacity)
|
||||
:pointer-events :none}
|
||||
[icons/icon :i/delete
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [quo2.components.icon :as icons]
|
||||
[quo2.components.record-audio.record-audio.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.core :refer [use-effect]]
|
||||
[quo2.components.record-audio.record-audio.helpers :refer
|
||||
[animate-linear-with-delay
|
||||
@@ -14,13 +14,13 @@
|
||||
[recording? ready-to-lock? locked?]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [translate-x-y (ra/use-val 20)
|
||||
opacity (ra/use-val 0)
|
||||
connector-opacity (ra/use-val 0)
|
||||
width (ra/use-val 24)
|
||||
height (ra/use-val 12)
|
||||
border-radius-first-half (ra/use-val 8)
|
||||
border-radius-second-half (ra/use-val 8)
|
||||
(let [translate-x-y (reanimated/use-shared-value 20)
|
||||
opacity (reanimated/use-shared-value 0)
|
||||
connector-opacity (reanimated/use-shared-value 0)
|
||||
width (reanimated/use-shared-value 24)
|
||||
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-y-animation (fn []
|
||||
(animate-linear-with-delay translate-x-y 8 50 116.66)
|
||||
(animate-easing-with-delay connector-opacity 1 0 80)
|
||||
@@ -70,14 +70,14 @@
|
||||
(reset-x-y-animation)))
|
||||
[@locked?])
|
||||
[:<>
|
||||
[ra/view {:style (style/lock-button-container opacity)}
|
||||
[ra/view
|
||||
[reanimated/view {:style (style/lock-button-container opacity)}
|
||||
[reanimated/view
|
||||
{:style (style/lock-button-connector connector-opacity
|
||||
width
|
||||
height
|
||||
border-radius-first-half
|
||||
border-radius-second-half)}]]
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (style/lock-button translate-x-y opacity)
|
||||
:pointer-events :none}
|
||||
[icons/icon (if @ready-to-lock? :i/locked :i/unlocked)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[quo2.components.record-audio.record-audio.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn :refer [use-effect]]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[quo2.components.buttons.button :as button]
|
||||
[quo2.components.record-audio.record-audio.helpers :refer [set-value]]))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[recording? reviewing-audio?]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [opacity (ra/use-val 1)
|
||||
(let [opacity (reanimated/use-shared-value 1)
|
||||
show-animation #(set-value opacity 1)
|
||||
hide-animation #(set-value opacity 0)]
|
||||
(use-effect (fn []
|
||||
@@ -19,7 +19,7 @@
|
||||
(hide-animation)
|
||||
(show-animation)))
|
||||
[@recording? @reviewing-audio?])
|
||||
[ra/view {:style (style/record-button-container opacity)}
|
||||
[reanimated/view {:style (style/record-button-container opacity)}
|
||||
[button/button
|
||||
{:type :outline
|
||||
:size 32
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[quo2.components.record-audio.record-audio.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn :refer [use-effect]]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.audio-toolkit :as audio]
|
||||
[taoensso.timbre :as log]
|
||||
[cljs-bean.core :as bean]
|
||||
@@ -37,7 +37,7 @@
|
||||
(fn [props]
|
||||
(let [{:keys [scale opacity color]} (bean/bean props)]
|
||||
(reagent/as-element
|
||||
[ra/view {:style (style/animated-circle scale opacity color)}]))))))
|
||||
[reanimated/view {:style (style/animated-circle scale opacity color)}]))))))
|
||||
|
||||
(defn record-button-big
|
||||
[recording? ready-to-send? ready-to-lock? ready-to-delete? record-button-is-animating?
|
||||
@@ -45,29 +45,29 @@
|
||||
clear-timeout touch-active? recorder-ref reload-recorder-fn idle? on-send on-cancel]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [scale (ra/use-val 1)
|
||||
opacity (ra/use-val 0)
|
||||
(let [scale (reanimated/use-shared-value 1)
|
||||
opacity (reanimated/use-shared-value 0)
|
||||
opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default)
|
||||
animations (map
|
||||
(fn [index]
|
||||
(let [ring-scale (ring-scale scale (* scale-padding index))]
|
||||
{:scale ring-scale
|
||||
:opacity (ra/interpolate ring-scale
|
||||
[1 scale-to-each]
|
||||
[opacity-from 0])}))
|
||||
:opacity (reanimated/interpolate ring-scale
|
||||
[1 scale-to-each]
|
||||
[opacity-from 0])}))
|
||||
(range 0 5))
|
||||
rings-color (cond
|
||||
@ready-to-lock? (colors/theme-colors colors/neutral-80-opa-5-opaque
|
||||
colors/neutral-80)
|
||||
@ready-to-delete? colors/danger-50
|
||||
:else colors/primary-50)
|
||||
translate-y (ra/use-val 0)
|
||||
translate-x (ra/use-val 0)
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
translate-x (reanimated/use-shared-value 0)
|
||||
button-color colors/primary-50
|
||||
icon-color (if (and (not (colors/dark?)) @ready-to-lock?) colors/black colors/white)
|
||||
icon-opacity (ra/use-val 1)
|
||||
red-overlay-opacity (ra/use-val 0)
|
||||
gray-overlay-opacity (ra/use-val 0)
|
||||
icon-opacity (reanimated/use-shared-value 1)
|
||||
red-overlay-opacity (reanimated/use-shared-value 0)
|
||||
gray-overlay-opacity (reanimated/use-shared-value 0)
|
||||
complete-animation (fn []
|
||||
(cond
|
||||
(and @ready-to-lock? (not @record-button-is-animating?))
|
||||
@@ -114,7 +114,7 @@
|
||||
signal-anim-duration)))
|
||||
stop-animation (fn []
|
||||
(set-value opacity 0)
|
||||
(ra/cancel-animation scale)
|
||||
(reanimated/cancel-animation scale)
|
||||
(set-value scale 1)
|
||||
(when @clear-timeout (js/clearTimeout @clear-timeout)))
|
||||
start-y-animation (fn []
|
||||
@@ -190,7 +190,7 @@
|
||||
(start-x-animation)
|
||||
(reset-x-animation)))
|
||||
[@ready-to-delete?])
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (style/record-button-big-container translate-x translate-y opacity)
|
||||
:pointer-events :none}
|
||||
[:<>
|
||||
@@ -203,9 +203,9 @@
|
||||
:color rings-color}])
|
||||
animations)]
|
||||
[rn/view {:style (style/record-button-big-body button-color)}
|
||||
[ra/view {:style (style/record-button-big-red-overlay red-overlay-opacity)}]
|
||||
[ra/view {:style (style/record-button-big-gray-overlay gray-overlay-opacity)}]
|
||||
[ra/view {:style (style/record-button-big-icon-container icon-opacity)}
|
||||
[reanimated/view {:style (style/record-button-big-red-overlay red-overlay-opacity)}]
|
||||
[reanimated/view {:style (style/record-button-big-gray-overlay gray-overlay-opacity)}]
|
||||
[reanimated/view {:style (style/record-button-big-icon-container icon-opacity)}
|
||||
(if @locked?
|
||||
[rn/view {:style style/stop-icon}]
|
||||
[icons/icon :i/audio {:color icon-color}])]]]))])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [quo2.components.icon :as icons]
|
||||
[quo2.components.record-audio.record-audio.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.core :refer [use-effect]]
|
||||
[quo2.components.record-audio.record-audio.helpers :refer
|
||||
[animate-linear
|
||||
@@ -14,13 +14,13 @@
|
||||
[recording? ready-to-send? reviewing-audio?]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [opacity (ra/use-val 0)
|
||||
translate-y (ra/use-val 20)
|
||||
connector-opacity (ra/use-val 0)
|
||||
width (ra/use-val 12)
|
||||
height (ra/use-val 24)
|
||||
border-radius-first-half (ra/use-val 16)
|
||||
border-radius-second-half (ra/use-val 8)
|
||||
(let [opacity (reanimated/use-shared-value 0)
|
||||
translate-y (reanimated/use-shared-value 20)
|
||||
connector-opacity (reanimated/use-shared-value 0)
|
||||
width (reanimated/use-shared-value 12)
|
||||
height (reanimated/use-shared-value 24)
|
||||
border-radius-first-half (reanimated/use-shared-value 16)
|
||||
border-radius-second-half (reanimated/use-shared-value 8)
|
||||
start-y-animation (fn []
|
||||
(animate-linear-with-delay translate-y 12 50 133.33)
|
||||
(animate-easing-with-delay connector-opacity 1 0 93.33)
|
||||
@@ -74,14 +74,14 @@
|
||||
@recording? (reset-y-animation)))
|
||||
[@ready-to-send?])
|
||||
[:<>
|
||||
[ra/view {:style (style/send-button-container opacity)}
|
||||
[ra/view
|
||||
[reanimated/view {:style (style/send-button-container opacity)}
|
||||
[reanimated/view
|
||||
{:style (style/send-button-connector connector-opacity
|
||||
width
|
||||
height
|
||||
border-radius-first-half
|
||||
border-radius-second-half)}]]
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (style/send-button translate-y opacity)
|
||||
:pointer-events :none}
|
||||
[icons/icon :i/arrow-up
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns quo2.components.record-audio.record-audio.helpers
|
||||
(:require [react-native.reanimated :as ra]))
|
||||
(:require [react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn animate-linear
|
||||
[shared-value value duration]
|
||||
(ra/animate
|
||||
(reanimated/animate-shared-value-with-timing
|
||||
shared-value
|
||||
value
|
||||
duration
|
||||
@@ -11,26 +11,26 @@
|
||||
|
||||
(defn animate-linear-with-delay
|
||||
[shared-value value duration delay]
|
||||
(ra/animate-delay
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
shared-value
|
||||
value
|
||||
delay
|
||||
duration
|
||||
:linear))
|
||||
:linear
|
||||
delay))
|
||||
|
||||
(defn animate-linear-with-delay-loop
|
||||
[shared-value value duration delay]
|
||||
(ra/animate-delay-repeat
|
||||
(reanimated/animate-shared-value-with-delay-repeat
|
||||
shared-value
|
||||
value
|
||||
delay
|
||||
-1
|
||||
duration
|
||||
:linear))
|
||||
:linear
|
||||
delay
|
||||
-1))
|
||||
|
||||
(defn animate-easing
|
||||
[shared-value value duration]
|
||||
(ra/animate
|
||||
(reanimated/animate-shared-value-with-timing
|
||||
shared-value
|
||||
value
|
||||
duration
|
||||
@@ -38,13 +38,13 @@
|
||||
|
||||
(defn animate-easing-with-delay
|
||||
[shared-value value duration delay]
|
||||
(ra/animate-delay
|
||||
(reanimated/animate-shared-value-with-delay
|
||||
shared-value
|
||||
value
|
||||
delay
|
||||
duration
|
||||
:easing1))
|
||||
:easing1
|
||||
delay))
|
||||
|
||||
(defn set-value
|
||||
[shared-value value]
|
||||
(ra/set-val shared-value value))
|
||||
(reanimated/set-shared-value shared-value value))
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns quo2.components.record-audio.record-audio.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn animated-circle
|
||||
[scale opacity color]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:scale scale}]
|
||||
:opacity opacity}
|
||||
{:width 56
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
(defn record-button-big-container
|
||||
[translate-x translate-y opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}
|
||||
{:translateX translate-x}]
|
||||
:opacity opacity}
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
(defn record-button-big-red-overlay
|
||||
[red-overlay-opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity red-overlay-opacity}
|
||||
{:position :absolute
|
||||
:top 0
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
(defn record-button-big-gray-overlay
|
||||
[gray-overlay-opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity gray-overlay-opacity}
|
||||
{:position :absolute
|
||||
:top 0
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
(defn record-button-big-icon-container
|
||||
[icon-opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity icon-opacity}
|
||||
{}))
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
(defn send-button-container
|
||||
[opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
(defn send-button-connector
|
||||
[opacity width height border-radius-first-half border-radius-second-half]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity
|
||||
:width width
|
||||
:height height
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
(defn send-button
|
||||
[translate-y opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]
|
||||
:opacity opacity}
|
||||
{:justify-content :center
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
(defn lock-button-container
|
||||
[opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
{:transform [{:rotate "45deg"}]
|
||||
:justify-content :center
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
(defn lock-button-connector
|
||||
[opacity width height border-radius-first-half border-radius-second-half]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity
|
||||
:width width
|
||||
:height height
|
||||
@@ -154,7 +154,7 @@
|
||||
|
||||
(defn lock-button
|
||||
[translate-x-y opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translateX translate-x-y}
|
||||
{:translateY translate-x-y}]
|
||||
:opacity opacity}
|
||||
@@ -172,7 +172,7 @@
|
||||
|
||||
(defn delete-button-container
|
||||
[opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
@@ -184,7 +184,7 @@
|
||||
|
||||
(defn delete-button-connector
|
||||
[opacity width height border-radius-first-half border-radius-second-half]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity
|
||||
:width width
|
||||
:height height
|
||||
@@ -200,7 +200,7 @@
|
||||
|
||||
(defn delete-button
|
||||
[scale translate-x opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translateX translate-x}
|
||||
{:scale scale}]
|
||||
:opacity opacity}
|
||||
@@ -217,7 +217,7 @@
|
||||
|
||||
(defn record-button-container
|
||||
[opacity]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
{:margin-bottom 32
|
||||
:margin-right 32}))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
(:require [react-native.core :as rn]))
|
||||
|
||||
(defn style-container
|
||||
[size disabled border-color border-width background-color labelled? type]
|
||||
[size disabled border-color border-width background-color label type]
|
||||
(merge {:height size
|
||||
:border-color border-color
|
||||
:background-color background-color
|
||||
@@ -12,23 +12,14 @@
|
||||
:justify-content :center}
|
||||
(when disabled
|
||||
{:opacity 0.3})
|
||||
(when (and (or (= type :icon) (= type :emoji)) (not labelled?))
|
||||
(when (and (or (= type :icon) (= type :emoji)) (not label))
|
||||
{:width size})))
|
||||
|
||||
(defn base-tag
|
||||
[_]
|
||||
(fn
|
||||
[{:keys [id
|
||||
size
|
||||
disabled?
|
||||
border-color
|
||||
border-width
|
||||
background-color
|
||||
on-press
|
||||
accessibility-label
|
||||
type
|
||||
labelled?]
|
||||
:or {size 32}} children]
|
||||
(fn [{:keys [id size disabled? border-color border-width background-color on-press
|
||||
accessibility-label labelled? type]
|
||||
:or {size 32}} children]
|
||||
[rn/touchable-without-feedback
|
||||
(merge {:disabled disabled?
|
||||
:accessibility-label accessibility-label}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
:text-color {:style {:color colors/white}}}}})
|
||||
|
||||
(defn tag-resources
|
||||
[size type resource icon-color label text-color labelled?]
|
||||
[size type resource icon-color label text-color labelled]
|
||||
[rn/view
|
||||
{:style (merge {:flex-direction :row
|
||||
:align-items :center
|
||||
@@ -46,14 +46,16 @@
|
||||
24 12)
|
||||
:color icon-color}])
|
||||
(when (= type :emoji)
|
||||
[text/text
|
||||
{:style {:margin-right 4}
|
||||
:size (case size
|
||||
32 :paragraph-1
|
||||
24 :paragraph-2
|
||||
nil)}
|
||||
resource])
|
||||
(when labelled?
|
||||
[rn/image
|
||||
{:source resource
|
||||
:style (merge (case size
|
||||
32 {:height 20
|
||||
:width 20}
|
||||
24 {:height 12
|
||||
:width 12})
|
||||
(when label
|
||||
{:margin-right 4}))}])
|
||||
(when labelled
|
||||
[text/text
|
||||
(merge {:size (case size
|
||||
32 :paragraph-1
|
||||
@@ -68,7 +70,6 @@
|
||||
(defn tag
|
||||
"opts
|
||||
{:type :icon/:emoji/:label
|
||||
:label string
|
||||
:size 32/24
|
||||
:on-press fn
|
||||
:blurred? true/false
|
||||
@@ -81,26 +82,14 @@
|
||||
- `type` can be icon or emoji with or without a tag label
|
||||
- `labelled` boolean: is true if tag has label else false"
|
||||
[_ _]
|
||||
(fn
|
||||
[{:keys [id
|
||||
on-press
|
||||
disabled?
|
||||
size
|
||||
active
|
||||
accessibility-label
|
||||
label
|
||||
resource
|
||||
type
|
||||
labelled?
|
||||
blurred?
|
||||
icon-color
|
||||
override-theme]
|
||||
:or {size 32}}]
|
||||
(fn [{:keys [id on-press disabled? size resource active accessibility-label
|
||||
label type labelled? blurred? icon-color]
|
||||
:or {size 32}}]
|
||||
(let [state (cond disabled? :disabled
|
||||
active :active
|
||||
:else :default)
|
||||
{:keys [border-color blurred-border-color text-color]}
|
||||
(get-in themes [(or override-theme (theme/get-theme)) state])]
|
||||
(get-in themes [(theme/get-theme) state])]
|
||||
[rn/view {:style {:align-items :center}}
|
||||
[base-tag/base-tag
|
||||
{:id id
|
||||
|
||||
@@ -138,9 +138,7 @@
|
||||
:blurred? blurred?
|
||||
:icon-color icon-color
|
||||
:disabled? disabled?
|
||||
:label (if labelled?
|
||||
label
|
||||
(when (= type :label) label))
|
||||
:label label
|
||||
:type type
|
||||
:labelled? labelled?
|
||||
:on-press (fn [id]
|
||||
@@ -152,18 +150,17 @@
|
||||
:index index
|
||||
:viewPosition 0.5}))
|
||||
(when on-change
|
||||
(on-change id)))}]])})])
|
||||
(on-change id)))}
|
||||
label]])})])
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
(for [{:keys [id label resource]} data]
|
||||
(for [{:keys [label id resource]} data]
|
||||
^{:key id}
|
||||
[rn/view {:style {:margin-right 8}}
|
||||
[tag/tag
|
||||
(merge {:id id
|
||||
:size size
|
||||
:type type
|
||||
:label (if labelled?
|
||||
label
|
||||
(when (= type :label) label))
|
||||
:label (if labelled? label (when (= type :label) label))
|
||||
:active (= id active-tab-id)
|
||||
:disabled? disabled?
|
||||
:blurred? blurred?
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
quo2.components.avatars.channel-avatar
|
||||
quo2.components.avatars.group-avatar
|
||||
quo2.components.avatars.icon-avatar
|
||||
quo2.components.avatars.user-avatar
|
||||
quo2.components.avatars.user-avatar.view
|
||||
quo2.components.avatars.wallet-user-avatar
|
||||
quo2.components.banners.banner.view
|
||||
quo2.components.buttons.button
|
||||
@@ -102,7 +102,7 @@
|
||||
(def channel-avatar quo2.components.avatars.channel-avatar/channel-avatar)
|
||||
(def group-avatar quo2.components.avatars.group-avatar/group-avatar)
|
||||
(def icon-avatar quo2.components.avatars.icon-avatar/icon-avatar)
|
||||
(def user-avatar quo2.components.avatars.user-avatar/user-avatar)
|
||||
(def user-avatar quo2.components.avatars.user-avatar.view/user-avatar)
|
||||
(def wallet-user-avatar quo2.components.avatars.wallet-user-avatar/wallet-user-avatar)
|
||||
|
||||
;;;; BANNER
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns quo2.core-spec
|
||||
(:require [quo2.components.banners.banner.component-spec]
|
||||
(:require [quo2.components.avatars.user-avatar.component-spec]
|
||||
[quo2.components.banners.banner.component-spec]
|
||||
[quo2.components.buttons.--tests--.buttons-component-spec]
|
||||
[quo2.components.counter.--tests--.counter-component-spec]
|
||||
[quo2.components.dividers.--tests--.divider-label-component-spec]
|
||||
|
||||
@@ -58,6 +58,11 @@
|
||||
(def neutral-95 "#0D1625")
|
||||
(def neutral-100 "#09101C")
|
||||
|
||||
;;Blur
|
||||
(def neutral-5-opa-70 (alpha neutral-5 0.7))
|
||||
(def neutral-80-blur-opa-80 "rgba(25,36,56,0.8)")
|
||||
(def neutral-90-opa-70 (alpha neutral-90 0.7))
|
||||
|
||||
;;80 with transparency
|
||||
(def neutral-80-opa-5 (alpha neutral-80 0.05))
|
||||
(def neutral-80-opa-10 (alpha neutral-80 0.1))
|
||||
@@ -110,14 +115,6 @@
|
||||
(def white-opa-90 (alpha white 0.9))
|
||||
(def white-opa-95 (alpha white 0.95))
|
||||
|
||||
;;;;Blur
|
||||
(def white-70-blur (alpha white 0.7))
|
||||
(def neutral-5-opa-70-blur (alpha neutral-5 0.7))
|
||||
(def neutral-80-opa-80-blur (alpha "#192438" 0.8))
|
||||
(def neutral-90-opa-70-blur (alpha neutral-90 0.7))
|
||||
(def neutral-95-opa-70-blur neutral-95-opa-70)
|
||||
(def neutral-100-opa-70-blur neutral-100-opa-70)
|
||||
|
||||
;;;;Black
|
||||
|
||||
;;Solid
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
[react-native.flat-list :as rn-flat-list]
|
||||
[utils.collection]))
|
||||
|
||||
;;; Constants
|
||||
(def ^:const default-duration 300)
|
||||
;; Animations
|
||||
(def slide-in-up-animation SlideInUp)
|
||||
(def slide-out-up-animation SlideOutUp)
|
||||
(def linear-transition LinearTransition)
|
||||
|
||||
;;; Worklets
|
||||
(def worklet-factory (js/require "../src/js/worklet_factory.js"))
|
||||
|
||||
;;; Animated Components
|
||||
;; Animated Components
|
||||
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
|
||||
|
||||
(def view (reagent/adapt-react-class (.-View reanimated)))
|
||||
@@ -35,22 +34,18 @@
|
||||
(defn flat-list
|
||||
[props]
|
||||
[reanimated-flat-list (rn-flat-list/base-list-props props)])
|
||||
|
||||
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
|
||||
|
||||
(def linear-gradient (create-animated-component LinearGradient))
|
||||
(def fast-image (create-animated-component FastImage))
|
||||
(def blur-view (create-animated-component (.-BlurView blur)))
|
||||
|
||||
;;; Easings
|
||||
(def in-out (.-inOut ^js Easing))
|
||||
(def bezier (.-bezier ^js Easing))
|
||||
(def easings
|
||||
{:default (in-out (.-quad ^js Easing))
|
||||
:linear (bezier 0 0 1 1)
|
||||
:easing1 (bezier 0.25 0.1 0.25 1)
|
||||
:easing2 (bezier 0 0.3 0.6 0.9)
|
||||
:easing3 (bezier 0.3 0.3 0.3 0.9)})
|
||||
;; Hooks
|
||||
(def use-shared-value useSharedValue)
|
||||
(def use-animated-style useAnimatedStyle)
|
||||
|
||||
;;; Animations
|
||||
;; Animations
|
||||
(def with-timing withTiming)
|
||||
(def with-delay withDelay)
|
||||
(def with-spring withSpring)
|
||||
@@ -58,103 +53,112 @@
|
||||
(def key-frame Keyframe)
|
||||
(def with-repeat withRepeat)
|
||||
(def cancel-animation cancelAnimation)
|
||||
(defn with-repeat-timing
|
||||
[val reps reverse? duration easing]
|
||||
(with-repeat
|
||||
(with-timing val
|
||||
(clj->js {:duration duration
|
||||
:easing (get easings easing)}))
|
||||
reps
|
||||
reverse?))
|
||||
|
||||
;; Easings
|
||||
(def bezier (.-bezier ^js Easing))
|
||||
|
||||
;;; Hooks and Helpers
|
||||
(def use-val useSharedValue)
|
||||
(defn get-val
|
||||
(def in-out
|
||||
(.-inOut ^js Easing))
|
||||
|
||||
(def easings
|
||||
{:linear (bezier 0 0 1 1)
|
||||
:easing1 (bezier 0.25 0.1 0.25 1)
|
||||
:easing2 (bezier 0 0.3 0.6 0.9)
|
||||
:easing3 (bezier 0.3 0.3 0.3 0.9)})
|
||||
|
||||
;; Helper functions
|
||||
(defn get-shared-value
|
||||
[anim]
|
||||
(when anim
|
||||
(.-value anim)))
|
||||
(defn set-val
|
||||
|
||||
(defn set-shared-value
|
||||
[anim val]
|
||||
(when (and anim (some? val))
|
||||
(set! (.-value anim) val)))
|
||||
|
||||
;;; Executing animation functions
|
||||
(defn animate
|
||||
([animation value]
|
||||
(animate animation value default-duration :default))
|
||||
([animation value duration]
|
||||
(animate animation value duration :default))
|
||||
([animation value duration easing]
|
||||
(set-val animation
|
||||
(with-timing value
|
||||
(clj->js {:duration duration
|
||||
:easing (get easings easing)})))))
|
||||
|
||||
(defn animate-spring
|
||||
[animation val {:keys [damping mass stiffness]}]
|
||||
(set-val animation
|
||||
(with-spring val
|
||||
(clj->js {:damping damping
|
||||
:mass mass
|
||||
:stiffness stiffness}))))
|
||||
|
||||
(defn animate-decay
|
||||
([animation velocity]
|
||||
(animate-decay animation velocity []))
|
||||
([animation velocity clamp]
|
||||
(set-val animation
|
||||
(with-decay (clj->js {:velocity velocity
|
||||
:clamp clamp})))))
|
||||
|
||||
(defn animate-delay
|
||||
([animation val delay]
|
||||
(animate-delay animation val delay default-duration :default))
|
||||
([animation val delay duration]
|
||||
(animate-delay animation val delay duration :default))
|
||||
([animation val delay duration easing]
|
||||
(set-val animation
|
||||
(with-delay delay
|
||||
(with-timing val
|
||||
(clj->js {:duration duration
|
||||
:easing (get easings easing)}))))))
|
||||
|
||||
(defn animate-repeat
|
||||
([animation val reps]
|
||||
(animate-repeat animation val reps false default-duration :default))
|
||||
([animation val reps reverse?]
|
||||
(animate-repeat animation val reps reverse? default-duration :default))
|
||||
([animation val reps reverse? duration]
|
||||
(animate-repeat animation val reps reverse? duration :default))
|
||||
([animation val reps reverse? duration easing]
|
||||
(set-val animation (with-repeat-timing val reps reverse? duration easing))))
|
||||
|
||||
(defn animate-delay-repeat
|
||||
([animation val duration easing delay reps]
|
||||
(animate-delay-repeat animation val duration easing delay reps false))
|
||||
([animation val duration easing delay reps reverse?]
|
||||
(set-val animation (with-delay delay (with-repeat-timing val reps reverse? duration easing)))))
|
||||
;; Worklets
|
||||
(def worklet-factory (js/require "../src/js/worklet_factory.js"))
|
||||
|
||||
(defn interpolate
|
||||
([val input-range output-range]
|
||||
(interpolate val input-range output-range nil))
|
||||
([val input-range output-range extrapolation]
|
||||
([shared-value input-range output-range]
|
||||
(interpolate shared-value input-range output-range nil))
|
||||
([shared-value input-range output-range extrapolation]
|
||||
(.interpolateValue ^js worklet-factory
|
||||
val
|
||||
shared-value
|
||||
(clj->js input-range)
|
||||
(clj->js output-range)
|
||||
(clj->js extrapolation))))
|
||||
|
||||
|
||||
;;; Styling
|
||||
(def use-animated-style useAnimatedStyle)
|
||||
;;;; Component Animations
|
||||
(defn apply-animations-to-style
|
||||
[animations style]
|
||||
(use-animated-style
|
||||
(.applyAnimationsToStyle ^js worklet-factory (clj->js animations) (clj->js style))))
|
||||
|
||||
;; Animators
|
||||
(defn animate-shared-value-with-timing
|
||||
[anim val duration easing]
|
||||
(set-shared-value anim
|
||||
(with-timing val
|
||||
(js-obj "duration" duration
|
||||
"easing" (get easings easing)))))
|
||||
|
||||
;;; Built-in Animations
|
||||
(def slide-in-up-animation SlideInUp)
|
||||
(def slide-out-up-animation SlideOutUp)
|
||||
(def linear-transition LinearTransition)
|
||||
(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-delay-default-easing
|
||||
[anim val duration delay]
|
||||
(set-shared-value anim
|
||||
(with-delay delay
|
||||
(with-timing val
|
||||
(js-obj "duration" duration
|
||||
"easing" (in-out (.-quad ^js 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?)))
|
||||
|
||||
(defn animate-shared-value-with-delay-repeat
|
||||
([anim val duration easing delay number-of-repetitions]
|
||||
(animate-shared-value-with-delay-repeat anim val duration easing delay number-of-repetitions false))
|
||||
([anim val duration easing delay number-of-repetitions reverse?]
|
||||
(set-shared-value anim
|
||||
(with-delay delay
|
||||
(with-repeat
|
||||
(with-timing val
|
||||
#js
|
||||
{:duration duration
|
||||
:easing (get easings easing)})
|
||||
number-of-repetitions
|
||||
reverse?)))))
|
||||
|
||||
(defn animate-shared-value-with-spring
|
||||
[anim val {:keys [mass stiffness damping]}]
|
||||
(set-shared-value anim
|
||||
(with-spring val
|
||||
(js-obj "mass" mass
|
||||
"damping" damping
|
||||
"stiffness" stiffness))))
|
||||
|
||||
(defn animate-shared-value-with-decay
|
||||
[anim velocity clamp]
|
||||
(set-shared-value anim
|
||||
(with-decay (clj->js {:velocity velocity
|
||||
:clamp clamp}))))
|
||||
|
||||
(defn with-timing-duration
|
||||
[val duration]
|
||||
(with-timing val
|
||||
(clj->js {:duration duration
|
||||
:easing (in-out (.-quad ^js Easing))})))
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :creating-backup?] backup-type))}
|
||||
(when (:multiaccount db)
|
||||
(navigation/navigate-to-cofx :my-profile nil))
|
||||
(navigation/change-tab :browser-stack)) ;; Profile tab - Currently browser tab is used for
|
||||
;; profile
|
||||
(navigation/navigate-to-cofx :seed-phrase nil)))
|
||||
|
||||
(rf/defn recovery-card-pressed
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
:status nil))
|
||||
:hide-popover nil})
|
||||
(when (:multiaccount db)
|
||||
(navigation/navigate-to-cofx :my-profile nil))
|
||||
(navigation/change-tab :browser-stack)) ;; Profile tab - Currently browser tab is used for profile
|
||||
(when-not (:multiaccounts/login db)
|
||||
(if (:popover/popover db)
|
||||
(navigation/navigate-replace :keycard-pin nil)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.multiaccounts.login.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.async-storage.core :as async-storage]
|
||||
[status-im.communities.core :as communities]
|
||||
@@ -44,7 +43,8 @@
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[status-im2.common.log :as logging]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.security.core :as security]))
|
||||
[utils.security.core :as security]
|
||||
[status-im2.contexts.emoji-hash.events :as emoji-hash]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::initialize-communities-enabled
|
||||
@@ -388,10 +388,7 @@
|
||||
(let [{:networks/keys [current-network networks]
|
||||
:as settings}
|
||||
(data-store.settings/rpc->settings settings)
|
||||
multiaccount (-> settings
|
||||
(dissoc :networks/current-network :networks/networks)
|
||||
(set/rename-keys {:compressedKey :compressed-key
|
||||
:emojiHash :emoji-hash}))
|
||||
multiaccount (dissoc settings :networks/current-network :networks/networks)
|
||||
;;for some reason we save default networks in db, in case when we want to modify default-networks
|
||||
;;for
|
||||
;; existing accounts we have to merge them again into networks
|
||||
@@ -475,6 +472,7 @@
|
||||
(get-group-chat-invitations)
|
||||
(multiaccounts/get-profile-picture)
|
||||
(multiaccounts/switch-preview-privacy-mode-flag)
|
||||
(emoji-hash/fetch-for-current-public-key)
|
||||
(link-preview/request-link-preview-whitelist)
|
||||
(visibility-status-updates-store/fetch-visibility-status-updates-rpc)
|
||||
(switcher-cards-store/fetch-switcher-cards-rpc))))
|
||||
|
||||
@@ -481,6 +481,12 @@
|
||||
(when (validators/valid-public-key? public-key)
|
||||
(.generateAliasAsync ^js (status) public-key callback)))
|
||||
|
||||
(defn public-key->emoji-hash
|
||||
"Generate an emoji hash from the multiaccount public key"
|
||||
[public-key callback]
|
||||
(when (validators/valid-public-key? public-key)
|
||||
(.emojiHash ^js (status) public-key callback)))
|
||||
|
||||
(defn identicon
|
||||
"Generate a icon based on a string, synchronously"
|
||||
[seed]
|
||||
|
||||
@@ -64,9 +64,8 @@
|
||||
(let [own (new-chat.db/own-public-key? db public-key)]
|
||||
(cond
|
||||
(and public-key own)
|
||||
(rf/merge cofx
|
||||
{:pop-to-root-fx :shell-stack}
|
||||
(navigation/navigate-to-cofx :my-profile nil))
|
||||
{:shell/change-tab-fx :browser-stack ;; Profile tab - Currently browser tab is used for profile
|
||||
:pop-to-root-fx :shell-stack}
|
||||
|
||||
(and public-key (not own))
|
||||
(rf/merge cofx
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
(ns status-im.ui.screens.onboarding.intro.styles
|
||||
(:require [quo.animated :as animated]
|
||||
[quo.design-system.colors :as colors]))
|
||||
|
||||
(def dot-size 6)
|
||||
(def progress-size 36)
|
||||
|
||||
(def intro-view
|
||||
{:flex 1
|
||||
:justify-content :flex-end
|
||||
:margin-bottom 12})
|
||||
|
||||
(defn dot-selector
|
||||
[]
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-bottom 16
|
||||
:align-items :center})
|
||||
|
||||
(defn dot-style
|
||||
[active]
|
||||
{:background-color colors/blue-light
|
||||
:overflow :hidden
|
||||
:opacity 1
|
||||
:margin-horizontal 2
|
||||
:width (animated/mix active dot-size progress-size)
|
||||
:height dot-size
|
||||
:border-radius 3})
|
||||
|
||||
(defn dot-progress
|
||||
[active progress]
|
||||
{:background-color colors/blue
|
||||
:height dot-size
|
||||
:width progress-size
|
||||
:opacity (animated/mix active 0 1)
|
||||
:transform [{:translateX (animated/mix progress (- progress-size) 0)}]})
|
||||
|
||||
(defn wizard-text-with-height
|
||||
[height]
|
||||
(merge {:color colors/gray
|
||||
:text-align :center}
|
||||
(when-not (zero? height)
|
||||
{:height height})))
|
||||
|
||||
(def wizard-title
|
||||
{:margin-bottom 16
|
||||
:text-align :center})
|
||||
@@ -0,0 +1,204 @@
|
||||
(ns status-im.ui.screens.onboarding.intro.views
|
||||
(:require [quo.animated :as animated]
|
||||
[quo.core :as quo]
|
||||
[quo.design-system.colors :as colors]
|
||||
[quo.design-system.typography :as typography]
|
||||
[quo.react-native :as rn]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.onboarding.intro.styles :as styles]))
|
||||
|
||||
(defonce index (reagent/atom 0))
|
||||
|
||||
(defn code
|
||||
[val]
|
||||
^{:key val}
|
||||
[animated/code {:exec val}])
|
||||
|
||||
(defn dot
|
||||
[]
|
||||
(let [active (animated/value 0)
|
||||
active-transition (animated/with-timing-transition active {:duration 100})]
|
||||
(fn [{:keys [selected progress]}]
|
||||
[animated/view {:style (styles/dot-style active-transition)}
|
||||
[code (animated/set active (if selected 1 0))]
|
||||
[animated/view {:style (styles/dot-progress active-transition progress)}]])))
|
||||
|
||||
(defn dots-selector
|
||||
[{:keys [n progress]}]
|
||||
(let [selected @index]
|
||||
[react/view {:style (styles/dot-selector)}
|
||||
(for [i (range n)]
|
||||
^{:key i}
|
||||
[dot
|
||||
{:progress progress
|
||||
:selected (= selected i)}])]))
|
||||
|
||||
(defn slides-view
|
||||
[slides width]
|
||||
(let [height (reagent/atom 0)
|
||||
text-height (reagent/atom 0)
|
||||
text-temp-height (atom 0)
|
||||
text-temp-timer (atom nil)]
|
||||
(fn [_]
|
||||
[:<>
|
||||
(doall
|
||||
(for [s slides]
|
||||
^{:key (:title s)}
|
||||
[react/view
|
||||
{:style {:flex 1
|
||||
:width width
|
||||
:justify-content :flex-end
|
||||
:align-items :center
|
||||
:padding-horizontal 32}}
|
||||
(let [size (min width @height)]
|
||||
[react/view
|
||||
{:style {:flex 1}
|
||||
:on-layout (fn [^js e]
|
||||
(let [new-height (-> e .-nativeEvent .-layout .-height)]
|
||||
(swap! height #(if (pos? %) (min % new-height) new-height))))}
|
||||
[react/image
|
||||
{:source (:image s)
|
||||
:resize-mode :contain
|
||||
:style {:width size
|
||||
:height size}}]])
|
||||
[quo/text
|
||||
{:style styles/wizard-title
|
||||
:align :center
|
||||
:weight :bold
|
||||
:size :x-large}
|
||||
(i18n/label (:title s))]
|
||||
[quo/text
|
||||
{:style (styles/wizard-text-with-height @text-height)
|
||||
:on-layout
|
||||
(fn [^js e]
|
||||
(let [new-height (-> e .-nativeEvent .-layout .-height)]
|
||||
(when (and (not= new-height @text-temp-height)
|
||||
(not (zero? new-height))
|
||||
(< new-height 200))
|
||||
(swap! text-temp-height #(if (pos? %) (max % new-height) new-height))
|
||||
(when @text-temp-timer (js/clearTimeout @text-temp-timer))
|
||||
(reset! text-temp-timer
|
||||
(js/setTimeout #(reset! text-height @text-temp-height) 500)))))}
|
||||
(i18n/label (:text s))]]))])))
|
||||
|
||||
(defn carousel
|
||||
[slides width]
|
||||
;;TODO this is really not the best implementation, must be a better way
|
||||
(let [scroll-x (reagent/atom 0)
|
||||
scroll-view-ref (atom nil)
|
||||
|
||||
manual-scroll (atom false)
|
||||
progress (animated/value 1)
|
||||
autoscroll (animated/value 1)
|
||||
finished (animated/value 0)
|
||||
clock (animated/clock)
|
||||
go-next (fn []
|
||||
(let [x (if (>= @scroll-x
|
||||
(- (* (dec (count slides))
|
||||
width)
|
||||
5))
|
||||
0
|
||||
(+ @scroll-x width))]
|
||||
(reset! index (Math/round (/ x width)))
|
||||
(some-> ^js @scroll-view-ref
|
||||
(.scrollTo #js {:x x :animated true}))))
|
||||
code (animated/block
|
||||
[(animated/cond* (animated/and* (animated/not* (animated/clock-running clock))
|
||||
autoscroll)
|
||||
(animated/start-clock clock))
|
||||
(animated/cond* (animated/and* (animated/clock-running clock)
|
||||
(animated/not* autoscroll))
|
||||
[(animated/stop-clock clock)
|
||||
(animated/set finished 1)])
|
||||
(animated/set progress
|
||||
(animated/cancelable-loop
|
||||
{:clock clock
|
||||
:finished finished
|
||||
:duration 4000
|
||||
:on-reach go-next}))])
|
||||
cancel-animation (fn []
|
||||
(reset! manual-scroll true)
|
||||
(animated/set-value autoscroll 0))
|
||||
restart-animation (fn []
|
||||
(animated/set-value autoscroll 1))]
|
||||
(fn [_ _]
|
||||
[react/view
|
||||
{:style {:align-items :center
|
||||
:flex 1
|
||||
:justify-content :flex-end}}
|
||||
[animated/code {:exec code}]
|
||||
[react/scroll-view
|
||||
{:horizontal true
|
||||
:paging-enabled true
|
||||
:ref #(reset! scroll-view-ref %)
|
||||
:shows-vertical-scroll-indicator false
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:pinch-gesture-enabled false
|
||||
:scroll-event-throttle 16
|
||||
:on-scroll #(let [x (.-nativeEvent.contentOffset.x ^js %)]
|
||||
(when @manual-scroll
|
||||
;; NOTE: Will be not synced if velocity is big
|
||||
(reset! index (Math/round (/ x width))))
|
||||
(reset! scroll-x x))
|
||||
:on-scroll-begin-drag cancel-animation
|
||||
:on-scroll-end-drag restart-animation
|
||||
:on-momentum-scroll-end #(reset! manual-scroll false)
|
||||
:style {:margin-bottom 16}}
|
||||
[slides-view slides width]]
|
||||
[dots-selector
|
||||
{:progress progress
|
||||
:n (count slides)}]])))
|
||||
|
||||
(defonce tos-accepted (reagent/atom false))
|
||||
|
||||
(defn intro
|
||||
[]
|
||||
[react/view {:style styles/intro-view}
|
||||
[carousel
|
||||
[{:image (resources/get-theme-image :chat)
|
||||
:title :intro-title1
|
||||
:text :intro-text1}
|
||||
{:image (resources/get-theme-image :wallet)
|
||||
:title :intro-title2
|
||||
:text :intro-text2}
|
||||
{:image (resources/get-theme-image :browser)
|
||||
:title :intro-title3
|
||||
:text :intro-text3}]
|
||||
@(re-frame/subscribe [:dimensions/window-width])]
|
||||
[react/view {:style {:align-items :center}}
|
||||
[react/view
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:align-items :center
|
||||
:margin-top 36
|
||||
:margin-bottom 24}
|
||||
[quo/checkbox
|
||||
{:value @tos-accepted
|
||||
:on-change #(swap! tos-accepted not)}]
|
||||
[rn/touchable-opacity {:test-ID :terms-of-service :on-press #(swap! tos-accepted not)}
|
||||
[react/nested-text {:style {:margin-left 12}}
|
||||
(i18n/label :t/accept-status-tos-prefix)
|
||||
[{:style (merge {:color colors/blue}
|
||||
typography/font-medium)
|
||||
:on-press #(re-frame/dispatch [:open-modal :terms-of-service])
|
||||
:accessibility-label :terms-of-service-link}
|
||||
" "
|
||||
(i18n/label :t/terms-of-service)]]]]
|
||||
[react/view {:style {:margin-bottom 24}}
|
||||
[quo/button
|
||||
{:test-ID :get-started
|
||||
:disabled (not @tos-accepted)
|
||||
:on-press #(do (re-frame/dispatch [:init-root :onboarding])
|
||||
;; clear atom state for next use
|
||||
(reset! tos-accepted false)
|
||||
(re-frame/dispatch [:hide-terms-of-services-opt-in-screen]))}
|
||||
(i18n/label :t/get-started)]]
|
||||
[react/text
|
||||
{:style {:color colors/blue}
|
||||
:on-press #(re-frame/dispatch [:open-modal :privacy-policy])
|
||||
:accessibility-label :privacy-policy-link}
|
||||
(i18n/label :t/privacy-policy)]]])
|
||||
@@ -60,6 +60,7 @@
|
||||
[status-im.ui.screens.notifications-settings.views :as notifications-settings]
|
||||
[status-im.ui.screens.offline-messaging-settings.edit-mailserver.views :as edit-mailserver]
|
||||
[status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings]
|
||||
[status-im.ui.screens.onboarding.intro.views :as onboarding.intro]
|
||||
[status-im.ui.screens.onboarding.keys.views :as onboarding.keys]
|
||||
[status-im.ui.screens.onboarding.notifications.views :as onboarding.notifications]
|
||||
[status-im.ui.screens.onboarding.password.views :as onboarding.password]
|
||||
@@ -129,6 +130,11 @@
|
||||
{:name :progress
|
||||
:component progress/progress}
|
||||
|
||||
;[Onboarding]
|
||||
{:name :intro
|
||||
:insets {:bottom true}
|
||||
:component onboarding.intro/intro}
|
||||
|
||||
;[Onboarding]
|
||||
{:name :get-your-keys
|
||||
:insets {:bottom true}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.ui2.screens.chat.pin-limit-popover.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
(fn []
|
||||
(let [width (rf/sub [:dimensions/window-width])
|
||||
show-pin-limit-modal? (rf/sub [:chats/pin-modal chat-id])
|
||||
opacity-animation (ra/use-val 0)
|
||||
z-index-animation (ra/use-val -1)]
|
||||
opacity-animation (reanimated/use-shared-value 0)
|
||||
z-index-animation (reanimated/use-shared-value -1)]
|
||||
(react/effect!
|
||||
#(do
|
||||
(ra/set-val opacity-animation
|
||||
(ra/with-timing (if show-pin-limit-modal? 1 0)))
|
||||
(ra/set-val z-index-animation
|
||||
(ra/with-timing (if show-pin-limit-modal? 10 -1)))))
|
||||
(reanimated/set-shared-value opacity-animation
|
||||
(reanimated/with-timing (if show-pin-limit-modal? 1 0)))
|
||||
(reanimated/set-shared-value z-index-animation
|
||||
(reanimated/with-timing (if show-pin-limit-modal? 10 -1)))))
|
||||
(when show-pin-limit-modal?
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity opacity-animation
|
||||
:z-index z-index-animation}
|
||||
(style/pin-popover width))
|
||||
|
||||
@@ -109,9 +109,8 @@
|
||||
(log/info "universal-links: handling view profile" public-key)
|
||||
(cond
|
||||
(and public-key (new-chat.db/own-public-key? db public-key))
|
||||
(rf/merge cofx
|
||||
{:pop-to-root-fx :shell-stack}
|
||||
(navigation/navigate-to-cofx :my-profile nil))
|
||||
{:shell/change-tab-fx :browser-stack ;; Profile tab - Currently browser tab is used for profile
|
||||
:pop-to-root-fx :shell-stack}
|
||||
|
||||
public-key
|
||||
{:dispatch [:chat.ui/show-profile public-key ens-name]}))
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
(defn with-animation
|
||||
[value & [options callback]]
|
||||
(ra/with-spring
|
||||
(reanimated/with-spring
|
||||
value
|
||||
(clj->js (merge {:mass 2
|
||||
:stiffness 500
|
||||
@@ -45,12 +45,12 @@
|
||||
max-pan-down (if @expanded?
|
||||
bg-height-expanded
|
||||
bg-height)]
|
||||
(ra/set-val pan-y
|
||||
(max
|
||||
(min
|
||||
(.-translationY evt)
|
||||
max-pan-down)
|
||||
max-pan-up))))))
|
||||
(reanimated/set-shared-value pan-y
|
||||
(max
|
||||
(min
|
||||
(.-translationY evt)
|
||||
max-pan-down)
|
||||
max-pan-up))))))
|
||||
(gesture/on-end
|
||||
(fn [_]
|
||||
(reset! gesture-running? false)
|
||||
@@ -127,8 +127,8 @@
|
||||
{:keys [keyboard-shown]} (hooks/use-keyboard)
|
||||
bg-height-expanded (- window-height (:top insets))
|
||||
bg-height (max (min @content-height bg-height-expanded) 109)
|
||||
bottom-sheet-dy (ra/use-val 0)
|
||||
pan-y (ra/use-val 0)
|
||||
bottom-sheet-dy (reanimated/use-shared-value 0)
|
||||
pan-y (reanimated/use-shared-value 0)
|
||||
translate-y (.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y)
|
||||
bg-opacity
|
||||
(.useBackgroundOpacity ^js bottom-sheet-js translate-y bg-height window-height)
|
||||
@@ -136,11 +136,11 @@
|
||||
(let [height (oget evt "nativeEvent" "layout" "height")]
|
||||
(reset! content-height height)))
|
||||
on-expanded (fn []
|
||||
(ra/set-val bottom-sheet-dy bg-height-expanded)
|
||||
(ra/set-val pan-y 0))
|
||||
(reanimated/set-shared-value bottom-sheet-dy bg-height-expanded)
|
||||
(reanimated/set-shared-value pan-y 0))
|
||||
on-collapsed (fn []
|
||||
(ra/set-val bottom-sheet-dy bg-height)
|
||||
(ra/set-val pan-y 0))
|
||||
(reanimated/set-shared-value bottom-sheet-dy bg-height)
|
||||
(reanimated/set-shared-value pan-y 0))
|
||||
bottom-sheet-gesture (get-bottom-sheet-gesture
|
||||
pan-y
|
||||
translate-y
|
||||
@@ -185,38 +185,38 @@
|
||||
@show-bottom-sheet?
|
||||
(if @expanded?
|
||||
(do
|
||||
(ra/set-val
|
||||
(reanimated/set-shared-value
|
||||
bottom-sheet-dy
|
||||
(with-animation (+ bg-height-expanded (.-value pan-y))))
|
||||
;; Workaround for
|
||||
;; https://github.com/software-mansion/react-native-ra/issues/1758#issue-817145741
|
||||
;; https://github.com/software-mansion/react-native-reanimated/issues/1758#issue-817145741
|
||||
;; withTiming/withSpring callback not working
|
||||
;; on-expanded should be called as a callback of
|
||||
;; with-animation instead, once this issue has been resolved
|
||||
(timer/set-timeout on-expanded animation-delay))
|
||||
(do
|
||||
(ra/set-val
|
||||
(reanimated/set-shared-value
|
||||
bottom-sheet-dy
|
||||
(with-animation (+ bg-height (.-value pan-y))))
|
||||
;; Workaround for
|
||||
;; https://github.com/software-mansion/react-native-ra/issues/1758#issue-817145741
|
||||
;; https://github.com/software-mansion/react-native-reanimated/issues/1758#issue-817145741
|
||||
;; withTiming/withSpring callback not working
|
||||
;; on-collapsed should be called as a callback of
|
||||
;; with-animation instead, once this issue has been resolved
|
||||
(timer/set-timeout on-collapsed animation-delay)))
|
||||
|
||||
(= @show-bottom-sheet? false)
|
||||
(ra/set-val bottom-sheet-dy (with-animation 0)))))
|
||||
(reanimated/set-shared-value bottom-sheet-dy (with-animation 0)))))
|
||||
[@show-bottom-sheet? @expanded? @gesture-running?])
|
||||
|
||||
[:<>
|
||||
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity}
|
||||
styles/backdrop)}]]
|
||||
(cond->> [ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
(cond->> [reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
{:width window-width
|
||||
:height window-height})}
|
||||
|
||||
@@ -2,15 +2,10 @@
|
||||
|
||||
(def ui
|
||||
{:add-new-contact (js/require "../resources/images/ui2/add-contact.png")
|
||||
:intro-1 (js/require "../resources/images/ui2/intro-1.png")
|
||||
:intro-2 (js/require "../resources/images/ui2/intro-2.png")
|
||||
:intro-3 (js/require "../resources/images/ui2/intro-3.png")
|
||||
:intro-4 (js/require "../resources/images/ui2/intro-4.png")
|
||||
:lifestyle (js/require "../resources/images/ui2/lifestyle.png")
|
||||
:music (js/require "../resources/images/ui2/music.png")
|
||||
:podcasts (js/require "../resources/images/ui2/podcasts.png")
|
||||
:sync-device (js/require "../resources/images/ui2/sync-new-device-cover-background.png")
|
||||
:onboarding-bg-1 (js/require "../resources/images/ui2/onboarding-bg-1.png")})
|
||||
:sync-device (js/require "../resources/images/ui2/sync-new-device-cover-background.png")})
|
||||
|
||||
(def mock-images
|
||||
{:coinbase (js/require "../resources/images/mock2/coinbase.png")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns status-im2.common.scroll-page.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn image-slider
|
||||
[size]
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
(defn blur-slider
|
||||
[animation height]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY animation}]}
|
||||
{:z-index 5
|
||||
:position :absolute
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
(defn sticky-header-title
|
||||
[animation]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity animation}
|
||||
{:position :absolute
|
||||
:flex-direction :row
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
(defn display-picture-container
|
||||
[animation]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:scale animation}]}
|
||||
{:border-radius 50
|
||||
:border-width 1
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.common.scroll-page.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn icon-color
|
||||
[]
|
||||
@@ -31,30 +31,30 @@
|
||||
height
|
||||
name
|
||||
page-nav
|
||||
logo
|
||||
cover
|
||||
sticky-header
|
||||
top-nav
|
||||
title-colum
|
||||
navigate-back?]
|
||||
(let [input-range (if platform/ios? [-47 10] [0 10])
|
||||
output-range (if platform/ios? [-208 0] [-208 -45])
|
||||
y (ra/use-val scroll-height)
|
||||
translate-animation (ra/interpolate y
|
||||
input-range
|
||||
output-range
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"})
|
||||
opacity-animation (ra/use-val 0)
|
||||
y (reanimated/use-shared-value scroll-height)
|
||||
translate-animation (reanimated/interpolate y
|
||||
input-range
|
||||
output-range
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"})
|
||||
opacity-animation (reanimated/use-shared-value 0)
|
||||
threshold (if platform/ios? 30 170)]
|
||||
(rn/use-effect
|
||||
#(do
|
||||
(ra/set-val y scroll-height)
|
||||
(ra/set-val opacity-animation
|
||||
(ra/with-timing (if (>= scroll-height threshold) 1 0)
|
||||
(clj->js {:duration 300}))))
|
||||
(reanimated/set-shared-value y scroll-height)
|
||||
(reanimated/set-shared-value opacity-animation
|
||||
(reanimated/with-timing (if (>= scroll-height threshold) 1 0)
|
||||
(clj->js {:duration 300}))))
|
||||
[scroll-height])
|
||||
[:<>
|
||||
[ra/blur-view
|
||||
[reanimated/blur-view
|
||||
{:blur-amount 20
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
@@ -65,11 +65,11 @@
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0}}
|
||||
(when logo
|
||||
[ra/view
|
||||
(when cover
|
||||
[reanimated/view
|
||||
{:style (style/sticky-header-title opacity-animation)}
|
||||
[rn/image
|
||||
{:source logo
|
||||
{:source cover
|
||||
:style style/sticky-header-image}]
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
@@ -101,17 +101,17 @@
|
||||
(defn display-picture
|
||||
[scroll-height cover]
|
||||
(let [input-range (if platform/ios? [-67 10] [0 150])
|
||||
y (ra/use-val scroll-height)
|
||||
animation (ra/interpolate y
|
||||
input-range
|
||||
[1.2 0.5]
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"})]
|
||||
y (reanimated/use-shared-value scroll-height)
|
||||
animation (reanimated/interpolate y
|
||||
input-range
|
||||
[1.2 0.5]
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"})]
|
||||
(rn/use-effect #(do
|
||||
(ra/set-val y scroll-height)
|
||||
(reanimated/set-shared-value y scroll-height)
|
||||
js/undefined)
|
||||
[scroll-height])
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (style/display-picture-container animation)}
|
||||
[rn/image
|
||||
{:source cover
|
||||
@@ -122,7 +122,6 @@
|
||||
(let [scroll-height (reagent/atom negative-scroll-position-0)]
|
||||
(fn
|
||||
[{:keys [cover-image
|
||||
logo
|
||||
page-nav-right-section-buttons
|
||||
name
|
||||
on-scroll
|
||||
@@ -135,7 +134,7 @@
|
||||
children]
|
||||
[:<>
|
||||
[:f> scroll-page-header @scroll-height height name page-nav-right-section-buttons
|
||||
logo sticky-header top-nav title-colum navigate-back?]
|
||||
cover-image sticky-header top-nav title-colum navigate-back?]
|
||||
[rn/scroll-view
|
||||
{:content-container-style (style/scroll-view-container
|
||||
(diff-with-max-min @scroll-height 16 0))
|
||||
@@ -163,5 +162,5 @@
|
||||
:border-radius (diff-with-max-min @scroll-height 16 0)
|
||||
:background-color background-color}
|
||||
(when cover-image
|
||||
[:f> display-picture @scroll-height logo])
|
||||
[:f> display-picture @scroll-height cover-image])
|
||||
children])]])))
|
||||
|
||||
@@ -2,26 +2,26 @@
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.utils.utils :as utils.utils]
|
||||
[status-im2.common.toasts.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
;; (def ^:private slide-out-up-animation
|
||||
;; (-> ^js ra/slide-out-up-animation
|
||||
;; (-> ^js reanimated/slide-out-up-animation
|
||||
;; .springify
|
||||
;; (.damping 20)
|
||||
;; (.stiffness 300)))
|
||||
|
||||
;; (def ^:private slide-in-up-animation
|
||||
;; (-> ^js ra/slide-in-up-animation
|
||||
;; (-> ^js reanimated/slide-in-up-animation
|
||||
;; .springify
|
||||
;; (.damping 20)
|
||||
;; (.stiffness 300)))
|
||||
|
||||
;; (def ^:private linear-transition
|
||||
;; (-> ^js ra/linear-transition
|
||||
;; (-> ^js reanimated/linear-transition
|
||||
;; .springify
|
||||
;; (.damping 20)
|
||||
;; (.stiffness 300)))
|
||||
@@ -44,7 +44,7 @@
|
||||
on-dismissed #((or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity) id)
|
||||
create-timer (fn []
|
||||
(reset! timer (utils.utils/set-timeout close! duration)))
|
||||
translate-y (ra/use-val 0)
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
pan
|
||||
(->
|
||||
(gesture/gesture-pan)
|
||||
@@ -56,38 +56,38 @@
|
||||
(cond
|
||||
;; reset translate y on pan down
|
||||
(> evt-translation-y 100)
|
||||
(ra/animate-spring translate-y
|
||||
0
|
||||
{:mass 1
|
||||
:damping 20
|
||||
:stiffness 300})
|
||||
(reanimated/animate-shared-value-with-spring translate-y
|
||||
0
|
||||
{:mass 1
|
||||
:damping 20
|
||||
:stiffness 300})
|
||||
;; dismiss on pan up
|
||||
(< evt-translation-y -30)
|
||||
(do (ra/animate-spring
|
||||
(do (reanimated/animate-shared-value-with-spring
|
||||
translate-y
|
||||
-500
|
||||
{:mass 1 :damping 20 :stiffness 300})
|
||||
(reset! dismissed-locally? true)
|
||||
(close!))
|
||||
:else
|
||||
(ra/set-val translate-y
|
||||
evt-translation-y)))))
|
||||
(reanimated/set-shared-value translate-y
|
||||
evt-translation-y)))))
|
||||
(gesture/on-end (fn [_]
|
||||
(when-not @dismissed-locally?
|
||||
(ra/set-val translate-y 0)
|
||||
(reanimated/set-shared-value translate-y 0)
|
||||
(create-timer)))))]
|
||||
;; create auto dismiss timer, clear timer when unmount or duration changed
|
||||
(rn/use-effect (fn [] (create-timer) clear-timer) [duration])
|
||||
(rn/use-unmount on-dismissed)
|
||||
[gesture/gesture-detector {:gesture pan}
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{;; TODO: this will eanble layout animation at runtime and causing flicker on android
|
||||
;; we need to resolve this and re-enable layout animation
|
||||
;; issue at https://github.com/status-im/status-mobile/issues/14752
|
||||
;; :entering slide-in-up-animation
|
||||
;; :exiting slide-out-up-animation
|
||||
;; :layout ra/linear-transition
|
||||
:style (ra/apply-animations-to-style
|
||||
;; :layout reanimated/linear-transition
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
style/each-toast-container)}
|
||||
[toast id]]]))])))
|
||||
|
||||
@@ -215,9 +215,9 @@
|
||||
(def album-image-sizes ; sometimes we subtract 1 or 0.5 for padding
|
||||
{2 {0 image-size
|
||||
1 image-size}
|
||||
3 {0 [(* image-size 2) (* image-size 1.25)]
|
||||
1 [(- image-size 0.5) (- (* image-size 0.75) 1)]
|
||||
2 [(- image-size 0.5) (- (* image-size 0.75) 1)]}
|
||||
3 {0 [(* image-size 2) (* image-size 1.5)]
|
||||
1 [(- image-size 0.5) (- (* image-size 0.67) 1)]
|
||||
2 [(- image-size 0.5) (- (* image-size 0.67) 1)]}
|
||||
4 {0 image-size
|
||||
1 image-size
|
||||
2 image-size
|
||||
|
||||
@@ -353,8 +353,3 @@
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :lightbox/orientation value)})
|
||||
|
||||
(rf/defn lightbox-scale
|
||||
{:events [:chat.ui/lightbox-scale]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :lightbox/scale value)})
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
(:require
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.lightbox.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.lightbox.common :as common]))
|
||||
|
||||
(def small-image-size 40)
|
||||
|
||||
@@ -24,10 +25,10 @@
|
||||
[:f>
|
||||
(fn []
|
||||
(let [size (if (= @scroll-index index) focused-image-size small-image-size)
|
||||
size-value (ra/use-val size)
|
||||
size-value (common/use-val size)
|
||||
{:keys [scroll-index-lock? small-list-ref
|
||||
flat-list-ref]} atoms]
|
||||
(ra/animate size-value size)
|
||||
(common/set-val-timing size-value size)
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
@@ -43,11 +44,11 @@
|
||||
#js {:animated true :index index}))
|
||||
(if platform/ios? 50 150))
|
||||
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]))}
|
||||
[ra/fast-image
|
||||
[reanimated/fast-image
|
||||
{:source {:uri (:image (:content item))}
|
||||
:style (ra/apply-animations-to-style {:width size-value
|
||||
:height size-value}
|
||||
{:border-radius 10})}]]))])
|
||||
:style (reanimated/apply-animations-to-style {:width size-value
|
||||
:height size-value}
|
||||
{:border-radius 10})}]]))])
|
||||
|
||||
(defn bottom-view
|
||||
[messages index scroll-index insets animations item-width atoms]
|
||||
@@ -55,25 +56,23 @@
|
||||
(fn []
|
||||
(let [text (get-in (first messages) [:content :text])
|
||||
padding-horizontal (- (/ item-width 2) (/ focused-image-size 2))]
|
||||
[ra/linear-gradient
|
||||
[reanimated/linear-gradient
|
||||
{:colors [:black :transparent]
|
||||
:start {:x 0 :y 1}
|
||||
:end {:x 0 :y 0}
|
||||
:style (style/gradient-container insets animations)}
|
||||
(when (not= text "placeholder")
|
||||
[rn/text {:style style/text-style} text])
|
||||
[rn/text
|
||||
{:style style/text-style} text]
|
||||
[rn/flat-list
|
||||
{:ref #(reset! (:small-list-ref atoms) %)
|
||||
:key-fn :message-id
|
||||
:style {:height small-list-height}
|
||||
:data messages
|
||||
:render-fn small-image
|
||||
:render-data {:scroll-index scroll-index
|
||||
:atoms atoms}
|
||||
:horizontal true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:get-item-layout get-small-item-layout
|
||||
:separator [rn/view {:style {:width 8}}]
|
||||
:initial-scroll-index index
|
||||
:content-container-style (style/content-container padding-horizontal)}]]))])
|
||||
|
||||
{:ref #(reset! (:small-list-ref atoms) %)
|
||||
:key-fn :message-id
|
||||
:style {:height small-list-height}
|
||||
:data messages
|
||||
:render-fn small-image
|
||||
:render-data {:scroll-index scroll-index
|
||||
:atoms atoms}
|
||||
:horizontal true
|
||||
:get-item-layout get-small-item-layout
|
||||
:separator [rn/view {:style {:width 8}}]
|
||||
:initial-scroll-index index
|
||||
:content-container-style (style/content-container padding-horizontal)}]]))])
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
(ns status-im2.contexts.chat.lightbox.common
|
||||
(:require [react-native.reanimated :as reanimated]))
|
||||
|
||||
(def top-view-height 56)
|
||||
|
||||
;; TODO: Abstract Reanimated methods in a better way, issue:
|
||||
;; https://github.com/status-im/status-mobile/issues/15176
|
||||
(defn set-val-timing
|
||||
[animation value]
|
||||
(reanimated/set-shared-value animation (reanimated/with-timing value)))
|
||||
|
||||
(defn use-val
|
||||
[value]
|
||||
(reanimated/use-shared-value value))
|
||||
@@ -1,7 +1,8 @@
|
||||
(ns status-im2.contexts.chat.lightbox.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]))
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.lightbox.common :as common]))
|
||||
|
||||
;;;; MAIN-VIEW
|
||||
(def container-view
|
||||
@@ -9,25 +10,24 @@
|
||||
|
||||
;;;; TOP-VIEW
|
||||
(defn top-view-container
|
||||
[top-inset {:keys [opacity rotate top-view-y top-view-x top-view-width top-view-bg top-layout]}
|
||||
window-width
|
||||
[top-inset {:keys [opacity rotate top-view-y top-view-x top-view-width top-view-bg]} window-width
|
||||
bg-color]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
(if platform/ios?
|
||||
{:transform [{:translateY top-layout}
|
||||
{:rotate rotate}
|
||||
{:transform [{:rotate rotate}
|
||||
{:translateY top-view-y}
|
||||
{:translateX top-view-x}]
|
||||
:opacity opacity
|
||||
:width top-view-width
|
||||
:background-color top-view-bg}
|
||||
{:transform [{:translateY top-layout}]
|
||||
{:transform [{:rotate rotate}
|
||||
{:translateY top-view-y}
|
||||
{:translateX top-view-x}]
|
||||
:opacity opacity})
|
||||
{:position :absolute
|
||||
:padding-horizontal 20
|
||||
:top (if platform/ios? top-inset 0)
|
||||
;; height defined in top_view.cljs, but can't import due to circular dependency
|
||||
:height 56
|
||||
:height common/top-view-height
|
||||
:z-index 4
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
@@ -48,10 +48,9 @@
|
||||
|
||||
;;;; BOTTOM-VIEW
|
||||
(defn gradient-container
|
||||
[insets {:keys [opacity bottom-layout]}]
|
||||
(ra/apply-animations-to-style
|
||||
{:transform [{:translateY bottom-layout}]
|
||||
:opacity opacity}
|
||||
[insets {:keys [opacity]}]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
{:position :absolute
|
||||
:bottom 0
|
||||
:padding-bottom (:bottom insets)
|
||||
|
||||
@@ -5,39 +5,38 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.orientation :as orientation]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.lightbox.common :as common]
|
||||
[status-im2.contexts.chat.lightbox.style :as style]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def ^:const top-view-height 56)
|
||||
|
||||
(defn animate-rotation
|
||||
[result screen-width screen-height insets-atom
|
||||
{:keys [rotate top-view-y top-view-x top-view-width top-view-bg]}]
|
||||
(let [top-x (+ (/ top-view-height 2) (:top insets-atom))]
|
||||
(let [top-x (+ (/ common/top-view-height 2) (:top insets-atom))]
|
||||
(cond
|
||||
(= result orientation/landscape-left)
|
||||
(do
|
||||
(ra/animate rotate "90deg")
|
||||
(ra/animate top-view-y 60)
|
||||
(ra/animate top-view-x (- (/ screen-height 2) top-x))
|
||||
(ra/animate top-view-width screen-height)
|
||||
(ra/animate top-view-bg colors/neutral-100-opa-70))
|
||||
(common/set-val-timing rotate "90deg")
|
||||
(common/set-val-timing top-view-y 60)
|
||||
(common/set-val-timing top-view-x (- (/ screen-height 2) top-x))
|
||||
(common/set-val-timing top-view-width screen-height)
|
||||
(common/set-val-timing top-view-bg colors/neutral-100-opa-70))
|
||||
(= result orientation/landscape-right)
|
||||
(do
|
||||
(ra/animate rotate "-90deg")
|
||||
(ra/animate top-view-y (- (- screen-width) 4))
|
||||
(ra/animate top-view-x (+ (/ screen-height -2) top-x))
|
||||
(ra/animate top-view-width screen-height)
|
||||
(ra/animate top-view-bg colors/neutral-100-opa-70))
|
||||
(common/set-val-timing rotate "-90deg")
|
||||
(common/set-val-timing top-view-y (- (- screen-width) 4))
|
||||
(common/set-val-timing top-view-x (+ (/ screen-height -2) top-x))
|
||||
(common/set-val-timing top-view-width screen-height)
|
||||
(common/set-val-timing top-view-bg colors/neutral-100-opa-70))
|
||||
(= result orientation/portrait)
|
||||
(do
|
||||
(ra/animate rotate "0deg")
|
||||
(ra/animate top-view-y 0)
|
||||
(ra/animate top-view-x 0)
|
||||
(ra/animate top-view-width screen-width)
|
||||
(ra/animate top-view-bg colors/neutral-100-opa-0)))))
|
||||
(common/set-val-timing rotate "0deg")
|
||||
(common/set-val-timing top-view-y 0)
|
||||
(common/set-val-timing top-view-x 0)
|
||||
(common/set-val-timing top-view-width screen-width)
|
||||
(common/set-val-timing top-view-bg colors/neutral-100-opa-0)))))
|
||||
|
||||
(defn top-view
|
||||
[{:keys [from timestamp]} insets index animations landscape? screen-width]
|
||||
@@ -45,17 +44,15 @@
|
||||
(fn []
|
||||
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
|
||||
bg-color (if landscape? colors/neutral-100-opa-70 colors/neutral-100-opa-0)]
|
||||
[ra/view
|
||||
[reanimated/view
|
||||
{:style (style/top-view-container (:top insets) animations screen-width bg-color)}
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:align-items :center}}
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(ra/animate (:opacity animations) 0)
|
||||
(rf/dispatch (if platform/ios?
|
||||
[:chat.ui/exit-lightbox-signal @index]
|
||||
[:navigate-back])))
|
||||
{:on-press #(rf/dispatch (if platform/ios?
|
||||
[:chat.ui/exit-lightbox-signal @index]
|
||||
[:navigate-back]))
|
||||
:style style/close-container}
|
||||
[quo/icon :close {:size 20 :color colors/white}]]
|
||||
[rn/view {:style {:margin-left 12}}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.orientation :as orientation]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.contexts.chat.lightbox.common :as common]
|
||||
[utils.re-frame :as rf]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
@@ -19,18 +20,18 @@
|
||||
|
||||
(defn toggle-opacity
|
||||
[opacity-value border-value transparent? index {:keys [small-list-ref]}]
|
||||
(let [opacity (ra/get-val opacity-value)]
|
||||
(let [opacity (reanimated/get-shared-value opacity-value)]
|
||||
(if (= opacity 1)
|
||||
(do
|
||||
(ra/animate opacity-value 0)
|
||||
(common/set-val-timing opacity-value 0)
|
||||
(js/setTimeout #(reset! transparent? (not @transparent?)) 400))
|
||||
(do
|
||||
(reset! transparent? (not @transparent?))
|
||||
(ra/animate-delay opacity-value 1 50)
|
||||
(reanimated/animate-shared-value-with-delay-default-easing opacity-value 1 300 50)
|
||||
(js/setTimeout #(when @small-list-ref
|
||||
(.scrollToIndex ^js @small-list-ref #js {:animated false :index index}))
|
||||
100)))
|
||||
(ra/animate border-value (if (= opacity 1) 0 12))))
|
||||
(common/set-val-timing border-value (if (= opacity 1) 0 12))))
|
||||
|
||||
(defn handle-orientation
|
||||
[result index window animations {:keys [flat-list-ref insets-atom]}]
|
||||
@@ -93,7 +94,7 @@
|
||||
(let [{:keys [messages index]} (rf/sub [:get-screen-params])
|
||||
atoms {:flat-list-ref (atom nil)
|
||||
:small-list-ref (atom nil)
|
||||
:scroll-index-lock? (atom true)
|
||||
:scroll-index-lock? (atom false)
|
||||
:insets-atom (atom nil)}
|
||||
;; The initial value of data is the image that was pressed (and not the whole album) in order
|
||||
;; for the transition animation to execute properly, otherwise it would animate towards
|
||||
@@ -102,19 +103,16 @@
|
||||
scroll-index (reagent/atom index)
|
||||
transparent? (reagent/atom false)
|
||||
window (rf/sub [:dimensions/window])
|
||||
animations {:border (ra/use-val (if platform/ios? 0 12))
|
||||
:opacity (ra/use-val 0)
|
||||
:rotate (ra/use-val "0deg")
|
||||
:top-layout (ra/use-val -10)
|
||||
:bottom-layout (ra/use-val 10)
|
||||
:top-view-y (ra/use-val 0)
|
||||
:top-view-x (ra/use-val 0)
|
||||
:top-view-width (ra/use-val (:width window))
|
||||
:top-view-bg (ra/use-val colors/neutral-100-opa-0)}
|
||||
animations {:border (common/use-val 12)
|
||||
:opacity (common/use-val 1)
|
||||
:rotate (common/use-val "0deg")
|
||||
:top-view-y (common/use-val 0)
|
||||
:top-view-x (common/use-val 0)
|
||||
:top-view-width (common/use-val (:width window))
|
||||
:top-view-bg (common/use-val colors/neutral-100-opa-0)}
|
||||
|
||||
callback (fn [e]
|
||||
(on-viewable-items-changed e scroll-index atoms))]
|
||||
(println "aims" (ra/get-val (:opacity animations)))
|
||||
(reset! data messages)
|
||||
(orientation/use-device-orientation-change
|
||||
(fn [result]
|
||||
@@ -126,21 +124,11 @@
|
||||
;; RNN does not support landscape-right
|
||||
(when (and enabled? (not= result orientation/landscape-right))
|
||||
(handle-orientation result scroll-index window animations atoms)))))))
|
||||
(rn/use-effect (fn []
|
||||
(when @(:flat-list-ref atoms)
|
||||
(.scrollToIndex ^js @(:flat-list-ref atoms)
|
||||
#js {:animated false :index index}))
|
||||
(js/setTimeout (fn []
|
||||
(ra/animate (:opacity animations) 1)
|
||||
(ra/animate (:top-layout animations) 0)
|
||||
(ra/animate (:bottom-layout animations) 0)
|
||||
(ra/animate (:border animations) 12))
|
||||
(if platform/ios? 250 100))
|
||||
(js/setTimeout #(reset! (:scroll-index-lock? atoms) false) 300)
|
||||
(fn []
|
||||
(rf/dispatch [:chat.ui/zoom-out-signal nil])
|
||||
(when platform/android?
|
||||
(rf/dispatch [:chat.ui/lightbox-scale 1])))))
|
||||
(rn/use-effect-once (fn []
|
||||
(when @(:flat-list-ref atoms)
|
||||
(.scrollToIndex ^js @(:flat-list-ref atoms)
|
||||
#js {:animated false :index index}))
|
||||
js/undefined))
|
||||
[safe-area/consumer
|
||||
(fn [insets]
|
||||
(let [curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
(ns status-im2.contexts.chat.lightbox.zoomable-image.style
|
||||
(:require
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]))
|
||||
(:require [react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn container
|
||||
[{:keys [width height]}
|
||||
{:keys [pan-x pan-y pinch-x pinch-y scale]}
|
||||
set-full-height?]
|
||||
(ra/apply-animations-to-style
|
||||
{:keys [pan-x pan-y pinch-x pinch-y scale]}]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translateX pan-x}
|
||||
{:translateY pan-y}
|
||||
{:translateX pinch-x}
|
||||
@@ -15,14 +12,14 @@
|
||||
{:scale scale}]}
|
||||
{:justify-content :center
|
||||
:align-items :center
|
||||
:width (if platform/ios? width "100%")
|
||||
:height (if set-full-height? "100%" height)}))
|
||||
:width width
|
||||
:height height}))
|
||||
|
||||
(defn image
|
||||
[{:keys [image-width image-height]}
|
||||
{:keys [rotate rotate-scale]}
|
||||
border-radius]
|
||||
(ra/apply-animations-to-style
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:rotate rotate}
|
||||
{:scale rotate-scale}]
|
||||
:border-radius border-radius}
|
||||
|
||||
@@ -3,96 +3,10 @@
|
||||
[clojure.string :as string]
|
||||
[react-native.orientation :as orientation]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as ra]
|
||||
[status-im2.contexts.chat.lightbox.zoomable-image.constants :as c]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
;;; Helpers
|
||||
(defn center-x
|
||||
[{:keys [pinch-x pinch-x-start pan-x pan-x-start]} exit?]
|
||||
(let [duration (if exit? 100 c/default-duration)]
|
||||
(ra/animate pinch-x c/init-offset duration)
|
||||
(ra/set-val pinch-x-start c/init-offset)
|
||||
(ra/animate pan-x c/init-offset duration)
|
||||
(ra/set-val pan-x-start c/init-offset)))
|
||||
|
||||
(defn center-y
|
||||
[{:keys [pinch-y pinch-y-start pan-y pan-y-start]} exit?]
|
||||
(let [duration (if exit? 100 c/default-duration)]
|
||||
(ra/animate pinch-y c/init-offset duration)
|
||||
(ra/set-val pinch-y-start c/init-offset)
|
||||
(ra/animate pan-y c/init-offset duration)
|
||||
(ra/set-val pan-y-start c/init-offset)))
|
||||
|
||||
(defn reset-values
|
||||
[exit? animations {:keys [focal-x focal-y]}]
|
||||
(center-x animations exit?)
|
||||
(center-y animations exit?)
|
||||
(reset! focal-x nil)
|
||||
(reset! focal-y nil))
|
||||
|
||||
(defn rescale-image
|
||||
[value
|
||||
exit?
|
||||
{:keys [x-threshold-scale y-threshold-scale]}
|
||||
{:keys [scale saved-scale] :as animations}
|
||||
{:keys [pan-x-enabled? pan-y-enabled?] :as props}]
|
||||
(ra/animate scale value (if exit? 100 c/default-duration))
|
||||
(ra/set-val saved-scale value)
|
||||
(when (= value c/min-scale)
|
||||
(reset-values exit? animations props))
|
||||
(reset! pan-x-enabled? (> value x-threshold-scale))
|
||||
(reset! pan-y-enabled? (> value y-threshold-scale))
|
||||
(when platform/android?
|
||||
(rf/dispatch [:chat.ui/lightbox-scale value])))
|
||||
|
||||
;;; Handlers
|
||||
(defn handle-orientation-change
|
||||
[curr-orientation
|
||||
focused?
|
||||
{:keys [landscape-scale-val x-threshold-scale y-threshold-scale]}
|
||||
{:keys [rotate rotate-scale scale] :as animations}
|
||||
{:keys [pan-x-enabled? pan-y-enabled?]}]
|
||||
(let [duration (when focused? c/default-duration)]
|
||||
(cond
|
||||
(= curr-orientation orientation/landscape-left)
|
||||
(do
|
||||
(ra/animate rotate "90deg" duration)
|
||||
(ra/animate rotate-scale landscape-scale-val duration))
|
||||
(= curr-orientation orientation/landscape-right)
|
||||
(do
|
||||
(ra/animate rotate "-90deg" duration)
|
||||
(ra/animate rotate-scale landscape-scale-val duration))
|
||||
(= curr-orientation orientation/portrait)
|
||||
(do
|
||||
(ra/animate rotate c/init-rotation duration)
|
||||
(ra/animate rotate-scale c/min-scale duration)))
|
||||
(center-x animations false)
|
||||
(center-y animations false)
|
||||
(reset! pan-x-enabled? (> (ra/get-val scale) x-threshold-scale))
|
||||
(reset! pan-y-enabled? (> (ra/get-val scale) y-threshold-scale))))
|
||||
|
||||
|
||||
(defn handle-exit-lightbox-signal
|
||||
"On ios, when attempting to navigate back while zoomed in, the shared-element transition animation
|
||||
doesn't execute properly, so we need to zoom out first"
|
||||
[exit-lightbox-signal index scale rescale set-full-height?]
|
||||
(when (= exit-lightbox-signal index)
|
||||
(reset! set-full-height? false)
|
||||
(if (> scale c/min-scale)
|
||||
(do
|
||||
(rescale c/min-scale true)
|
||||
(js/setTimeout #(rf/dispatch [:navigate-back]) 70))
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(js/setTimeout #(rf/dispatch [:chat.ui/exit-lightbox-signal nil]) 500)))
|
||||
|
||||
(defn handle-zoom-out-signal
|
||||
"Zooms out when pressing on another photo from the small bottom list"
|
||||
[zoom-out-signal index scale rescale]
|
||||
(when (and (= zoom-out-signal index) (> scale c/min-scale))
|
||||
(rescale c/min-scale true)))
|
||||
|
||||
;;; Dimensions
|
||||
(defn get-dimensions
|
||||
"Calculates all required dimensions. Dimensions calculations are different on iOS and Android because landscape
|
||||
mode is implemented differently.On Android, we just need to resize the content, and the OS takes care of the
|
||||
@@ -125,6 +39,24 @@
|
||||
:y-threshold-scale (/ screen-height (min screen-height container-height))
|
||||
:landscape-scale-val (/ portrait-image-width portrait-image-height)}))
|
||||
|
||||
(defn handle-exit-lightbox-signal
|
||||
"On ios, when attempting to navigate back while zoomed in, the shared-element transition animation
|
||||
doesn't execute properly, so we need to zoom out first"
|
||||
[exit-lightbox-signal index scale rescale]
|
||||
(when (= exit-lightbox-signal index)
|
||||
(if (> scale c/min-scale)
|
||||
(do
|
||||
(rescale c/min-scale true)
|
||||
(js/setTimeout #(rf/dispatch [:navigate-back]) 70))
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(js/setTimeout #(rf/dispatch [:chat.ui/exit-lightbox-signal nil]) 500)))
|
||||
|
||||
(defn handle-zoom-out-signal
|
||||
"Zooms out when pressing on another photo from the small bottom list"
|
||||
[zoom-out-signal index scale rescale]
|
||||
(when (and (= zoom-out-signal index) (> scale c/min-scale))
|
||||
(rescale c/min-scale true)))
|
||||
|
||||
|
||||
;;; MATH
|
||||
(defn get-max-offset
|
||||
@@ -149,11 +81,3 @@
|
||||
(defn get-pinch-position
|
||||
[scale-diff size focal]
|
||||
(* (- (/ size 2) focal) scale-diff))
|
||||
|
||||
(defn get-focal
|
||||
[focal size screen-size]
|
||||
(let [min (/ (- screen-size size) 2)
|
||||
max (+ min size)]
|
||||
(if (or (> focal max) (< focal min))
|
||||
(/ screen-size 2)
|
||||
focal)))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns status-im2.contexts.chat.lightbox.zoomable-image.view
|
||||
(:require
|
||||
[react-native.core :as rn]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
@@ -12,6 +11,96 @@
|
||||
[status-im2.contexts.chat.lightbox.zoomable-image.style :as style]
|
||||
[status-im2.contexts.chat.lightbox.zoomable-image.utils :as utils]))
|
||||
|
||||
;;;; Some aliases for reanimated methods, as they are used 10s of times in this file
|
||||
;; TODO: Abstract Reanimated methods in a better way, issue:
|
||||
;; https://github.com/status-im/status-mobile/issues/15176
|
||||
(defn get-val
|
||||
[animation]
|
||||
(reanimated/get-shared-value animation))
|
||||
|
||||
(defn set-val
|
||||
[animation value]
|
||||
(reanimated/set-shared-value animation value))
|
||||
|
||||
(defn use-val
|
||||
[value]
|
||||
(reanimated/use-shared-value value))
|
||||
|
||||
(defn timing
|
||||
([value]
|
||||
(timing value c/default-duration))
|
||||
([value duration]
|
||||
(if (= duration nil)
|
||||
value
|
||||
(reanimated/with-timing-duration value duration))))
|
||||
|
||||
(defn set-val-decay
|
||||
[animation velocity bounds]
|
||||
(reanimated/animate-shared-value-with-decay animation (* velocity c/velocity-factor) bounds))
|
||||
|
||||
;;;; Helpers
|
||||
(defn center-x
|
||||
[{:keys [pinch-x pinch-x-start pan-x pan-x-start]} exit?]
|
||||
(let [duration (if exit? 100 c/default-duration)]
|
||||
(set-val pinch-x (timing c/init-offset duration))
|
||||
(set-val pinch-x-start c/init-offset)
|
||||
(set-val pan-x (timing c/init-offset duration))
|
||||
(set-val pan-x-start c/init-offset)))
|
||||
|
||||
(defn center-y
|
||||
[{:keys [pinch-y pinch-y-start pan-y pan-y-start]} exit?]
|
||||
(let [duration (if exit? 100 c/default-duration)]
|
||||
(set-val pinch-y (timing c/init-offset duration))
|
||||
(set-val pinch-y-start c/init-offset)
|
||||
(set-val pan-y (timing c/init-offset duration))
|
||||
(set-val pan-y-start c/init-offset)))
|
||||
|
||||
(defn reset-values
|
||||
[exit? animations {:keys [focal-x focal-y]}]
|
||||
(center-x animations exit?)
|
||||
(center-y animations exit?)
|
||||
(reset! focal-x nil)
|
||||
(reset! focal-y nil))
|
||||
|
||||
(defn rescale-image
|
||||
[value
|
||||
exit?
|
||||
{:keys [x-threshold-scale y-threshold-scale]}
|
||||
{:keys [scale saved-scale] :as animations}
|
||||
{:keys [pan-x-enabled? pan-y-enabled?] :as props}]
|
||||
(set-val scale (timing value (if exit? 100 c/default-duration)))
|
||||
(set-val saved-scale value)
|
||||
(when (= value c/min-scale)
|
||||
(reset-values exit? animations props))
|
||||
(reset! pan-x-enabled? (> value x-threshold-scale))
|
||||
(reset! pan-y-enabled? (> value y-threshold-scale)))
|
||||
|
||||
(defn handle-orientation-change
|
||||
[curr-orientation
|
||||
focused?
|
||||
{:keys [landscape-scale-val x-threshold-scale y-threshold-scale]}
|
||||
{:keys [rotate rotate-scale scale] :as animations}
|
||||
{:keys [pan-x-enabled? pan-y-enabled?]}]
|
||||
(let [duration (when focused? c/default-duration)]
|
||||
(cond
|
||||
(= curr-orientation orientation/landscape-left)
|
||||
(do
|
||||
(set-val rotate (timing "90deg" duration))
|
||||
(set-val rotate-scale (timing landscape-scale-val duration)))
|
||||
(= curr-orientation orientation/landscape-right)
|
||||
(do
|
||||
(set-val rotate (timing "-90deg" duration))
|
||||
(set-val rotate-scale (timing landscape-scale-val duration)))
|
||||
(= curr-orientation orientation/portrait)
|
||||
(do
|
||||
(set-val rotate (timing c/init-rotation duration))
|
||||
(set-val rotate-scale (timing c/min-scale duration))))
|
||||
(center-x animations false)
|
||||
(center-y animations false)
|
||||
(reset! pan-x-enabled? (> (get-val scale) x-threshold-scale))
|
||||
(reset! pan-y-enabled? (> (get-val scale) y-threshold-scale))))
|
||||
|
||||
;;;; Gestures
|
||||
(defn tap-gesture
|
||||
[on-tap]
|
||||
(->
|
||||
@@ -27,109 +116,92 @@
|
||||
(gesture/number-of-taps 2)
|
||||
(gesture/on-start
|
||||
(fn [e]
|
||||
(if (= (reanimated/get-shared-value scale) c/min-scale)
|
||||
(if (= (get-val scale) c/min-scale)
|
||||
(let [translate-x (utils/get-double-tap-offset width screen-width (oget e "x"))
|
||||
translate-y (utils/get-double-tap-offset height screen-height (oget e "y"))]
|
||||
(when (> c/double-tap-scale x-threshold-scale)
|
||||
(reanimated/set-shared-value pan-x (reanimated/with-timing translate-x))
|
||||
(reanimated/set-shared-value pan-x-start translate-x))
|
||||
(set-val pan-x (timing translate-x))
|
||||
(set-val pan-x-start translate-x))
|
||||
(when (> c/double-tap-scale y-threshold-scale)
|
||||
(reanimated/set-shared-value pan-y (reanimated/with-timing translate-y))
|
||||
(reanimated/set-shared-value pan-y-start translate-y))
|
||||
(set-val pan-y (timing translate-y))
|
||||
(set-val pan-y-start translate-y))
|
||||
(rescale c/double-tap-scale))
|
||||
(rescale c/min-scale))))))
|
||||
|
||||
;; not using on-finalize because on-finalize gets called always regardless the gesture executed or not
|
||||
(defn finalize-pinch
|
||||
[{:keys [width height screen-height screen-width x-threshold-scale y-threshold-scale]}
|
||||
{:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pan-y pan-y-start pan-x
|
||||
pan-x-start]}
|
||||
{:keys [pan-x-enabled? pan-y-enabled?]}]
|
||||
(let [curr-offset-y (+ (reanimated/get-shared-value pan-y) (reanimated/get-shared-value pinch-y))
|
||||
max-offset-y (utils/get-max-offset height screen-height (reanimated/get-shared-value scale))
|
||||
max-offset-y (if (neg? curr-offset-y) (- max-offset-y) max-offset-y)
|
||||
curr-offset-x (+ (reanimated/get-shared-value pan-x) (reanimated/get-shared-value pinch-x))
|
||||
max-offset-x (utils/get-max-offset width screen-width (reanimated/get-shared-value scale))
|
||||
max-offset-x (if (neg? curr-offset-x) (- max-offset-x) max-offset-x)]
|
||||
(when (and (> (reanimated/get-shared-value scale) y-threshold-scale)
|
||||
(< (reanimated/get-shared-value scale) c/max-scale)
|
||||
(> (Math/abs curr-offset-y) (Math/abs max-offset-y)))
|
||||
(reanimated/set-shared-value pinch-y (reanimated/with-timing c/init-offset))
|
||||
(reanimated/set-shared-value pinch-y-start c/init-offset)
|
||||
(reanimated/set-shared-value pan-y (reanimated/with-timing max-offset-y))
|
||||
(reanimated/set-shared-value pan-y-start max-offset-y))
|
||||
(when (and (> (reanimated/get-shared-value scale) x-threshold-scale)
|
||||
(< (reanimated/get-shared-value scale) c/max-scale)
|
||||
(> (Math/abs curr-offset-x) (Math/abs max-offset-x)))
|
||||
(reanimated/set-shared-value pinch-x (reanimated/with-timing c/init-offset))
|
||||
(reanimated/set-shared-value pinch-x-start c/init-offset)
|
||||
(reanimated/set-shared-value pan-x (reanimated/with-timing max-offset-x))
|
||||
(reanimated/set-shared-value pan-x-start max-offset-x))
|
||||
(reset! pan-x-enabled? (> (reanimated/get-shared-value scale) x-threshold-scale))
|
||||
(reset! pan-y-enabled? (> (reanimated/get-shared-value scale) y-threshold-scale))
|
||||
(when platform/android?
|
||||
(rf/dispatch [:chat.ui/lightbox-scale (reanimated/get-shared-value saved-scale)]))))
|
||||
|
||||
(defn pinch-gesture
|
||||
[{:keys [width height screen-height screen-width x-threshold-scale y-threshold-scale] :as dimensions}
|
||||
{:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pinch-x-max pinch-y-max]
|
||||
[{:keys [width height screen-height screen-width x-threshold-scale y-threshold-scale]}
|
||||
{:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pinch-x-max pinch-y-max pan-y
|
||||
pan-y-start pan-x pan-x-start]
|
||||
:as animations}
|
||||
{:keys [focal-x focal-y] :as props}
|
||||
{:keys [pan-x-enabled? pan-y-enabled? focal-x focal-y]}
|
||||
rescale]
|
||||
(->
|
||||
(gesture/gesture-pinch)
|
||||
(gesture/on-begin (fn [e]
|
||||
(when platform/ios?
|
||||
(reset! focal-x (oget e "focalX"))
|
||||
(reset! focal-y (utils/get-focal (oget e "focalY") height screen-height)))))
|
||||
(reset! focal-y (oget e "focalY")))))
|
||||
(gesture/on-start (fn [e]
|
||||
(when platform/android?
|
||||
(reset! focal-x (utils/get-focal (oget e "focalX") width screen-width))
|
||||
(reset! focal-y (utils/get-focal (oget e "focalY") height screen-height)))))
|
||||
(gesture/on-update
|
||||
(fn [e]
|
||||
(let [new-scale (* (oget e "scale") (reanimated/get-shared-value saved-scale))
|
||||
scale-diff (utils/get-scale-diff new-scale (reanimated/get-shared-value saved-scale))
|
||||
new-pinch-x (utils/get-pinch-position scale-diff screen-width @focal-x)
|
||||
new-pinch-y (utils/get-pinch-position scale-diff screen-height @focal-y)]
|
||||
(when (and (>= new-scale c/max-scale)
|
||||
(= (reanimated/get-shared-value pinch-x-max) js/Infinity))
|
||||
(reanimated/set-shared-value pinch-x-max (reanimated/get-shared-value pinch-x))
|
||||
(reanimated/set-shared-value pinch-y-max (reanimated/get-shared-value pinch-y)))
|
||||
(reanimated/set-shared-value pinch-x
|
||||
(+ new-pinch-x (reanimated/get-shared-value pinch-x-start)))
|
||||
(reanimated/set-shared-value pinch-y
|
||||
(+ new-pinch-y (reanimated/get-shared-value pinch-y-start)))
|
||||
(reanimated/set-shared-value scale new-scale))))
|
||||
(reset! focal-x (oget e "focalX"))
|
||||
(reset! focal-y (oget e "focalY")))))
|
||||
(gesture/on-update (fn [e]
|
||||
(let [new-scale (* (oget e "scale") (get-val saved-scale))
|
||||
scale-diff (utils/get-scale-diff new-scale (get-val saved-scale))
|
||||
new-pinch-x (utils/get-pinch-position scale-diff width @focal-x)
|
||||
new-pinch-y (utils/get-pinch-position scale-diff height @focal-y)]
|
||||
(when (and (>= new-scale c/max-scale) (= (get-val pinch-x-max) js/Infinity))
|
||||
(set-val pinch-x-max (get-val pinch-x))
|
||||
(set-val pinch-y-max (get-val pinch-y)))
|
||||
(set-val pinch-x (+ new-pinch-x (get-val pinch-x-start)))
|
||||
(set-val pinch-y (+ new-pinch-y (get-val pinch-y-start)))
|
||||
(set-val scale new-scale))))
|
||||
(gesture/on-end
|
||||
(fn []
|
||||
(cond
|
||||
(< (reanimated/get-shared-value scale) c/min-scale)
|
||||
(< (get-val scale) c/min-scale)
|
||||
(rescale c/min-scale)
|
||||
(> (reanimated/get-shared-value scale) c/max-scale)
|
||||
(> (get-val scale) c/max-scale)
|
||||
(do
|
||||
(reanimated/set-shared-value pinch-x
|
||||
(reanimated/with-timing (reanimated/get-shared-value
|
||||
pinch-x-max)))
|
||||
(reanimated/set-shared-value pinch-x-start (reanimated/get-shared-value pinch-x-max))
|
||||
(reanimated/set-shared-value pinch-x-max js/Infinity)
|
||||
(reanimated/set-shared-value pinch-y
|
||||
(reanimated/with-timing (reanimated/get-shared-value
|
||||
pinch-y-max)))
|
||||
(reanimated/set-shared-value pinch-y-start (reanimated/get-shared-value pinch-y-max))
|
||||
(reanimated/set-shared-value pinch-y-max js/Infinity)
|
||||
(reanimated/set-shared-value scale (reanimated/with-timing c/max-scale))
|
||||
(reanimated/set-shared-value saved-scale c/max-scale))
|
||||
(set-val pinch-x (timing (get-val pinch-x-max)))
|
||||
(set-val pinch-x-start (get-val pinch-x-max))
|
||||
(set-val pinch-x-max js/Infinity)
|
||||
(set-val pinch-y (timing (get-val pinch-y-max)))
|
||||
(set-val pinch-y-start (get-val pinch-y-max))
|
||||
(set-val pinch-y-max js/Infinity)
|
||||
(set-val scale (timing c/max-scale))
|
||||
(set-val saved-scale c/max-scale))
|
||||
:else
|
||||
(do
|
||||
(reanimated/set-shared-value saved-scale (reanimated/get-shared-value scale))
|
||||
(reanimated/set-shared-value pinch-x-start (reanimated/get-shared-value pinch-x))
|
||||
(reanimated/set-shared-value pinch-y-start (reanimated/get-shared-value pinch-y))
|
||||
(when (< (reanimated/get-shared-value scale) x-threshold-scale)
|
||||
(utils/center-x animations false))
|
||||
(when (< (reanimated/get-shared-value scale) y-threshold-scale)
|
||||
(utils/center-y animations false))))
|
||||
(finalize-pinch dimensions animations props)))))
|
||||
(set-val saved-scale (get-val scale))
|
||||
(set-val pinch-x-start (get-val pinch-x))
|
||||
(set-val pinch-y-start (get-val pinch-y))
|
||||
(when (< (get-val scale) x-threshold-scale)
|
||||
(center-x animations false))
|
||||
(when (< (get-val scale) y-threshold-scale)
|
||||
(center-y animations false))))))
|
||||
(gesture/on-finalize
|
||||
(fn []
|
||||
(let [curr-offset-y (+ (get-val pan-y) (get-val pinch-y))
|
||||
max-offset-y (utils/get-max-offset height screen-height (get-val scale))
|
||||
max-offset-y (if (neg? curr-offset-y) (- max-offset-y) max-offset-y)
|
||||
curr-offset-x (+ (get-val pan-x) (get-val pinch-x))
|
||||
max-offset-x (utils/get-max-offset width screen-width (get-val scale))
|
||||
max-offset-x (if (neg? curr-offset-x) (- max-offset-x) max-offset-x)]
|
||||
(when (and (> (get-val scale) y-threshold-scale)
|
||||
(> (Math/abs curr-offset-y) (Math/abs max-offset-y)))
|
||||
(set-val pinch-y (timing c/init-offset))
|
||||
(set-val pinch-y-start c/init-offset)
|
||||
(set-val pan-y (timing max-offset-y))
|
||||
(set-val pan-y-start max-offset-y))
|
||||
(when (and (> (get-val scale) x-threshold-scale)
|
||||
(> (Math/abs curr-offset-x) (Math/abs max-offset-x)))
|
||||
(set-val pinch-x (timing c/init-offset))
|
||||
(set-val pinch-x-start c/init-offset)
|
||||
(set-val pan-x (timing max-offset-x))
|
||||
(set-val pan-x-start max-offset-x))
|
||||
(reset! pan-x-enabled? (> (get-val scale) x-threshold-scale))
|
||||
(reset! pan-y-enabled? (> (get-val scale) y-threshold-scale)))))))
|
||||
|
||||
(defn pan-x-gesture
|
||||
[{:keys [width screen-width x-threshold-scale]}
|
||||
@@ -141,33 +213,27 @@
|
||||
(gesture/enabled @pan-x-enabled?)
|
||||
(gesture/average-touches false)
|
||||
(gesture/on-update (fn [e]
|
||||
(reanimated/set-shared-value pan-x
|
||||
(+ (reanimated/get-shared-value pan-x-start)
|
||||
(oget e "translationX")))))
|
||||
(set-val pan-x (+ (get-val pan-x-start) (oget e "translationX")))))
|
||||
(gesture/on-end
|
||||
(fn [e]
|
||||
(let [curr-offset (+ (reanimated/get-shared-value pan-x)
|
||||
(reanimated/get-shared-value pinch-x-start))
|
||||
max-offset (utils/get-max-offset width screen-width (reanimated/get-shared-value scale))
|
||||
max-offset (if (neg? curr-offset) (- max-offset) max-offset)
|
||||
velocity (* (oget e "velocityX") c/velocity-factor)]
|
||||
(let [curr-offset (+ (get-val pan-x) (get-val pinch-x-start))
|
||||
max-offset (utils/get-max-offset width screen-width (get-val scale))
|
||||
max-offset (if (neg? curr-offset) (- max-offset) max-offset)]
|
||||
(cond
|
||||
(< (reanimated/get-shared-value scale) x-threshold-scale)
|
||||
(< (get-val scale) x-threshold-scale)
|
||||
(rescale c/min-scale)
|
||||
(> (Math/abs curr-offset) (Math/abs max-offset))
|
||||
(do
|
||||
(reanimated/set-shared-value pan-x (reanimated/with-timing max-offset))
|
||||
(reanimated/set-shared-value pan-x-start max-offset)
|
||||
(reanimated/set-shared-value pinch-x (reanimated/with-timing c/init-offset))
|
||||
(reanimated/set-shared-value pinch-x-start c/init-offset))
|
||||
(set-val pan-x (timing max-offset))
|
||||
(set-val pan-x-start max-offset)
|
||||
(set-val pinch-x (timing c/init-offset))
|
||||
(set-val pinch-x-start c/init-offset))
|
||||
:else
|
||||
(let [lower-bound (- (- (Math/abs max-offset)) (reanimated/get-shared-value pinch-x-start))
|
||||
upper-bound (- (Math/abs max-offset) (reanimated/get-shared-value pinch-x-start))]
|
||||
(reanimated/set-shared-value pan-x-start (reanimated/get-shared-value pan-x))
|
||||
(reanimated/animate-shared-value-with-decay pan-x velocity [lower-bound upper-bound])
|
||||
(reanimated/animate-shared-value-with-decay pan-x-start
|
||||
velocity
|
||||
[lower-bound upper-bound]))))))))
|
||||
(let [lower-bound (- (- (Math/abs max-offset)) (get-val pinch-x-start))
|
||||
upper-bound (- (Math/abs max-offset) (get-val pinch-x-start))]
|
||||
(set-val pan-x-start (get-val pan-x))
|
||||
(set-val-decay pan-x (oget e "velocityX") [lower-bound upper-bound])
|
||||
(set-val-decay pan-x-start (oget e "velocityX") [lower-bound upper-bound]))))))))
|
||||
|
||||
|
||||
(defn pan-y-gesture
|
||||
@@ -180,94 +246,81 @@
|
||||
(gesture/enabled @pan-y-enabled?)
|
||||
(gesture/average-touches false)
|
||||
(gesture/on-update (fn [e]
|
||||
(reanimated/set-shared-value pan-y
|
||||
(+ (reanimated/get-shared-value pan-y-start)
|
||||
(oget e "translationY")))))
|
||||
(set-val pan-y (+ (get-val pan-y-start) (oget e "translationY")))))
|
||||
(gesture/on-end
|
||||
(fn [e]
|
||||
(let [curr-offset (+ (reanimated/get-shared-value pan-y)
|
||||
(reanimated/get-shared-value pinch-y-start))
|
||||
max-offset (utils/get-max-offset height screen-height (reanimated/get-shared-value scale))
|
||||
max-offset (if (neg? curr-offset) (- max-offset) max-offset)
|
||||
velocity (* (oget e "velocityY") c/velocity-factor)]
|
||||
(let [curr-offset (+ (get-val pan-y) (get-val pinch-y-start))
|
||||
max-offset (utils/get-max-offset height screen-height (get-val scale))
|
||||
max-offset (if (neg? curr-offset) (- max-offset) max-offset)]
|
||||
(cond
|
||||
(< (reanimated/get-shared-value scale) y-threshold-scale)
|
||||
(< (get-val scale) y-threshold-scale)
|
||||
(rescale c/min-scale)
|
||||
(> (Math/abs curr-offset) (Math/abs max-offset))
|
||||
(do
|
||||
(reanimated/set-shared-value pan-y (reanimated/with-timing max-offset))
|
||||
(reanimated/set-shared-value pan-y-start max-offset)
|
||||
(reanimated/set-shared-value pinch-y (reanimated/with-timing c/init-offset))
|
||||
(reanimated/set-shared-value pinch-y-start c/init-offset))
|
||||
(set-val pan-y (timing max-offset))
|
||||
(set-val pan-y-start max-offset)
|
||||
(set-val pinch-y (timing c/init-offset))
|
||||
(set-val pinch-y-start c/init-offset))
|
||||
:else
|
||||
(let [lower-bound (- (- (Math/abs max-offset)) (reanimated/get-shared-value pinch-y-start))
|
||||
upper-bound (- (Math/abs max-offset) (reanimated/get-shared-value pinch-y-start))]
|
||||
(reanimated/set-shared-value pan-y-start (reanimated/get-shared-value pan-y))
|
||||
(reanimated/animate-shared-value-with-decay pan-y velocity [lower-bound upper-bound])
|
||||
(reanimated/animate-shared-value-with-decay pan-y-start
|
||||
velocity
|
||||
[lower-bound upper-bound]))))))))
|
||||
(let [lower-bound (- (- (Math/abs max-offset)) (get-val pinch-y-start))
|
||||
upper-bound (- (Math/abs max-offset) (get-val pinch-y-start))]
|
||||
(set-val pan-y-start (get-val pan-y))
|
||||
(set-val-decay pan-y (oget e "velocityY") [lower-bound upper-bound])
|
||||
(set-val-decay pan-y-start (oget e "velocityY") [lower-bound upper-bound]))))))))
|
||||
|
||||
|
||||
;;;; Finally, the component
|
||||
(defn zoomable-image
|
||||
[{:keys [image-width image-height content message-id]} index border-radius on-tap]
|
||||
(let [set-full-height? (reagent/atom false)]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [shared-element-id (rf/sub [:shared-element-id])
|
||||
exit-lightbox-signal (rf/sub [:lightbox/exit-signal])
|
||||
zoom-out-signal (rf/sub [:lightbox/zoom-out-signal])
|
||||
initial-scale (if platform/ios? c/min-scale (rf/sub [:lightbox/scale]))
|
||||
curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
|
||||
focused? (= shared-element-id message-id)
|
||||
dimensions (utils/get-dimensions image-width image-height curr-orientation)
|
||||
animations {:scale (reanimated/use-shared-value initial-scale)
|
||||
:saved-scale (reanimated/use-shared-value initial-scale)
|
||||
:pan-x-start (reanimated/use-shared-value c/init-offset)
|
||||
:pan-x (reanimated/use-shared-value c/init-offset)
|
||||
:pan-y-start (reanimated/use-shared-value c/init-offset)
|
||||
:pan-y (reanimated/use-shared-value c/init-offset)
|
||||
:pinch-x-start (reanimated/use-shared-value c/init-offset)
|
||||
:pinch-x (reanimated/use-shared-value c/init-offset)
|
||||
:pinch-y-start (reanimated/use-shared-value c/init-offset)
|
||||
:pinch-y (reanimated/use-shared-value c/init-offset)
|
||||
:pinch-x-max (reanimated/use-shared-value js/Infinity)
|
||||
:pinch-y-max (reanimated/use-shared-value js/Infinity)
|
||||
:rotate (reanimated/use-shared-value c/init-rotation)
|
||||
:rotate-scale (reanimated/use-shared-value c/min-scale)}
|
||||
props {:pan-x-enabled? (reagent/atom false)
|
||||
:pan-y-enabled? (reagent/atom false)
|
||||
:focal-x (reagent/atom nil)
|
||||
:focal-y (reagent/atom nil)}
|
||||
rescale (fn [value exit?]
|
||||
(utils/rescale-image value exit? dimensions animations props))]
|
||||
(rn/use-effect-once (fn []
|
||||
(js/setTimeout #(reset! set-full-height? true) 500)
|
||||
js/undefined))
|
||||
(when platform/ios?
|
||||
(utils/handle-orientation-change curr-orientation focused? dimensions animations props)
|
||||
(utils/handle-exit-lightbox-signal exit-lightbox-signal
|
||||
index
|
||||
(reanimated/get-shared-value (:scale animations))
|
||||
rescale
|
||||
set-full-height?))
|
||||
(utils/handle-zoom-out-signal zoom-out-signal
|
||||
index
|
||||
(reanimated/get-shared-value (:scale animations))
|
||||
rescale)
|
||||
[:f>
|
||||
(fn []
|
||||
(let [tap (tap-gesture on-tap)
|
||||
double-tap (double-tap-gesture dimensions animations rescale)
|
||||
pinch (pinch-gesture dimensions animations props rescale)
|
||||
pan-x (pan-x-gesture dimensions animations props rescale)
|
||||
pan-y (pan-y-gesture dimensions animations props rescale)
|
||||
composed-gestures (gesture/exclusive
|
||||
(gesture/simultaneous pinch pan-x pan-y)
|
||||
(gesture/exclusive double-tap tap))]
|
||||
[gesture/gesture-detector {:gesture composed-gestures}
|
||||
[ra/view
|
||||
{:style (style/container dimensions animations @set-full-height?)}
|
||||
[ra/fast-image
|
||||
{:source {:uri (:image content)}
|
||||
:native-ID (when focused? :shared-element)
|
||||
:style (style/image dimensions animations border-radius)}]]]))]))]))
|
||||
[:f>
|
||||
(fn []
|
||||
(let [shared-element-id (rf/sub [:shared-element-id])
|
||||
exit-lightbox-signal (rf/sub [:lightbox/exit-signal])
|
||||
zoom-out-signal (rf/sub [:lightbox/zoom-out-signal])
|
||||
curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
|
||||
focused? (= shared-element-id message-id)
|
||||
dimensions (utils/get-dimensions image-width image-height curr-orientation)
|
||||
animations {:scale (use-val c/min-scale)
|
||||
:saved-scale (use-val c/min-scale)
|
||||
:pan-x-start (use-val c/init-offset)
|
||||
:pan-x (use-val c/init-offset)
|
||||
:pan-y-start (use-val c/init-offset)
|
||||
:pan-y (use-val c/init-offset)
|
||||
:pinch-x-start (use-val c/init-offset)
|
||||
:pinch-x (use-val c/init-offset)
|
||||
:pinch-y-start (use-val c/init-offset)
|
||||
:pinch-y (use-val c/init-offset)
|
||||
:pinch-x-max (use-val js/Infinity)
|
||||
:pinch-y-max (use-val js/Infinity)
|
||||
:rotate (use-val c/init-rotation)
|
||||
:rotate-scale (use-val c/min-scale)}
|
||||
props {:pan-x-enabled? (reagent/atom false)
|
||||
:pan-y-enabled? (reagent/atom false)
|
||||
:focal-x (reagent/atom nil)
|
||||
:focal-y (reagent/atom nil)}
|
||||
rescale (fn [value exit?]
|
||||
(rescale-image value exit? dimensions animations props))]
|
||||
(when platform/ios?
|
||||
(handle-orientation-change curr-orientation focused? dimensions animations props)
|
||||
(utils/handle-exit-lightbox-signal exit-lightbox-signal
|
||||
index
|
||||
(get-val (:scale animations))
|
||||
rescale))
|
||||
(utils/handle-zoom-out-signal zoom-out-signal index (get-val (:scale animations)) rescale)
|
||||
[:f>
|
||||
(fn []
|
||||
(let [tap (tap-gesture on-tap)
|
||||
double-tap (double-tap-gesture dimensions animations rescale)
|
||||
pinch (pinch-gesture dimensions animations props rescale)
|
||||
pan-x (pan-x-gesture dimensions animations props rescale)
|
||||
pan-y (pan-y-gesture dimensions animations props rescale)
|
||||
composed-gestures (gesture/exclusive
|
||||
(gesture/simultaneous pinch pan-x pan-y)
|
||||
(gesture/exclusive double-tap tap))]
|
||||
[gesture/gesture-detector {:gesture composed-gestures}
|
||||
[reanimated/view
|
||||
{:style (style/container dimensions animations)}
|
||||
[reanimated/fast-image
|
||||
{:source {:uri (:image content)}
|
||||
:native-ID (when focused? :shared-element)
|
||||
:style (style/image dimensions animations border-radius)}]]]))]))])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns status-im2.contexts.chat.messages.composer.mentions.view
|
||||
(:require [utils.re-frame :as rf]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im2.common.contact-list-item.view :as contact-list-item]))
|
||||
|
||||
(defn mention-item
|
||||
@@ -13,13 +13,13 @@
|
||||
[{:keys [refs suggestions max-y]} insets]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [translate-y (ra/use-val 0)]
|
||||
(let [translate-y (reanimated/use-shared-value 0)]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(ra/set-val translate-y
|
||||
(ra/with-timing (if (seq suggestions) 0 200)))))
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
(reanimated/set-shared-value translate-y
|
||||
(reanimated/with-timing (if (seq suggestions) 0 200)))))
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
{:bottom (or (:bottom insets) 0)
|
||||
:position :absolute
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.messages.composer.style :as style]
|
||||
@@ -43,7 +43,7 @@
|
||||
(gesture/on-start
|
||||
(fn [_]
|
||||
(if keyboard-shown
|
||||
(swap! gesture-values assoc :pan-y (ra/get-val translate-y))
|
||||
(swap! gesture-values assoc :pan-y (reanimated/get-shared-value translate-y))
|
||||
(input/input-focus text-input-ref))))
|
||||
(gesture/on-update
|
||||
(fn [evt]
|
||||
@@ -51,7 +51,7 @@
|
||||
(let [tY (oget evt "translationY")]
|
||||
(swap! gesture-values assoc :dy (- tY (:pdy @gesture-values)))
|
||||
(swap! gesture-values assoc :pdy tY)
|
||||
(ra/set-val
|
||||
(reanimated/set-shared-value
|
||||
translate-y
|
||||
(max (min (+ tY (:pan-y @gesture-values)) (- min-y)) (- max-y)))))))
|
||||
(gesture/on-end
|
||||
@@ -129,12 +129,12 @@
|
||||
:bg-bottom bg-bottom
|
||||
:window-height window-height
|
||||
:set-bg-opacity (fn [value]
|
||||
(ra/set-val bg-bottom (if (= value 1) 0 (- window-height)))
|
||||
(ra/set-val bg-opacity (ra/with-timing value)))
|
||||
(reanimated/set-shared-value bg-bottom (if (= value 1) 0 (- window-height)))
|
||||
(reanimated/set-shared-value bg-opacity (reanimated/with-timing value)))
|
||||
:set-translate-y (fn [value]
|
||||
(ra/set-val translate-y (ra/with-timing value)))
|
||||
(reanimated/set-shared-value translate-y (reanimated/with-timing value)))
|
||||
:set-parent-height (fn [value]
|
||||
(ra/set-val parent-height (ra/with-timing value)))})
|
||||
(reanimated/set-shared-value parent-height (reanimated/with-timing value)))})
|
||||
|
||||
;; IMPORTANT! PLEASE READ BEFORE MAKING CHANGES
|
||||
|
||||
@@ -165,9 +165,9 @@
|
||||
|
||||
{window-height :height} (rn/use-window-dimensions)
|
||||
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
translate-y (ra/use-val 0)
|
||||
bg-opacity (ra/use-val 0)
|
||||
bg-bottom (ra/use-val (- window-height))
|
||||
translate-y (reanimated/use-shared-value 0)
|
||||
bg-opacity (reanimated/use-shared-value 0)
|
||||
bg-bottom (reanimated/use-shared-value (- window-height))
|
||||
|
||||
suggestions? (and (seq suggestions)
|
||||
keyboard-shown
|
||||
@@ -190,7 +190,7 @@
|
||||
(when (or edit reply) 38)
|
||||
(when (seq images) 80))))
|
||||
|
||||
parent-height (ra/use-val min-y)
|
||||
parent-height (reanimated/use-shared-value min-y)
|
||||
max-parent-height (Math/abs (- max-y 110 (:bottom insets)))
|
||||
|
||||
params
|
||||
@@ -201,14 +201,14 @@
|
||||
input-content-change (get-input-content-change params)
|
||||
bottom-sheet-gesture (get-bottom-sheet-gesture params)]
|
||||
(effect! params)
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:height parent-height}
|
||||
{})}
|
||||
;;;;input
|
||||
[gesture/gesture-detector {:gesture bottom-sheet-gesture}
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY translate-y}]}
|
||||
(style/input-bottom-sheet window-height))}
|
||||
[rn/view {:style (style/bottom-sheet-handle)}]
|
||||
@@ -225,8 +225,8 @@
|
||||
[mentions/mentions params insets]
|
||||
[controls/view send-ref params insets chat-id images #(clean-and-minimize params)])
|
||||
;;;;black background
|
||||
[ra/view
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:opacity bg-opacity
|
||||
:transform [{:translateY bg-bottom}]}
|
||||
(style/bottom-sheet-background window-height))}]]))])))
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
[rn/touchable-opacity
|
||||
{:key (:message-id item)
|
||||
:active-opacity 1
|
||||
;; issue: https://github.com/status-im/status-mobile/issues/14995
|
||||
:on-long-press #(on-long-press message context)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)])
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:key message-id
|
||||
:style {:margin-top (when (> index 0) 10)}
|
||||
:style {:margin-top (when (> index 0) 20)}
|
||||
:on-long-press on-long-press
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:chat.ui/update-shared-element-id message-id])
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
(:require [react-native.platform :as platform]))
|
||||
|
||||
(def screen-title-container
|
||||
{:height 56
|
||||
:padding-vertical 12
|
||||
:justify-content :center
|
||||
:margin-horizontal 20})
|
||||
{:height 56
|
||||
:padding-vertical 12
|
||||
:justify-content :center})
|
||||
|
||||
(def featured-communities-header
|
||||
{:flex-direction :row
|
||||
@@ -13,7 +12,6 @@
|
||||
:padding-top 8
|
||||
:margin-bottom 8
|
||||
:padding-right 20
|
||||
:margin-left 20
|
||||
:justify-content :space-between})
|
||||
|
||||
(def featured-communities-title-container
|
||||
@@ -23,13 +21,7 @@
|
||||
(def featured-list-container
|
||||
{:flex-direction :row
|
||||
:overflow :hidden
|
||||
:margin-bottom 24
|
||||
:margin-left 20
|
||||
:padding-right 20})
|
||||
|
||||
(def other-communities-container
|
||||
{:flex 1
|
||||
:margin-horizontal 20})
|
||||
:margin-bottom 24})
|
||||
|
||||
(defn discover-communities-segments
|
||||
[fixed?]
|
||||
@@ -38,9 +30,8 @@
|
||||
:height 56
|
||||
:background-color :transparent}
|
||||
(when-not fixed?
|
||||
{:margin-top 12
|
||||
:margin-horizontal 20
|
||||
:margin-bottom 4})))
|
||||
{:margin-top 12
|
||||
:margin-bottom 4})))
|
||||
|
||||
(defn discover-screen-container
|
||||
[background-color]
|
||||
@@ -56,7 +47,8 @@
|
||||
:justify-content :center})
|
||||
|
||||
(def render-communities-container
|
||||
{:margin-top 100})
|
||||
{:padding-horizontal 20
|
||||
:margin-top 100})
|
||||
|
||||
(defn blur-tabs-header
|
||||
[]
|
||||
|
||||
@@ -18,17 +18,26 @@
|
||||
{:data {:community-color "#0052FF"
|
||||
:status :gated
|
||||
:locked? true
|
||||
:cover (resources/get-mock-image :community-cover)
|
||||
:tokens [{:id 1
|
||||
:group [{:id 1
|
||||
:token-icon (resources/get-mock-image :status-logo)}]}]}})
|
||||
:token-icon (resources/get-mock-image :status-logo)}]}]
|
||||
:tags [{:id 1
|
||||
:tag-label (i18n/label :t/music)
|
||||
:resource (resources/get-image :music)}
|
||||
{:id 2
|
||||
:tag-label (i18n/label :t/lifestyle)
|
||||
:resource (resources/get-image :lifestyle)}
|
||||
{:id 3
|
||||
:tag-label (i18n/label :t/podcasts)
|
||||
:resource (resources/get-image :podcasts)}]}})
|
||||
|
||||
(defn render-fn
|
||||
[community-item _ _ {:keys [width view-type]}]
|
||||
(let [item (merge community-item
|
||||
(get mock-community-item-data :data))
|
||||
cover {:uri (get-in (:images item) [:banner :uri])}]
|
||||
(let [item (merge community-item
|
||||
(get mock-community-item-data :data))]
|
||||
(if (= view-type :card-view)
|
||||
[quo/community-card-view-item (assoc item :width width :cover cover)
|
||||
[quo/community-card-view-item (assoc item :width width)
|
||||
#(rf/dispatch [:navigate-to :community-overview (:id item)])]
|
||||
[quo/communities-list-view-item
|
||||
{:on-press (fn []
|
||||
@@ -125,7 +134,7 @@
|
||||
|
||||
(defn other-communities-list
|
||||
[{:keys [communities communities-ids view-type]}]
|
||||
[rn/view {:style style/other-communities-container}
|
||||
[rn/view {:flex 1}
|
||||
(map-indexed
|
||||
(fn [inner-index item]
|
||||
(let [community-id (when communities-ids item)
|
||||
|
||||
@@ -288,12 +288,10 @@
|
||||
(let [categories-heights (reagent/atom [])
|
||||
first-channel-height (reagent/atom 0)
|
||||
scroll-height (reagent/atom 0)
|
||||
cover {:uri (get-in images [:banner :uri])}
|
||||
logo {:uri (get-in images [:thumbnail :uri])}]
|
||||
cover {:uri (get-in images [:large :uri])}]
|
||||
(fn [community]
|
||||
[scroll-page/scroll-page
|
||||
{:cover-image cover
|
||||
:logo logo
|
||||
:page-nav-right-section-buttons (page-nav-right-section-buttons id)
|
||||
:name name
|
||||
:on-scroll #(reset! scroll-height %)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(ns status-im2.contexts.emoji-hash.events
|
||||
(:require [utils.re-frame :as rf]
|
||||
[status-im.native-module.core :as native-module]
|
||||
[utils.transforms :as transform]))
|
||||
|
||||
(defn fetch-for-current-public-key
|
||||
[]
|
||||
(let [public-key (rf/sub [:multiaccount/public-key])]
|
||||
(native-module/public-key->emoji-hash
|
||||
public-key
|
||||
(fn [response]
|
||||
(let [response-clj (transform/json->clj response)
|
||||
emoji-hash (get response-clj :result)]
|
||||
(rf/dispatch [:emoji-hash/add-to-multiaccount emoji-hash]))))))
|
||||
|
||||
(rf/defn add-emoji-hash-to-multiaccount
|
||||
{:events [:emoji-hash/add-to-multiaccount]}
|
||||
[{:keys [db]} emoji-hash]
|
||||
{:db (assoc db :multiaccount/emoji-hash emoji-hash)})
|
||||
@@ -1,26 +0,0 @@
|
||||
(ns status-im2.contexts.onboarding.common.background
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.common.resources :as resources]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[status-im2.contexts.onboarding.common.style :as style]))
|
||||
|
||||
(defn view
|
||||
[dark-overlay?]
|
||||
[rn/view
|
||||
{:style style/background-container}
|
||||
;; Todo - add carousel component as background once ready
|
||||
;; https://github.com/status-im/status-mobile/issues/15012
|
||||
[rn/image
|
||||
{:blur-radius (if dark-overlay? 13 0)
|
||||
:style {:flex 1}
|
||||
:source (resources/get-image :onboarding-bg-1)}]
|
||||
[linear-gradient/linear-gradient
|
||||
{:colors [(if dark-overlay? (colors/custom-color :yin 50) "#000716")
|
||||
(if dark-overlay? (colors/custom-color :yin 50 0) "#000716")]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0 :y 1}
|
||||
:style (style/background-gradient-overlay dark-overlay?)}]
|
||||
(when dark-overlay?
|
||||
[rn/view
|
||||
{:style style/background-blur-overlay}])])
|
||||
@@ -1,61 +0,0 @@
|
||||
(ns status-im2.contexts.onboarding.common.intro.style
|
||||
(:require
|
||||
[react-native.platform :as platform]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(def progress-bar-container
|
||||
{:background-color colors/neutral-100
|
||||
:flex-direction :row
|
||||
:margin-vertical 16})
|
||||
|
||||
(defn progress-bar-item
|
||||
[index position end?]
|
||||
{:height 2
|
||||
:flex 1
|
||||
:border-width 1
|
||||
:border-color (if (= index position) colors/white colors/white-opa-10)
|
||||
:margin-right (if end? 0 8)})
|
||||
|
||||
(def carousel
|
||||
{:height 92
|
||||
;; (padding-top) This insets issue needs a consistent implementation across all screens.
|
||||
:padding-top (if platform/android? 0 44)
|
||||
:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:z-index 2
|
||||
:background-color colors/neutral-100
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20})
|
||||
|
||||
(def carousel-text
|
||||
{:background-color colors/neutral-100
|
||||
:color colors/white})
|
||||
|
||||
(def page-container
|
||||
{:flex 1
|
||||
:justify-content :flex-end})
|
||||
|
||||
(def page-image
|
||||
{:position :absolute
|
||||
:background-color colors/neutral-100
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:width "100%"
|
||||
:aspect-ratio 1})
|
||||
|
||||
(def text-container
|
||||
{:flex 1
|
||||
:flex-wrap :wrap})
|
||||
|
||||
(def plain-text
|
||||
{:flex 1
|
||||
:color (colors/alpha colors/white 0.7)})
|
||||
|
||||
(def highlighted-text
|
||||
{:flex 1
|
||||
:color colors/white})
|
||||
@@ -1,88 +0,0 @@
|
||||
(ns status-im2.contexts.onboarding.common.intro.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.onboarding.common.intro.style :as style]
|
||||
[status-im2.common.resources :as resources]))
|
||||
|
||||
(def carousels
|
||||
[{:image (resources/get-image :intro-1)
|
||||
:text (i18n/label :t/join-decentralised-communities)
|
||||
:sub-text (i18n/label :t/participate-in-the-metaverse)}
|
||||
{:image (resources/get-image :intro-2)
|
||||
:text (i18n/label :t/chat-with-friends)
|
||||
:sub-text (i18n/label :t/with-full-encryption)}
|
||||
{:image (resources/get-image :intro-3)
|
||||
:text (i18n/label :t/own-your-crypto)
|
||||
:sub-text (i18n/label :t/use-the-multichain-wallet)}
|
||||
{:image (resources/get-image :intro-4)
|
||||
:text (i18n/label :t/discover-web3)
|
||||
:sub-text (i18n/label :t/explore-the-decentralized-web)}])
|
||||
|
||||
(defn progress-bar
|
||||
[index]
|
||||
[rn/view style/progress-bar-container
|
||||
[rn/view {:style (style/progress-bar-item index 0 false)}]
|
||||
[rn/view {:style (style/progress-bar-item index 1 false)}]
|
||||
[rn/view {:style (style/progress-bar-item index 2 false)}]
|
||||
[rn/view {:style (style/progress-bar-item index 3 true)}]])
|
||||
|
||||
;; TODO: carousel component is to be correctly implemented as quo2 component with animations etc in:
|
||||
;; https://github.com/status-im/status-mobile/issues/15012
|
||||
(defn carousel
|
||||
[index]
|
||||
[rn/view {:style style/carousel}
|
||||
[progress-bar index]
|
||||
[quo/text
|
||||
{:style style/carousel-text
|
||||
:weight :semi-bold
|
||||
:size :heading-2} (get-in carousels [index :text])]
|
||||
[quo/text
|
||||
{:style style/carousel-text
|
||||
:size :paragraph-1} (get-in carousels [index :sub-text])]])
|
||||
|
||||
(defn set-index
|
||||
[old-index]
|
||||
(mod (inc old-index) 4))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(reagent/with-let
|
||||
[carousel-index (reagent/atom 0)
|
||||
interval-id
|
||||
(js/setInterval
|
||||
#(swap! carousel-index set-index)
|
||||
1500)]
|
||||
[rn/view {:style style/page-container}
|
||||
[carousel @carousel-index]
|
||||
[rn/image
|
||||
{:style style/page-image
|
||||
:source (get-in carousels [@carousel-index :image])}]
|
||||
[quo/drawer-buttons
|
||||
{:top-card {:on-press (fn []
|
||||
(rf/dispatch [:init-root :onboarding])
|
||||
(rf/dispatch [:hide-terms-of-services-opt-in-screen]))
|
||||
:heading (i18n/label :t/sign-in)
|
||||
:accessibility-label :already-use-status-button}
|
||||
:bottom-card {:on-press (fn []
|
||||
(rf/dispatch [:init-root :onboarding])
|
||||
(rf/dispatch [:hide-terms-of-services-opt-in-screen]))
|
||||
:heading (i18n/label :t/im-new-to-status)
|
||||
:accessibility-label :new-to-status-button}}
|
||||
(i18n/label :t/you-already-use-status)
|
||||
[quo/text
|
||||
{:style style/text-container}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/plain-text
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/by-continuing-you-accept)]
|
||||
[quo/text
|
||||
{:on-press #(rf/dispatch [:open-modal :privacy-policy])
|
||||
:size :paragraph-2
|
||||
:style style/highlighted-text
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/terms-of-service)]]]]
|
||||
(finally (js/clearInterval interval-id))))
|
||||
@@ -1,23 +0,0 @@
|
||||
(ns status-im2.contexts.onboarding.common.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def background-container
|
||||
{:background-color colors/neutral-95
|
||||
:flex-direction :row})
|
||||
|
||||
(defn background-gradient-overlay
|
||||
[dark-overlay?]
|
||||
{:position :absolute
|
||||
:height (if dark-overlay? 240 136)
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0})
|
||||
|
||||
(def background-blur-overlay
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:top 0
|
||||
:bottom 0
|
||||
:right 0
|
||||
:background-color colors/neutral-80-opa-80-blur})
|
||||
@@ -1,7 +0,0 @@
|
||||
(ns status-im2.contexts.onboarding.profiles.view
|
||||
(:require [status-im2.contexts.onboarding.common.background :as background]))
|
||||
|
||||
(defn views
|
||||
[]
|
||||
[:<>
|
||||
[background/view true]])
|
||||
@@ -4,7 +4,7 @@
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]
|
||||
[react-native.reanimated :as ra]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[quo2.components.animated-header-flatlist.view :as animated-header-list]))
|
||||
|
||||
(def data [0 1 2 3 4 5 6 7 8 9 10])
|
||||
@@ -38,8 +38,8 @@
|
||||
[animation]
|
||||
[:f>
|
||||
(fn []
|
||||
[ra/fast-image
|
||||
{:style (ra/apply-animations-to-style
|
||||
[reanimated/fast-image
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:width animation
|
||||
:height animation}
|
||||
{:border-radius 72})
|
||||
|
||||