Compare commits

..
Author SHA1 Message Date
Ibrahem Khalil 9abb794785 Merge branch 'develop' into 18877 2024-02-18 14:02:46 +02:00
Flavio Fraschetti bfed36d19f [Communities] Account selection: сan't see the entire text of the community rules (#18761)
Resolved the scrolling issue pertaining to community rules. Additionally, will ensure compatibility with iOS devices lacking safe-area-view in the follow-up.
2024-02-18 08:03:52 -03:00
ibrkhalil aefb0338ec Use placeholder value if no wallet name is supplied 2024-02-17 20:14:36 +02:00
Yevheniia Berdnyk 456ccb4c69 e2e: temp fix for image selection 2024-02-17 19:03:20 +02:00
Andrea Maria Piana be2c697b7c set light client 2024-02-16 16:30:44 +00:00
Ajay Sivan b27f323dd7 FIX: Addresses for permissions info button bg color (#18855) 2024-02-16 06:08:05 -08:00
Mohsen a33e7f2e90 [#18600] feat: implement set bio screen (#18765) 2024-02-16 16:19:44 +03:00
Ajay Sivan 54d9e5ebeb Share all current and future addresses - UI (#18843)
Fixes
- 'Confirm changes' button unexpected enabled state
- The Confirm button remains enabled even after deselecting all addresses when the user has watch-only wallet accounts.
- Disable the Confirm button when the user deselects the accounts with the token required to join.
- Use community color for address checkbox
2024-02-16 04:11:22 -08:00
Alexander 49567596da General QR code scanner flow (#18677)
* QR scanner

* More options for QR

* Router fixes

* Updates for `on-qr-code-scanned`

* Update for communities

* Updates

* Scan profile path

* More fixes

* Last fixes for scanning

* Fixes

* Fixes

* Fixes

* Test fixes

* Fixes

* Updated Utils.m

* Test fix
2024-02-16 12:06:28 +01:00
Nikolay 2e23dc7ad7 chore(wallet): update default placeholder name for account and watched address when adding it #18416 (#18683) 2024-02-15 20:30:38 +00:00
Mohsen dc53bddb66 [#18754] fix: scrollable addresses permission list in android (#18808) 2024-02-15 18:00:21 +03:00
Mohamed Javid 10f9fe11db [Fix] Broken wallet account emoji when syncing devices (#18828)
This commit fixes the broken wallet account emoji when syncing devices by adding a sanitization method for the wallet account emoji. The desktop can handle both variants (raw emoji and img tag); this PR adds the same for mobile.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-15 18:52:59 +05:30
Flavio Fraschetti 2e13cfc47f [Refactor#18748] - Collectible Tag (#18804)
[Refactor Collectible Tag] Improve component schema and add component_spec
2024-02-15 09:52:24 -03:00
Siddarth Kumar e6ea8ae9a9 fix: iOS build stage to install app on simulator (#18839)
fixes #18836

## Summary

While introducing https://github.com/status-im/status-mobile/pull/18784 I missed out on adding an install step to `run-ios.sh` script.

`make run-ios` would work fine for simulators that already have the app installed but would fail for new emulators.
@flexsurfer  discovered this problem.

This commit fixes that by adding an install step to the script.

## Review notes
- `make run-clojure`
- `make run-ios` 
should just work.

## Platforms
- iOS
2024-02-15 17:55:06 +05:30
Alexander 834c0a3800 Design review: create profile password (#18607)
* Design review: create profile password

* Fixes

* Fixes

* Fixes

* Fixes

* Code style fix

* Fixes
2024-02-15 10:42:54 +01:00
Siddarth Kumar 2c96c38339 chore: disable hermes and cleanup gradle vars (#18832)
fixes #18831

We update the nix derivation to build android by passing `hermesEnabled` flag which checks the environment variable and if the environment variable is not set we default `hermesEnabled` to `true`.
This ensures that `hermes` is disabled for debug builds and enabled for release builds.

In this commit we also
- rename `nix/mobile/android/release.nix` → `nix/mobile/android/build.nix` since that nix file no longer generates release only builds.
- cleanup 2 other env vars and use the `gradle` project format
- replace `BUILD_NUMBER` with `verisonCode` for consistency
- replace `androidGradleOpts ` with `buildUrl ` 
- bump `status-jenkins-lib` to v1.8.7
2024-02-15 13:48:11 +05:30
Mohsen 1d2c01c16b [#18752] fix: The W/O address shouldn't be in account selection (#18809) 2024-02-14 20:37:52 +03:00
Andrea Maria Piana 8dc71f6432 Fix translations 2024-02-14 16:12:17 +00:00
Andrea Maria Piana 25f9499454 remove rounding 2024-02-14 16:12:17 +00:00
Siddarth Kumar 42cab08553 chore: Improve DX for building the app locally (#18784)
After upgrading `react-native` to `0.72.5` we frequently started seeing the _red screen of death_ on both `Android` and `iOS` simulators right after the app was built and installed.
This used to happen because our workflow required us to do the following :
- `make run-clojure`
- `make run-metro`
- `make run-ios` OR `make run-android`

The problem with this approach was after `metro` was started the `iOS`, `Android` build step would change the files that `metro` couldn't handle and hence metro would go out of sync.
The quick fix back then was to restart `metro` terminal and to open the app again from the simulator.
This was however not a good DX.

This commit fixes that.
We no longer rely on `react-native` cli to generate and deploy debug builds on simulators. We take control of the process via our own script. The new workflow introduced in this commit will first build the app, then install the app on the simulators and then start metro terminal. When `metro` is successfully running the script will then open the app.

The new workflow now is :
- `make run-clojure`
- `make run-ios` OR `make run-android`
2024-02-14 19:58:45 +05:30
Jamie Caprani 83523b1923 chore: clean up wallet reframe root keys (#18730) 2024-02-14 04:29:35 -08:00
Mohamed Javid f762cdcf9b [Feature] Wallet - Network filter UI in Wallet home and account screens (#18772)
This commit adds network filter UI in the Wallet home and account screens.

---------

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-02-14 15:37:04 +05:30
Ibrahem Khalil 357db52720 Use blurred background for all type shell? bottom sheets (#18400) 2024-02-13 22:54:43 +02:00
Yevheniia Berdnyk 5fdaf0054d e2e: updated join community 2024-02-13 15:26:19 +00:00
Andrea Maria Piana 4e3ce54ac4 Reduce renderings in community overview
https://github.com/status-im/status-go/compare/c15f9e73...1ea2bd99

This PR reduces the amount of rendering in community overview.
It limits the amount of data is passed to components to the necessary,
and it creates functions on component initialization so that they won't
cause a re-render.
Performance of the header are very noticeably better on my local
environment, though on nightly builds is less noticeable.

It also removes data from `communities/communities id` as that cause a
re-render of any component subscribed to it.
2024-02-13 15:26:19 +00:00
Andrea Maria Piana 37be08d2d7 Fix permission screen & trailing zeros
https://github.com/status-im/status-go/compare/c15f9e73...b7b7660a

There were a few issues with the permission screen:
1) Wrong permission was displayed when able to join
2) If not able to join, we were showing both admin/member permissions
3) Trailing zeros in token amount
2024-02-13 15:26:19 +00:00
Paul FitzgeraldandJamie Caprani 3c4d27b6ff chore(wallet): connect UI and data model for input page in bridge flow (#18678)
Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
2024-02-13 07:24:02 -08:00
jakub c5df51d944 nix: upgrade from 2.13.4 to 2.19.3
We are moving location of symlinks for build derivations for `gcroots`
from `/nix/var/nix/gcroots/per-user` to `.nix-gcroots` in the repo to
avoid errors like this caused by profile migration in `2.14` release:
```
error: creating directory '/nix/var/nix/gcroots/per-user/joe': Permission denied
```
For more details see: https://github.com/NixOS/nix/issues/8564

To upgrade without using `make nix-purge` use `make nix-upgrade`.

Related infra change:
https://github.com/status-im/infra-ci/commit/37c6ce47

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2024-02-13 13:32:50 +01:00
NikolayandJamie Caprani b1c467de19 feat(wallet): add ui for account origin info (#18725)
Co-authored-by: Jamie Caprani <jamiecaprani@gmail.com>
2024-02-13 03:27:28 -08:00
Shivek Khurana c766d21296 ⚒️ Fix typo (#18794) 2024-02-12 20:50:07 +00:00
133 changed files with 1677 additions and 933 deletions
+3
View File
@@ -194,3 +194,6 @@ test/appium/tests/users.py
## git hooks
lefthook.yml
## metro server logs
metro-server-logs.log
+6 -13
View File
@@ -44,7 +44,7 @@ export KEYSTORE_PATH ?= $(HOME)/.gradle/status-im.keystore
# Our custom config is located in nix/nix.conf
export NIX_USER_CONF_FILES = $(PWD)/nix/nix.conf
# Location of symlinks to derivations that should not be garbage collected
export _NIX_GCROOTS = /nix/var/nix/gcroots/per-user/$(USER)/status-mobile
export _NIX_GCROOTS = ./.nix-gcroots
# Defines which variables will be kept for Nix pure shell, use semicolon as divider
export _NIX_KEEP ?= TMPDIR,BUILD_ENV,\
BUILD_TYPE,BUILD_NUMBER,COMMIT_HASH,\
@@ -214,7 +214,7 @@ build-fdroid: ##@build Build release for F-Droid
build-android: export BUILD_ENV ?= prod
build-android: export BUILD_TYPE ?= nightly
build-android: export BUILD_NUMBER ?= $(TMP_BUILD_NUMBER)
build-android: export ORG_GRADLE_PROJECT_versionCode ?= $(TMP_BUILD_NUMBER)
build-android: export ANDROID_ABI_SPLIT ?= false
build-android: export ANDROID_ABI_INCLUDE ?= armeabi-v7a;arm64-v8a;x86
build-android: ##@build Build unsigned Android APK
@@ -267,7 +267,7 @@ run-clojure: ##@run Watch for and build Clojure changes for mobile
run-metro: export TARGET := clojure
run-metro: ##@run Start Metro to build React Native changes
@scripts/start-react-native.sh
@scripts/run-metro.sh
run-re-frisk: export TARGET := clojure
run-re-frisk: ##@run Start re-frisk server
@@ -278,22 +278,15 @@ run-android: export TARGET := android
# Disabled for debug builds to avoid 'maximum call stack exceeded' errors.
# https://github.com/status-im/status-mobile/issues/18493
run-android: export ORG_GRADLE_PROJECT_hermesEnabled := false
# INFO: If it's empty (no devices attached, parsing issues, script error) - for Nix it's the same as not set.
run-android: export ANDROID_ABI_INCLUDE ?= $(shell ./scripts/adb_devices_abis.sh)
run-android: ##@run Build Android APK and start it on the device
npx react-native run-android --appIdSuffix debug
@scripts/run-android.sh
SIMULATOR=iPhone 13
# TODO: fix IOS_STATUS_GO_TARGETS to be either amd64 or arm64 when RN is upgraded
run-ios: export TARGET := ios
run-ios: export IOS_STATUS_GO_TARGETS := ios/arm64;iossimulator/amd64
run-ios: export XCBeautify=$(shell which xcbeautify) # for react-native-cli to pick this up and to auto format output
run-ios: ##@run Build iOS app and start it in a simulator/device
ifneq ("$(SIMULATOR)", "")
npx react-native run-ios --simulator="$(SIMULATOR)"
else
npx react-native run-ios
endif
run-ios: ##@run Build iOS app and start it in on the simulator
@scripts/run-ios.sh "${SIMULATOR}"
show-ios-devices: ##@other shows connected ios device and its name
xcrun xctrace list devices
+2 -2
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'linux && x86_64 && nix-2.14' }
agent { label 'linux && x86_64 && nix-2.19' }
options {
timestamps()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
agent { label 'linux' }
+2 -2
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'macos && arm64 && nix-2.14 && xcode-15.1' }
agent { label 'macos && arm64 && nix-2.19 && xcode-15.1' }
parameters {
string(
+2 -2
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
pipeline {
agent { label 'linux && x86_64 && nix-2.14' }
agent { label 'linux && x86_64 && nix-2.19' }
options {
timestamps()
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
agent { label 'macos' }
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
agent { label params.AGENT_LABEL }
@@ -82,7 +82,7 @@ pipeline {
env.NIXPKGS_SYSTEM_OVERRIDE = nixSysOverride(os, arch, 'android')
/* Build/fetch deps required to build android release. */
nix.build(
attr: 'targets.mobile.android.release.buildInputs',
attr: 'targets.mobile.android.build.buildInputs',
sandbox: false,
pure: false,
link: false
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.8.5'
library 'status-jenkins-lib@v1.8.7'
pipeline {
agent {
+1 -2
View File
@@ -122,10 +122,9 @@ See below:
Do the following:
Ensure you have 3 terminals running the following
Ensure you have 2 terminals running the following
- `make run-clojure`
- `make run-metro`
- `make run-ios` / `make run-android`
[See the STARTING GUIDE for details](STARTING_GUIDE.md#development)
+1 -2
View File
@@ -15,8 +15,7 @@ This step will take a while the first time as it will download all dependencies.
There are three steps necessary to start development, in this case for Android:
1. `make run-clojure` - Compiles Clojure into JavaScript, watches for changes on cljs files, and hot-reloads code in the app.
2. `make run-metro` - Starts metro bundler and watches JavaScript code.
3. `make run-android` or `make run-ios` - Builds the Android/iOS app and starts it on the device.
2. `make run-android` or `make run-ios` - Builds the Android/iOS app, starts it on the device and starts metro bundler.
The first two will continue watching for changes and keep re-building the app. They need to be ready first.
The last one will exit once the app is up and ready.
+1 -1
View File
@@ -793,7 +793,7 @@ CHECKOUT OPTIONS:
:submodules: true
SPEC CHECKSUMS:
boost: 57d2868c099736d80fcd648bf211b4431e51a558
boost: 64032b9e9b938fda23325e68a3771f0fabf414dc
BVLinearGradient: 612a04ff38e8480291f3379ee5b5a2c571f03fe0
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
@@ -120,9 +120,12 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(checkAddressChecksum:(NSString *)address)
return StatusgoCheckAddressChecksum(address);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isAddress:(NSString *)address) {
return StatusgoIsAddress(address);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(toChecksumAddress:(NSString *)address) {
return StatusgoToChecksumAddress(address);
}
@end
+7 -5
View File
@@ -61,7 +61,7 @@ We will use the `make jsbundle` target as an example of a derivation you can bui
3. [`build.sh`](/nix/scripts/build.sh) calls `nix-build --attr targets.mobile.jsbundle` with extra arguments
4. `nix-build` builds the derivation from [`nix/mobile/jsbundle/default.nix`](/nix/mobile/jsbundle/default.nix)
The same can be done for other targets like `targets.mobile.android.release`.
The same can be done for other targets like `targets.mobile.android.build`.
Except in that case extra arguments are required which is why the [`scripts/release-android.sh`](/scripts/release-android.sh) is used in the `make release-android` target.
If you run `make release-android` you'll see the `nix-build` command used:
@@ -71,21 +71,23 @@ nix-build \
--fallback \
--no-out-link \
--show-trace \
--attr targets.mobile.android.release \
--attr targets.mobile.android.build \
--argstr secrets-file '/tmp/tmp-status-mobile-559a3a441/tmp.xAnrPuNtAP' \
--option extra-sandbox-paths '/home/joe/.gradle/status-im.keystore /tmp/tmp-status-mobile-559a3a441/tmp.xAnrPuNtAP' \
default.nix
```
Some of those are required which is why just calling:
```
nix-build --attr targets.mobile.android.release
nix-build --attr targets.mobile.android.build
```
Would fail.
# Garbage Collection
The `make nix-gc` target calls `nix-store --gc` and normally would remove almost everything, but to prevent that we place symlinks to protected derivations in `/nix/var/nix/gcroots` subfolder. Specifically:
The `make nix-gc` target calls `nix-store --gc` and normally would remove almost everything, but to prevent that we place symlinks to protected derivations in `.nix-gcroots` folder. Specifically:
```sh
_NIX_GCROOTS="${_NIX_GCROOTS:-/nix/var/nix/gcroots/per-user/${USER}/status-mobile}"
_NIX_GCROOTS="${_NIX_GCROOTS:-${GIT_ROOT}/.nix-gcroots}
```
These symlinks in turn will be symlinked from `/nix/var/nix/gcroots/auto` through use of `nix-store --add-gcroots`.
Whenever `nix/scripts/build.sh` or `nix/scripts/shell.sh` are called they update symlinks named after given targets in that folder. This in combination with `keep-outputs = true` set in `nix/nix.conf` prevents garbage collection from removing too much.
+1 -1
View File
@@ -28,7 +28,7 @@ export STATUS_GO_IPFS_GATEWAY_URL="https://ipfs.status.im/"
```
You can see the defaults in code:
- [`nix/status-go/default.nix`](./status-go/default.nix)
- [`nix/mobile/android/release.nix`](./mobile/android/release.nix)
- [`nix/mobile/android/release.nix`](./mobile/android/build.nix)
## Shell
+1 -1
View File
@@ -6,7 +6,7 @@ This directory contains the tools and the data that allows Nix to manage Gradle
Simply calling `generate.sh` should result in a `deps.json` file which is used in the derivation that provides Gradle dependencies when building the Android app.
You can see in [`nix/mobile/android/release.nix`](../../mobile/android/release.nix) that it's used via the `-Dmaven.repo.local='${deps.gradle}'` Gradle flag.
You can see in [`nix/mobile/android/release.nix`](../../mobile/android/build.nix) that it's used via the `-Dmaven.repo.local='${deps.gradle}'` Gradle flag.
# Files
@@ -7,15 +7,15 @@
# Path to the file containing secret environment variables
secretsFile ? "",
# Build type (influences which .env file gets used for feature flags)
# TODO: pr or relase for default?
buildType ? lib.getEnvWithDefault "BUILD_TYPE" "release",
# Used for versionCode
buildNumber ? lib.getEnvWithDefault "BUILD_NUMBER" 9999,
versionCode ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_versionCode" 9999,
# Included in APK Manifest for easier identification.
# TODO: or GIT_COMMIT from Jenkins?
commitHash ? lib.getEnvWithDefault "COMMIT_HASH" "unknown",
# Gradle options passed for Android builds
androidGradleOpts ? lib.getEnvWithDefault "ANDROID_GRADLE_OPTS" null,
commitHash ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_commitHash" "unknown",
# Disabled for debug builds to avoid 'maximum call stack exceeded' errors.
# https://github.com/status-im/status-mobile/issues/18493
hermesEnabled ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_hermesEnabled" "true",
buildUrl ? lib.getEnvWithDefault "ORG_GRADLE_PROJECT_buildUrl" null,
statusGoSrcOverride ? lib.getEnvWithDefault "STATUS_GO_SRC_OVERRIDE" null,
# If APKs should be split based on architectures
androidAbiSplit ? lib.getEnvWithDefault "ANDROID_ABI_SPLIT" "false",
@@ -40,8 +40,10 @@ let
else if (elem buildType ["pr" "manual"]) then ".env.jenkins"
else ".env";
# There are only two types of Gradle build targets: pr and release
gradleBuildType = if buildType == "pr" then "Pr" else "Release";
gradleBuildType =
if buildType == "pr" then "Pr"
else if buildType == "debug" then "Debug"
else "Release";
apksPath = "./android/app/build/outputs/apk/${toLower gradleBuildType}";
@@ -81,7 +83,10 @@ in stdenv.mkDerivation rec {
ANDROID_ABI_INCLUDE = androidAbiInclude;
# Disabled for debug builds to avoid 'maximum call stack exceeded' errors.
# https://github.com/status-im/status-mobile/issues/18493
ORG_GRADLE_PROJECT_hermesEnabled = true;
ORG_GRADLE_PROJECT_versionCode = versionCode;
ORG_GRADLE_PROJECT_commitHash = commitHash;
ORG_GRADLE_PROJECT_buildUrl = buildUrl;
ORG_GRADLE_PROJECT_hermesEnabled = hermesEnabled;
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
NODE_OPTIONS = "--openssl-legacy-provider";
@@ -116,8 +121,6 @@ in stdenv.mkDerivation rec {
# Symlink React Native entrypoint.
cp -Lr ${builtJsBundle} ./result
pwd
find -L result
# Copy android/ directory
mkdir -p ./android/build
@@ -144,7 +147,6 @@ in stdenv.mkDerivation rec {
"LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${makeLibraryPath [ pkgs.zlib ]}";
gradleCommand = ''
${pkgs.gradle}/bin/gradle \
${toString androidGradleOpts} \
--console=plain \
--offline \
--no-daemon \
@@ -152,8 +154,6 @@ in stdenv.mkDerivation rec {
--no-watch-fs \
--no-build-cache \
-Dmaven.repo.local='${deps.gradle}' \
-PversionCode=${toString buildNumber} \
-PcommitHash=${commitHash} \
assemble${gradleBuildType}
'';
in
@@ -171,12 +171,14 @@ in stdenv.mkDerivation rec {
${adhocEnvVars} ${gradleCommand}
popd > /dev/null
'';
doCheck = true;
checkPhase = ''
doCheck = buildType != "debug";
checkPhase = ''
ls ${apksPath}/*.apk \
| xargs -n1 ${pkgs.unzip}/bin/unzip -qql \
| grep 'index.android.bundle'
'';
installPhase = ''
mkdir -p $out
cp ${apksPath}/*.apk $out/
+2 -2
View File
@@ -2,7 +2,7 @@
, jsbundle, status-go, androidPkgs, androidShell }:
rec {
release = callPackage ./release.nix {
build = callPackage ./build.nix {
inherit jsbundle status-go;
};
@@ -15,7 +15,7 @@ rec {
];
inputsFrom = [
(release {})
(build {})
androidShell
];
+1 -1
View File
@@ -45,7 +45,7 @@ if [[ -z "${TARGET}" ]]; then
fi
# Hack fix for missing Android SDK for aarch64 on Darwin. See systemOverride in `nix/pkgs.nix`.
if [[ "${TARGET}" =~ ^(targets.status-go.mobile.android|targets.mobile.android.release)$ ]]; then
if [[ "${TARGET}" =~ ^(targets.status-go.mobile.android|targets.mobile.android.build)$ ]]; then
os=$(uname -s | tr '[:upper:]' '[:lower:]')
export NIXPKGS_SYSTEM_OVERRIDE="x86_64-${os}"
fi
+2 -2
View File
@@ -2,12 +2,12 @@
set -Ee
_NIX_GCROOTS="${_NIX_GCROOTS:-/nix/var/nix/gcroots/per-user/${USER}/status-mobile}"
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/nix/scripts/source.sh"
source "${GIT_ROOT}/scripts/colors.sh"
_NIX_GCROOTS="${_NIX_GCROOTS:-${GIT_ROOT}/.nix-gcroots}"
TARGET="${1}"
shift
if [[ -z "${TARGET}" ]]; then
+3 -5
View File
@@ -1,8 +1,6 @@
#!/usr/bin/env bash
# WARNING: Versions 2.14, 2.15, 2.16 have an issue creating gcroots:
# https://github.com/NixOS/nix/issues/8564
export NIX_VERSION="2.13.4"
export NIX_PACKAGE="nixVersions.nix_2_13"
export NIX_VERSION="2.19.3"
export NIX_PACKAGE="nixVersions.nix_2_19"
export NIX_INSTALL_URL="https://nixos.org/releases/nix/nix-${NIX_VERSION}/install"
export NIX_INSTALL_SHA256="a9908cc48f5886b4f22172bdd2f9657873276fd295e78c6ed97fb308c6d284d0"
export NIX_INSTALL_SHA256="73d47b0ab783fddca1b2d44a03d52a74c97c28a1fc8ff5a29419079302ef9c3d"
export NIX_INSTALL_PATH="/tmp/nix-install-${NIX_VERSION}"
+1 -3
View File
@@ -21,8 +21,6 @@ function append_env_export() {
VAR_VALUE=$(must_get_env "${VAR_NAME}")
echo "export ${VAR_NAME}=\"${VAR_VALUE}\";" >> "${SECRETS_FILE_PATH}"
}
export COMMIT_HASH="$(git rev-parse --verify HEAD)"
nixOpts=()
# We create if now so the trap knows its location
@@ -73,4 +71,4 @@ else
fi
"${GIT_ROOT}/nix/scripts/build.sh" targets.mobile.android.release "${nixOpts[@]}"
"${GIT_ROOT}/nix/scripts/build.sh" targets.mobile.android.build "${nixOpts[@]}"
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
set -euo pipefail
set -m # needed to access jobs
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
# We run Metro in background while calling adb.
cleanupMetro() {
pkill -f run-metro.sh
rm -f metro-server-logs.log
}
# Using function gives a neater jobspec name.
runMetro() {
nohup "${GIT_ROOT}/scripts/run-metro.sh" 2>&1 \
| tee metro-server-logs.log
}
waitForMetro() {
set +e # Allow grep command to fail in the loop.
TIMEOUT=5
echo "Waiting for Metro server..." >&2
while ! grep -q "Welcome to Metro" metro-server-logs.log; do
echo -n "." >&2
sleep 1
if ((TIMEOUT == 0)); then
echo -e "\nMetro server timed out, exiting" >&2
set -e # Restore errexit for rest of script.
return 1
fi
((TIMEOUT--))
done
set -e # Restore errexit for rest of script.
}
# Generate android debug build.
export ANDROID_ABI_INCLUDE=$("${GIT_ROOT}/scripts/adb_devices_abis.sh")
export BUILD_ENV=debug
export BUILD_TYPE=debug
"${GIT_ROOT}/scripts/build-android.sh"
# Install the APK on running emulator or android device.
adb install ./result/app-debug.apk
trap cleanupMetro EXIT ERR INT QUIT
runMetro &
waitForMetro
# Start the installed app.
adb shell monkey -p im.status.ethereum.debug 1
# bring metro job to foreground
fg 'runMetro'
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
set -euo pipefail
set -m # needed to access jobs
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
# We run Metro in background while calling adb.
cleanupMetro() {
pkill -f run-metro.sh
rm -f metro-server-logs.log
}
# Using function gives a neater jobspec name.
runMetro() {
nohup "${GIT_ROOT}/scripts/run-metro.sh" 2>&1 \
| tee metro-server-logs.log
}
waitForMetro() {
set +e # Allow grep command to fail in the loop.
TIMEOUT=5
echo "Waiting for Metro server..." >&2
while ! grep -q "Welcome to Metro" metro-server-logs.log; do
echo -n "." >&2
sleep 1
if ((TIMEOUT == 0)); then
echo -e "\nMetro server timed out, exiting" >&2
set -e # Restore errexit for rest of script.
return 1
fi
((TIMEOUT--))
done
set -e # Restore errexit for rest of script.
}
# Check if the first argument is provided
if [ -z "${1-}" ]; then
echo "Error: No simulator name provided." >&2
exit 1
fi
SIMULATOR=${1}
# get our desired UUID
UUID=$(xcrun simctl list devices | grep -E "$SIMULATOR \(" | head -n 1 | awk -F '[()]' '{print $2}')
# get simulator status
SIMULATOR_STATE=$(xcrun simctl list devices | grep -E "$SIMULATOR \(" | head -n 1 | awk '{print $NF}')
# sometimes a simulator is already running, shut it down to avoid errors
if [ "$SIMULATOR_STATE" != "(Shutdown)" ]; then
xcrun simctl shutdown "$UUID"
fi
# boot up iOS for simulator
xcrun simctl boot "$UUID"
# start the simulator
open -a Simulator --args -CurrentDeviceUDID "$UUID"
BUILD_DIR="${GIT_ROOT}/build"
#iOS build of debug scheme
xcodebuild -workspace "ios/StatusIm.xcworkspace" -configuration Debug -scheme StatusIm -destination id="$UUID" -derivedDataPath "${BUILD_DIR}" | xcbeautify
APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphonesimulator/StatusIm.app"
# Install on the simulator
xcrun simctl install "$UUID" "$APP_PATH"
trap cleanupMetro EXIT ERR INT QUIT
runMetro &
waitForMetro
# launch the app when metro is ready
xcrun simctl launch "$UUID" im.status.ethereum.debug
# bring metro job to foreground
fg 'runMetro'
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
pkill -f 'react-native start'
react-native start --reset-cache
-17
View File
@@ -1,17 +0,0 @@
#!/usr/bin/env bash
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/scripts/colors.sh"
METRO_PORT=8081
METRO_PID="$(lsof -i :${METRO_PORT} | awk 'NR!=1 {print $2}' | sort -u | tr '\r\n' ' ')"
if [ ! -z "$METRO_PID" ]; then
echo -e "${YLW}TCP port ${METRO_PORT} is required by the Metro packager.\nThe following processes currently have the port open, preventing Metro from starting:${RST}"
ps -fp $METRO_PID
echo -e "${YLW}Do you want to terminate them (y/n)?${RST}"
read -n 1 term
[[ $term == 'y' ]] && kill $METRO_PID
fi
react-native start --reset-cache
-3
View File
@@ -45,9 +45,6 @@
;; To match the folder created by Nix build of JSBundle.
:output-dir "result"
:init-fn status-im.core/init
:build-hooks [(status-im.setup.build-hooks.worklets/transform-output)
(status-im.setup.build-hooks.worklets/optimize-start)
(status-im.setup.build-hooks.worklets/optimize-output)]
;; When false, the Shadow-CLJS watcher won't automatically refresh
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
@@ -36,7 +36,7 @@
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet-old)
(wallet/restart-wallet-service nil)
(add-new-contact/set-new-identity-reconnected)]
#(add-new-contact/set-new-identity-reconnected %)]
logged-in?
[(mailserver/process-next-messages-request)
+1 -1
View File
@@ -72,7 +72,7 @@
:PeerExchange true
:Port 0
:UDPPort 0
:LightClient true})
:LightClient false})
(def login-node-config
{:WalletConfig (cond-> {:Enabled true}
+5 -1
View File
@@ -81,5 +81,9 @@
{:db (-> db
(assoc :contacts/identity identity)
(assoc :contacts/ens-name ens-name))
:dispatch [:contacts/build-contact identity ens-name true]}
:dispatch [:contacts/build-contact
{:pubkey identity
:ens ens-name
:success-fn (fn [_]
{:dispatch [:open-modal :profile]})}]}
{:dispatch [:navigate-to :my-profile]})))
@@ -55,7 +55,8 @@
:on-change (fn [text]
(re-frame/dispatch [:wallet-legacy/search-recipient-filter-changed text])
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:contacts/set-new-identity text] 300))}]]))
(debounce/debounce-and-dispatch [:contacts/set-new-identity {:input text}]
300))}]]))
(defn section
[_ _ _]
@@ -3,7 +3,7 @@
(def container
{:height 40
:flex-direction :row
:padding-horizontal 20
:padding-horizontal 16
:align-items :center})
(defn text
@@ -30,7 +30,7 @@
(defn circular-progress
[{:keys [color percentage]}]
(let [strength-indicator-radius 6.5
(let [strength-indicator-radius 7.5
strength-indicator-circumference (* 2 Math/PI strength-indicator-radius)]
[svg/svg
{:view-box "0 0 16 16"
@@ -63,7 +63,10 @@
:alert [icon/icon :i/alert
{:color color
:size 16}]
[circular-progress {:color color :percentage percentage}])))
[rn/view
{:padding-left 4
:padding-right 2}
[circular-progress {:color color :percentage percentage}]])))
(defn view
"Options
@@ -137,7 +137,8 @@
:description description}]))
(defn- right-icon
[{:keys [theme type on-button-press on-button-long-press button-disabled? button-icon]}]
[{:keys [theme type on-button-press on-button-long-press button-disabled? button-icon button-type]
:or {button-type :primary}}]
(cond
(= :info type)
[icons/icon
@@ -153,7 +154,7 @@
:on-press on-button-press
:on-long-press on-button-long-press
:disabled? button-disabled?
:type :primary
:type button-type
:size 24
:icon-only? true}
button-icon]))
@@ -182,7 +183,7 @@
(defn- view-internal
[{:keys [title title-icon type theme description blur? community-name community-logo button-icon
account-name emoji context-tag-type
account-name emoji context-tag-type button-type
on-button-press
on-button-long-press
button-disabled? account-avatar-emoji account-avatar-type customization-color icon-avatar
@@ -221,6 +222,7 @@
[right-icon
{:theme theme
:type type
:button-type button-type
:on-button-press on-button-press
:on-button-long-press on-button-long-press
:button-disabled? button-disabled?
@@ -311,7 +311,7 @@
- title
- description
- picture: a valid rn/image `:source` value
`:wallet-network`
`:wallet-networks`
- networks: a vector of network image source
- networks-on-press: a callback
`:community`
@@ -11,8 +11,8 @@
:padding-bottom 8})
(defn settings-items
[{:keys [blur? theme]}]
{:margin-top 12
[{:keys [label blur? theme]}]
{:margin-top (if label 12 4)
:border-radius 16
:background-color (if blur?
colors/white-opa-5
@@ -0,0 +1,52 @@
(ns quo.components.tags.collectible-tag.component-spec
(:require
[quo.components.tags.collectible-tag.view :as collectible-tag]
[test-helpers.component :as h]))
(def collectible-name "Collectible")
(def collectible-id "#123")
(defn get-test-data
[{:keys [options blur? size]}]
{:collectible-name collectible-name
:collectible-id collectible-id
:collectible-img-src {:uri "https://example.com/image.jpg"}
:options options
:blur? (or blur? false)
:size (or size :size-24)})
(h/describe "Collectible_tag tests"
(h/test "Renders Default option"
(let [data (get-test-data {})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders Add option"
(let [data (get-test-data {:options :add})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders Hold option"
(let [data (get-test-data {:options :hold})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders with Blur"
(let [data (get-test-data {:blur? true})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders without Blur"
(let [data (get-test-data {:blur? false})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders with Size 24"
(let [data (get-test-data {:size :size-24})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name))))
(h/test "Renders with Size 32"
(let [data (get-test-data {:size :size-32})]
(h/render-with-theme-provider [collectible-tag/view data])
(h/is-truthy (h/get-by-text collectible-name)))))
@@ -0,0 +1,15 @@
(ns quo.components.tags.collectible-tag.schema)
(def ?schema
[:=>
[:catn
[:props
[:map
[:options {:optional true} [:maybe [:enum :add :hold]]]
[:size {:optional true} [:maybe [:enum :size-24 :size-32]]]
[:blur? {:optional true} [:maybe :boolean]]
[:theme :schema.common/theme]
[:collectible-img-src :schema.common/image-source]
[:collectible-name :string]
[:collectible-id :string]]]]
:any])
@@ -1,70 +1,59 @@
(ns quo.components.tags.collectible-tag.view
(:require
[oops.core :as oops]
[quo.components.icon :as icons]
[quo.components.markdown.text :as text]
[quo.components.tags.collectible-tag.schema :as component-schema]
[quo.components.tags.collectible-tag.style :as style]
[quo.theme]
[react-native.core :as rn]
[react-native.hole-view :as hole-view]
[reagent.core :as reagent]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:options {:optional true} [:maybe [:enum false :add :hold]]]
[:size {:optional true} [:enum :size-24 :size-32]]
[:blur? {:optional true} :boolean]
[:theme :schema.common/theme]
[:collectible-img-src [:or :int :string]]
[:collectible-name :string]
[:collectible-id :string]
[:container-width :number]
[:on-layout {:optional true} [:maybe fn?]]]]]
:any])
(defn- view-internal
[]
(fn [{:keys [options size blur? theme collectible-img-src collectible-name collectible-id
container-width on-layout]
:or {size :size-24}}]
[rn/view
{:on-layout on-layout}
[hole-view/hole-view
{:holes (if options
[{:x (- container-width
(case size
:size-24 10
:size-32 12
nil))
:y (case size
:size-24 -6
:size-32 -4
nil)
:width 16
:height 16
:borderRadius 8}]
[])}
[rn/view {:style (style/container size options blur? theme)}
[rn/image {:style (style/collectible-img size) :source collectible-img-src}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/label theme)}
collectible-name]
[text/text
{:size :paragraph-2
:weight :medium
:margin-left 5
:style (style/label theme)}
collectible-id]]]
(when options
[rn/view {:style (style/options-icon size)}
[icons/icon (if (= options :hold) :i/hold :i/add-token)
{:size 20
:no-color true}]])]))
(let [container-width (reagent/atom 0)
on-layout #(->> (oops/oget % :nativeEvent :layout :width)
(reset! container-width))]
(fn [{:keys [options blur? theme collectible-img-src collectible-name collectible-id] :as props}]
(let [size (or (:size props) :size-24)]
[rn/view
{:on-layout on-layout}
[hole-view/hole-view
{:holes (if options
[{:x (- @container-width
(case size
:size-24 10
:size-32 12
nil))
:y (case size
:size-24 -6
:size-32 -4
nil)
:width 16
:height 16
:borderRadius 8}]
[])}
[rn/view {:style (style/container size options blur? theme)}
[rn/image {:style (style/collectible-img size) :source collectible-img-src}]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/label theme)}
collectible-name]
[text/text
{:size :paragraph-2
:weight :medium
:margin-left 5
:style (style/label theme)}
collectible-id]]]
(when options
[rn/view {:style (style/options-icon size)}
[icons/icon (if (= options :hold) :i/hold :i/add-token)
{:size 20
:no-color true}]])]))))
(def view
(quo.theme/with-theme
(schema/instrument #'view-internal ?schema)))
(schema/instrument #'view-internal component-schema/?schema)))
@@ -18,5 +18,6 @@
[:disabled? {:optional true} [:maybe :boolean]]
[:on-change {:optional true} [:maybe fn?]]
[:container-style {:optional true} [:maybe :map]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:theme :schema.common/theme]]]]
:any])
@@ -42,9 +42,11 @@
(defn- view-internal
[{:keys
[checked? disabled? on-change token-details keycard? theme container-style]
[checked? disabled? on-change token-details keycard? theme container-style customization-color]
{:keys
[name address emoji customization-color]} :account}]
[name address emoji]
:as account} :account
:or {customization-color :blue}}]
[rn/view
{:style (merge (style/container theme) container-style)
:accessibility-label :wallet-account-permissions}
@@ -52,7 +54,7 @@
[account-avatar/view
{:size 32
:emoji emoji
:customization-color customization-color}]
:customization-color (:customization-color account)}]
[rn/view {:style style/account-details}
[rn/view {:style style/name-and-keycard}
[text/text
@@ -67,10 +69,11 @@
{:address address
:format :short}]]
[selectors/view
{:type :checkbox
:checked? checked?
:disabled? disabled?
:on-change on-change}]]
{:type :checkbox
:checked? checked?
:customization-color customization-color
:disabled? disabled?
:on-change on-change}]]
[token-details-section token-details]])
@@ -15,101 +15,101 @@
(h/describe "Confirmation Progress"
(h/test "component renders when state is sending and network is optimism"
(h/render-with-theme-provider [quo/confirmation-propgress
(h/render-with-theme-provider [quo/confirmation-progress
(get-test-data {:state :sending
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box))))
(h/test "component renders when state is confirmed and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :confirmed
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalising and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :finalising
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalized and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :finalized
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is error and network is optimism"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :error
:network :optimism})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is sending and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :sending
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is confirmed and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :confirmed
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalising and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :finalising
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is finalized and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :finalized
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is error and network is arbitrum"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :error
:network :arbitrum})])
(h/is-truthy (h/get-by-label-text :progress-box)))
(h/test "component renders when state is pending and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {})])
[quo/confirmation-progress (get-test-data {})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is sending and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :sending})])
[quo/confirmation-progress (get-test-data {:state :sending})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is confirmed and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :confirmed})])
[quo/confirmation-progress (get-test-data {:state :confirmed})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is finalising and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :finalising})])
[quo/confirmation-progress (get-test-data {:state :finalising})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is finalized and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress (get-test-data {:state :finalized})])
[quo/confirmation-progress (get-test-data {:state :finalized})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
(h/test "component renders when state is error and network is mainnet"
(h/render-with-theme-provider
[quo/confirmation-propgress
[quo/confirmation-progress
(get-test-data {:state :error})])
(h/is-truthy (h/get-by-label-text :mainnet-progress-box)))
+1 -1
View File
@@ -418,7 +418,7 @@
(def account-permissions quo.components.wallet.account-permissions.view/view)
(def address-text quo.components.wallet.address-text.view/view)
(def amount-input quo.components.wallet.amount-input.view/view)
(def confirmation-propgress quo.components.wallet.confirmation-progress.view/view)
(def confirmation-progress quo.components.wallet.confirmation-progress.view/view)
(def keypair quo.components.wallet.keypair.view/view)
(def network-amount quo.components.wallet.network-amount.view/view)
(def network-bridge quo.components.wallet.network-bridge.view/view)
+1
View File
@@ -79,6 +79,7 @@
quo.components.share.share-qr-code.component-spec
quo.components.switchers.base-card.component-spec
quo.components.switchers.group-messaging-card.component-spec
quo.components.tags.collectible-tag.component-spec
quo.components.tags.network-tags.component-spec
quo.components.tags.status-tags-component-spec
quo.components.tags.summary-tag.component-spec
+1 -4
View File
@@ -20,8 +20,7 @@
LinearTransition
enableLayoutAnimations
useAnimatedScrollHandler
runOnJS)
:as reanimated*]
runOnJS)]
["react-native-redash" :refer (withPause)]
[oops.core :as oops]
[react-native.flat-list :as rn-flat-list]
@@ -114,8 +113,6 @@
(when (and anim (some? v))
(set! (.-value anim) v)))
(def interpolate* reanimated*/interpolate)
(defn interpolate
([shared-value input-range output-range]
(interpolate shared-value input-range output-range nil))
+6 -2
View File
@@ -63,7 +63,7 @@
item-height (reagent/atom 0)]
(fn [{:keys [hide? insets theme]}
{:keys [content selected-item padding-bottom-override border-radius on-close shell?
gradient-cover? customization-color hide-handle?]
gradient-cover? customization-color hide-handle? blur-radius]
:or {border-radius 12}}]
(let [{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
@@ -106,7 +106,11 @@
{:transform [{:translateY translate-y}]}
(style/sheet insets window-height selected-item))}
(when shell?
[blur/ios-view {:style style/shell-bg}])
[blur/ios-view
{:style style/shell-bg
:blur-radius (or blur-radius 20)
:blur-type :transparent
:overlay-color :transparent}])
(when selected-item
[rn/view
{:on-layout #(reset! item-height (.-nativeEvent.layout.height ^js %))
@@ -15,12 +15,12 @@
(def ^:const drag-threshold 200)
(defn drag-gesture
[{:keys [translate-y opacity scroll-enabled curr-scroll close reset-open-sheet set-animating-true]}]
[{:keys [translate-y opacity scroll-enabled? curr-scroll close reset-open-sheet set-animating-true]}]
(-> (gesture/gesture-pan)
(gesture/on-start (fn [e]
(set-animating-true)
(when (< (oops/oget e "velocityY") 0)
(reset! scroll-enabled true))))
(reset! scroll-enabled? true))))
(gesture/on-update (fn [e]
(let [translation (oops/oget e "translationY")
progress (Math/abs (/ translation drag-threshold))]
@@ -34,7 +34,7 @@
(gesture/on-finalize (fn [e]
(when (and (>= (oops/oget e "velocityY") 0)
(<= @curr-scroll (if platform/ios? -1 0)))
(reset! scroll-enabled false))))))
(reset! scroll-enabled? false))))))
(defn on-scroll
[e curr-scroll]
@@ -43,7 +43,7 @@
(defn- f-view
[_]
(let [scroll-enabled (reagent/atom true)
(let [scroll-enabled? (reagent/atom true)
curr-scroll (reagent/atom 0)
animating? (reagent/atom true)
set-animating-true #(reset! animating? true)
@@ -63,7 +63,7 @@
(reanimated/animate translate-y 0 300)
(reanimated/animate opacity 1 300)
(set-animating-false 300)
(reset! scroll-enabled true))]
(reset! scroll-enabled? true))]
(rn/use-effect
(fn []
(reanimated/animate translate-y 0 300)
@@ -76,7 +76,7 @@
[gesture/gesture-detector
{:gesture (drag-gesture {:translate-y translate-y
:opacity opacity
:scroll-enabled scroll-enabled
:scroll-enabled? scroll-enabled?
:curr-scroll curr-scroll
:close close
:reset-open-sheet reset-open-sheet
@@ -87,7 +87,7 @@
[content
{:insets insets
:close close
:scroll-enabled scroll-enabled
:scroll-enabled? @scroll-enabled?
:current-scroll curr-scroll
:on-scroll #(on-scroll % curr-scroll)
:sheet-animating? animating?}]]]]))))
+2 -2
View File
@@ -94,11 +94,11 @@
:container-style style/empty-results}])
(defn- render-list
[{:keys [theme filtered-data on-viewable-items-changed scroll-enabled on-scroll
[{:keys [theme filtered-data on-viewable-items-changed scroll-enabled? on-scroll
on-select set-scroll-ref close sheet-animating?]}]
[gesture/flat-list
{:ref set-scroll-ref
:scroll-enabled @scroll-enabled
:scroll-enabled scroll-enabled?
:data (or filtered-data emoji-picker.data/flatten-data)
:initial-num-to-render 14
:max-to-render-per-batch 10
+1 -1
View File
@@ -33,7 +33,7 @@
nil)]
[quo/top-nav
{:avatar-on-press #(rf/dispatch [:open-modal :settings])
:scan-on-press #(js/alert "to be implemented")
:scan-on-press #(rf/dispatch [:open-modal :shell-qr-reader])
:activity-center-on-press #(rf/dispatch [:activity-center/open])
:qr-code-on-press #(rf/dispatch [:open-modal :share-shell])
:container-style (merge style/top-nav-container container-style)
+19 -9
View File
@@ -26,8 +26,18 @@
(def web2-domain "status.app")
(def user-path "u#")
(def user-with-data-path "u/")
(def community-path "c#")
(def community-with-data-path "c/")
(def channel-path "cc/")
(def web-urls (map #(str % web2-domain "/") web-prefixes))
(defn path-urls
[path]
(map #(str % path) web-urls))
(def handled-schemes (set (into uri-schemes web-urls)))
(def group-chat-extractor
@@ -41,15 +51,15 @@
(def routes
[""
{handled-schemes {["c/" :community-data] :community
["cc/" :community-data] :community-chat
["p/" :chat-id] :private-chat
["cr/" :community-id] :community-requests
"g/" group-chat-extractor
["wallet/" :account] :wallet-account
["u/" :user-data] :user
"c" :community
"u" :user}
{handled-schemes {[community-with-data-path :community-data] :community
[channel-path :community-data] :community-chat
["p/" :chat-id] :private-chat
["cr/" :community-id] :community-requests
"g/" group-chat-extractor
["wallet/" :account] :wallet-account
[user-with-data-path :user-data] :user
"c" :community
"u" :user}
ethereum-scheme eip-extractor}])
(defn parse-query-params
+13 -2
View File
@@ -1,11 +1,11 @@
(ns status-im.common.validation.profile
(:require [clojure.string :as string]
[status-im.constants :as constants]
[utils.i18n :as i18n]))
;; NOTE - validation should match with Desktop
;; https://github.com/status-im/status-desktop/blob/2ba96803168461088346bf5030df750cb226df4c/ui/imports/utils/Constants.qml#L468
(def min-length 5)
(def max-length 24)
(def emoji-regex
#"(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])")
@@ -22,7 +22,9 @@
(defn name-too-short? [s] (< (count (string/trim (str s))) min-length))
(defn name-too-long? [s] (> (count (string/trim (str s))) max-length))
(defn name-too-long? [s] (> (count (string/trim (str s))) constants/profile-name-max-length))
(defn bio-too-long? [s] (> (count (string/trim (str s))) constants/profile-bio-max-length))
(defn validation-name
[s]
@@ -39,3 +41,12 @@
{:check (i18n/label :t/special-characters)})
(name-too-short? s) (i18n/label :t/minimum-characters {:min-chars min-length})
(name-too-long? s) (i18n/label :t/profile-name-is-too-long)))
(defn validation-bio
[s]
(cond
(or (= s nil) (= s "")) nil
(has-emojis? s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/emojis)})
(has-special-characters? s) (i18n/label :t/are-not-allowed
{:check (i18n/label :t/special-characters)})
(bio-too-long? s) (i18n/label :t/bio-is-too-long)))
+1 -1
View File
@@ -167,5 +167,5 @@
(def default-kdf-iterations 3200)
(def community-accounts-selection-enabled? (enabled? (get-config :ACCOUNT_SELECTION_ENABLED "0")))
(def community-accounts-selection-enabled? true)
(def fetch-messages-enabled? (enabled? (get-config :FETCH_MESSAGES_ENABLED "1")))
+4
View File
@@ -107,6 +107,7 @@
(def ^:const profile-default-color :blue)
(def ^:const profile-name-max-length 24)
(def ^:const profile-bio-max-length 240)
(def ^:const profile-default-currency :usd)
(def ^:const profile-pictures-show-to-contacts-only 1)
@@ -257,6 +258,7 @@
(def ^:const terms-of-service-link "https://status.im/terms-of-use")
(def ^:const docs-link "https://status.im/docs/")
(def ^:const principles-link "https://our.status.im/our-principles/")
(def ^:const create-account-link "https://status.app/help/wallet/create-wallet-accounts")
(def ^:const visibility-status-unknown 0)
(def ^:const visibility-status-automatic 1)
@@ -431,6 +433,8 @@
(def ^:const optimism-network-name :optimism)
(def ^:const arbitrum-network-name :arbitrum)
(def ^:const default-network-names #{mainnet-network-name optimism-network-name arbitrum-network-name})
(def ^:const chain-id-separator ":")
(def ^:const account-default-customization-color :blue)
@@ -1,13 +1,12 @@
(ns status-im.contexts.chat.home.add-new-contact.events
(:require
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.common.validators :as validators]
[status-im.contexts.chat.contacts.events :as data-store.contacts]
status-im.contexts.chat.home.add-new-contact.effects
[status-im.navigation.events :as navigation]
[utils.ens.stateofus :as stateofus]
[utils.ethereum.chain :as chain]
[utils.re-frame :as rf]
[utils.string :as utils.string]))
(defn init-contact
@@ -87,72 +86,64 @@
(def validate-contact (comp ->state ->type ->id))
(defn dispatcher [event input] (fn [arg] (rf/dispatch [event input arg])))
(declare build-contact)
(rf/defn set-new-identity
{:events [:contacts/set-new-identity]}
[{:keys [db]} input scanned]
(defn set-new-identity
[{:keys [db]} [{:keys [input build-success-fn failure-fn]}]]
(let [user-public-key (get-in db [:profile/profile :public-key])
{:keys [input id ens state]
:as contact} (-> {:user-public-key user-public-key
:input input
:scanned scanned}
:scanned input}
init-contact
validate-contact)]
(case state
:empty {:db (dissoc db :contacts/new-identity)}
(:valid :invalid) {:db (assoc db :contacts/new-identity contact)}
:decompress-key {:db (assoc db :contacts/new-identity contact)
:serialization/decompress-public-key
{:compressed-key id
:on-success
(dispatcher :contacts/set-new-identity-success input)
#(re-frame/dispatch [:contacts/set-new-identity-success
{:input input
:pubkey %
:build-success-fn build-success-fn}])
:on-error
(dispatcher :contacts/set-new-identity-error input)}}
#(re-frame/dispatch [:contacts/set-new-identity-error
{:input input
:pubkey %
:failure-fn failure-fn}])}}
:resolve-ens {:db (assoc db :contacts/new-identity contact)
:effects.contacts/resolve-public-key-from-ens
{:chain-id (chain/chain-id db)
:ens ens
:on-success
(dispatcher :contacts/set-new-identity-success input)
#(re-frame/dispatch [:contacts/set-new-identity-success
{:input input
:pubkey %
:build-success-fn build-success-fn}])
:on-error
(dispatcher :contacts/set-new-identity-error input)}})))
#(re-frame/dispatch [:contacts/set-new-identity-error
{:input input
:pubkey %
:failure-fn failure-fn}])}})))
(re-frame/reg-event-fx :contacts/set-new-identity set-new-identity)
(rf/defn build-contact
{:events [:contacts/build-contact]}
[_ pubkey ens open-profile-modal?]
{:json-rpc/call [{:method "wakuext_buildContact"
:params [{:publicKey pubkey
:ENSName ens}]
:js-response true
:on-success #(rf/dispatch [:contacts/contact-built
pubkey
open-profile-modal?
(data-store.contacts/<-rpc-js %)])}]})
(rf/defn contact-built
{:events [:contacts/contact-built]}
[{:keys [db]} pubkey open-profile-modal? contact]
(merge {:db (assoc-in db [:contacts/contacts pubkey] contact)}
(when open-profile-modal?
{:dispatch [:open-modal :profile]})))
(rf/defn set-new-identity-success
{:events [:contacts/set-new-identity-success]}
[{:keys [db]} input pubkey]
(defn- set-new-identity-success
[{:keys [db]} [{:keys [input pubkey build-success-fn]}]]
(let [contact (get-in db [:contacts/new-identity])]
(when (= (:input contact) input)
(rf/merge {:db (assoc db
:contacts/new-identity
(->state (assoc contact :public-key pubkey)))}
(build-contact pubkey (:ens contact) false)))))
{:db (assoc db :contacts/new-identity (->state (assoc contact :public-key pubkey)))
:dispatch [:contacts/build-contact
{:pubkey pubkey
:ens (:ens contact)
:success-fn build-success-fn}]})))
(rf/defn set-new-identity-error
{:events [:contacts/set-new-identity-error]}
[{:keys [db]} input err]
(re-frame/reg-event-fx :contacts/set-new-identity-success set-new-identity-success)
(defn- set-new-identity-error
[{:keys [db]} [{:keys [input err failure-fn]}]]
(let [contact (get-in db [:contacts/new-identity])]
(when (= (:input contact) input)
(let [state (cond
@@ -163,21 +154,41 @@
(string/includes? (:message err) "no such host")))
{:state :invalid :msg :t/lost-connection}
:else {:state :invalid})]
{:db (assoc db :contacts/new-identity (merge contact state))}))))
(merge {:db (assoc db :contacts/new-identity (merge contact state))}
(when failure-fn
(failure-fn)))))))
(rf/defn clear-new-identity
{:events [:contacts/clear-new-identity :contacts/new-chat-focus]}
(re-frame/reg-event-fx :contacts/set-new-identity-error set-new-identity-error)
(defn- build-contact
[_ [{:keys [pubkey ens success-fn]}]]
{:json-rpc/call [{:method "wakuext_buildContact"
:params [{:publicKey pubkey
:ENSName ens}]
:js-response true
:on-success #(re-frame/dispatch [:contacts/build-contact-success
{:pubkey pubkey
:contact (data-store.contacts/<-rpc-js %)
:success-fn success-fn}])}]})
(re-frame/reg-event-fx :contacts/build-contact build-contact)
(defn- build-contact-success
[{:keys [db]} [{:keys [pubkey contact success-fn]}]]
(merge {:db (assoc-in db [:contacts/contacts pubkey] contact)}
(when success-fn
(success-fn contact))))
(re-frame/reg-event-fx :contacts/build-contact-success build-contact-success)
(defn- clear-new-identity
[{:keys [db]}]
{:db (dissoc db :contacts/new-identity)})
(rf/defn qr-code-scanned
{:events [:contacts/qr-code-scanned]}
[{:keys [db] :as cofx} scanned]
(rf/merge cofx
(set-new-identity scanned scanned)
(navigation/navigate-back)))
(re-frame/reg-event-fx :contacts/clear-new-identity clear-new-identity)
(rf/defn set-new-identity-reconnected
(defn set-new-identity-reconnected
[{:keys [db]}]
(let [input (get-in db [:contacts/new-identity :input])]
(rf/dispatch [:contacts/set-new-identity input])))
(re-frame/dispatch [:contacts/set-new-identity {:input input}])))
@@ -2,6 +2,7 @@
(:require
[cljs.test :refer-macros [deftest are]]
matcher-combinators.test
[re-frame.core :as re-frame]
[status-im.contexts.chat.home.add-new-contact.events :as events]))
(def user-ukey
@@ -90,8 +91,8 @@
:config {:NetworkId 1}}}})
(deftest set-new-identity-test
(with-redefs [events/dispatcher (fn [& args] args)]
(are [i edb] (match? (events/set-new-identity {:db db} i nil) edb)
(with-redefs [re-frame/dispatch (fn [& args] args)]
(are [i edb] (match? (events/set-new-identity {:db db} [{:input i}]) edb)
"" {:db db}
@@ -103,6 +104,7 @@
:id ukey
:type :public-key
:public-key ukey
:scanned ukey
:state :invalid
:msg :t/not-a-chatkey}))}
@@ -115,6 +117,7 @@
:type :ens
:ens ens-stateofus-eth
:public-key nil ; not yet...
:scanned ens
:state :resolve-ens}))
:effects.contacts/resolve-public-key-from-ens
{:chain-id 1
@@ -131,6 +134,7 @@
:id user-ckey
:type :compressed-key
:public-key nil ; not yet...
:scanned user-ckey
:state :decompress-key}))
:serialization/decompress-public-key
{:compressed-key user-ckey
@@ -13,7 +13,8 @@
(rn/dismiss-keyboard!))
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:on-success-scan #(debounce/debounce-and-dispatch [:contacts/set-new-identity % %] 300)}]]))
:on-success-scan #(debounce/debounce-and-dispatch [:contacts/set-new-identity {:input %}]
300)}]]))
(defn view
[]
@@ -59,7 +59,8 @@
paste-on-input #(clipboard/get-string
(fn [clipboard-text]
(reset! input-value clipboard-text)
(rf/dispatch [:contacts/set-new-identity clipboard-text nil])))]
(rf/dispatch [:contacts/set-new-identity
{:input clipboard-text}])))]
(let [{:keys [scanned]} (rf/sub [:contacts/new-identity])
empty-input? (and (string/blank? @input-value)
(string/blank? scanned))]
@@ -86,7 +87,7 @@
:value (or scanned @input-value)
:on-change-text (fn [new-text]
(reset! input-value new-text)
(as-> [:contacts/set-new-identity new-text nil] $
(as-> [:contacts/set-new-identity {:input new-text}] $
(if (string/blank? scanned)
(debounce/debounce-and-dispatch $ 600)
(rf/dispatch-sync $))))}]
@@ -65,7 +65,7 @@
item])))
(defn- view-internal
[{:keys [scroll-enabled on-scroll close theme]}]
[{:keys [scroll-enabled? on-scroll close theme]}]
(let [contacts (rf/sub [:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
selected-contacts (rf/sub [:group/selected-contacts])
@@ -105,7 +105,7 @@
:render-section-header-fn contact-list/contacts-section-header
:content-container-style {:padding-bottom 70}
:render-fn contact-item-render
:scroll-enabled @scroll-enabled
:scroll-enabled scroll-enabled?
:on-scroll on-scroll}])
(when contacts-selected?
[quo/button
@@ -61,7 +61,7 @@
(str (:title item) index))
(defn- f-album-selector
[{:keys [scroll-enabled on-scroll]} album? selected-album top]
[{:keys [scroll-enabled? on-scroll]} album? selected-album top]
(let [albums (rf/sub [:camera-roll/albums])
total-photos-count-android (rf/sub [:camera-roll/total-photos-count-android])
total-photos-count-ios (rf/sub [:camera-roll/total-photos-count-ios])
@@ -87,7 +87,7 @@
:content-container-style {:padding-top 64
:padding-bottom 40}
:key-fn key-fn
:scroll-enabled @scroll-enabled
:scroll-enabled scroll-enabled?
:on-scroll on-scroll
:style {:height window-height}}]]))
@@ -90,7 +90,7 @@
(inc (utils.collection/first-index #(= (:uri item) (:uri %)) @selected))]])]))
(defn photo-selector
[{:keys [scroll-enabled on-scroll current-scroll close] :as sheet}]
[{:keys [scroll-enabled? on-scroll current-scroll close] :as sheet}]
(rf/dispatch [:photo-selector/get-photos-for-selected-album])
(rf/dispatch [:photo-selector/camera-roll-get-albums])
(let [album? (reagent/atom false)
@@ -134,7 +134,7 @@
:padding-bottom (+ (safe-area/get-bottom) 100)
:padding-top 64}
:on-scroll on-scroll
:scroll-enabled @scroll-enabled
:scroll-enabled scroll-enabled?
:on-end-reached (fn []
(when (and (not loading?) has-next-page?)
(rf/dispatch [:photo-selector/camera-roll-loading-more true])
@@ -7,10 +7,6 @@
(def container
{:flex 1})
(def page-top
{:padding-vertical 12
:padding-horizontal screen-horizontal-padding})
(def section-title
{:padding-top 12
:padding-bottom 4
@@ -18,11 +14,6 @@
(defn bottom-actions
[]
{:position :absolute
:background-color (colors/theme-colors colors/white colors/neutral-95)
:bottom 0
:left 0
:right 0
{:padding-top 12
:padding-horizontal screen-horizontal-padding
:padding-vertical 12
:flex 1})
:background-color (colors/theme-colors colors/white colors/neutral-95)})
@@ -28,7 +28,7 @@
highest-role-text (i18n/label (communities.utils/role->translation-key
highest-permission-role
:t/member))]
[rn/view {:style style/container}
[rn/safe-area-view {:style style/container}
[quo/page-nav
{:text-align :left
:icon-name :i/close
@@ -2,6 +2,7 @@
(:require [quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[status-im.common.not-implemented :as not-implemented]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
@@ -27,32 +28,37 @@
:collectible-img-src (resources/get-mock-image :collectible))
(= type constants/community-token-type-erc20)
(assoc :amount (str (money/with-precision (money/token->unit amount decimals) 3))
(assoc :amount (str (money/token->unit amount decimals))
:token (:symbol balance)))))
(defn- account-item
[{:keys [customization-color address name emoji]} _ _ [selected-addresses community-id]]
[{:keys [color address name emoji]} _ _
{:keys [selected-addresses community-id share-all-addresses? community-color]}]
(let [balances (rf/sub [:communities/permissioned-balances-by-address community-id address])]
[quo/account-permissions
{:account {:name name
:address address
:emoji emoji
:customization-color customization-color}
:token-details (balances->components-props balances)
:checked? (contains? selected-addresses address)
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
address community-id])
:container-style {:margin-bottom 8}}]))
{:account {:name name
:address address
:emoji emoji
:customization-color color}
:token-details (balances->components-props balances)
:checked? (contains? selected-addresses address)
:disabled? share-all-addresses?
:on-change #(rf/dispatch [:communities/toggle-selected-permission-address
address community-id])
:container-style {:margin-bottom 8}
:customization-color community-color}]))
(defn view
[]
[{:keys [scroll-enabled? on-scroll]}]
(let [{id :community-id} (rf/sub [:get-screen-params])]
(rf/dispatch [:communities/get-permissioned-balances id])
(fn []
(let [{:keys [name color images]} (rf/sub [:communities/community id])
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
accounts (rf/sub [:wallet/accounts-with-customization-color])
accounts (rf/sub [:wallet/accounts-without-watched-accounts])
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
share-all-addresses? (rf/sub [:communities/share-all-addresses? id])
unsaved-address-changes? (rf/sub [:communities/unsaved-address-changes? id])
highest-role-text (when highest-permission-role
(i18n/label (communities.utils/role->translation-key
highest-permission-role)))]
@@ -63,14 +69,31 @@
:context-tag-type :community
:community-name name
:button-icon :i/info
:button-type :grey
:on-button-press not-implemented/alert
:community-logo (get-in images [:thumbnail :uri])
:customization-color color}]
[rn/flat-list
[quo/category
{:list-type :settings
:data [{:title (i18n/label :t/share-all-current-and-future-addresses)
:action :selector
:action-props {:on-change #(rf/dispatch
[:communities/toggle-share-all-addresses
id])
:customization-color color
:checked? share-all-addresses?}}]
:container-style {:padding-bottom 16}}]
[gesture/flat-list
{:render-fn account-item
:render-data [selected-addresses id]
:content-container-style {:padding 20}
:render-data {:selected-addresses selected-addresses
:community-id id
:share-all-addresses? share-all-addresses?
:community-color color}
:content-container-style {:padding-horizontal 20}
:scroll-enabled scroll-enabled?
:on-scroll on-scroll
:key-fn :address
:data accounts}]
@@ -106,7 +129,9 @@
[quo/button
{:container-style {:flex 1}
:customization-color color
:disabled? (empty? selected-addresses)
:disabled? (or (empty? selected-addresses)
(not highest-permission-role)
(not unsaved-address-changes?))
:on-press (fn []
(rf/dispatch [:communities/update-previous-permission-addresses id])
(rf/dispatch [:navigate-back]))}
@@ -3,5 +3,6 @@
(def community-rule
{:flex 1
:align-items :flex-start
:padding-vertical 8
:padding-top 8
:margin-bottom 12
:padding-horizontal 20})
@@ -8,8 +8,7 @@
(defn token-requirements
[]
(fn [id]
(let [{:keys [can-request-access?
number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])]
(let [{:keys [can-request-access? tokens]} (rf/sub [:community/token-gated-overview id])]
[rn/view {:style {:padding-horizontal 12}}
[quo/text {:weight :medium}
(if can-request-access?
@@ -17,7 +16,6 @@
(i18n/label :t/you-not-eligible-to-join))]
[quo/text {:style {:padding-bottom 18} :size :paragraph-2}
(if can-request-access?
(i18n/label :t/you-hold-number-of-hold-tokens-of-these
{:number-of-hold-tokens number-of-hold-tokens})
(i18n/label :t/you-hodl)
(i18n/label :t/you-must-hold))]
[quo/token-requirement-list {:tokens tokens}]])))
+34 -11
View File
@@ -12,6 +12,7 @@
status-im.contexts.communities.actions.addresses-for-permissions.events
status-im.contexts.communities.actions.community-options.events
status-im.contexts.communities.actions.leave.events
[status-im.contexts.communities.utils :as utils]
[status-im.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -163,15 +164,16 @@
(defn initialize-permission-addresses
[{:keys [db]} [community-id]]
(when community-id
(let [accounts (get-in db [:wallet :accounts])
sorted-accounts (sort-by :position (vals accounts))
addresses (set (map :address sorted-accounts))]
(let [accounts (utils/sorted-non-watch-only-accounts db)
addresses (set (map :address accounts))]
{:db (update-in db
[:communities community-id]
assoc
:previous-share-all-addresses? true
:share-all-addresses? true
:previous-permission-addresses addresses
:selected-permission-addresses addresses
:airdrop-address (:address (first sorted-accounts)))})))
:airdrop-address (:address (first accounts)))})))
(rf/reg-event-fx :communities/initialize-permission-addresses
initialize-permission-addresses)
@@ -179,17 +181,18 @@
(defn update-previous-permission-addresses
[{:keys [db]} [community-id]]
(when community-id
(let [accounts (get-in db [:wallet :accounts])
sorted-accounts (sort-by :position (vals accounts))
(let [accounts (utils/sorted-non-watch-only-accounts db)
selected-permission-addresses (get-in db
[:communities community-id
:selected-permission-addresses])
selected-accounts (filter #(contains? selected-permission-addresses (:address %))
sorted-accounts)
current-airdrop-address (get-in db [:communities community-id :airdrop-address])]
accounts)
current-airdrop-address (get-in db [:communities community-id :airdrop-address])
share-all-addresses? (get-in db [:communities community-id :share-all-addresses?])]
{:db (update-in db
[:communities community-id]
assoc
:previous-share-all-addresses? share-all-addresses?
:previous-permission-addresses selected-permission-addresses
:airdrop-address (if (contains? selected-permission-addresses
current-airdrop-address)
@@ -218,12 +221,32 @@
(rf/reg-event-fx :communities/toggle-selected-permission-address
toggle-selected-permission-address)
(defn toggle-share-all-addresses
[{:keys [db]} [community-id]]
(let [share-all-addresses? (get-in db [:communities community-id :share-all-addresses?])
accounts (utils/sorted-non-watch-only-accounts db)
addresses (set (map :address accounts))]
{:db (update-in db
[:communities community-id]
(fn [community]
(-> community
(assoc :share-all-addresses? (not share-all-addresses?))
(cond-> (not share-all-addresses?)
(assoc :selected-permission-addresses addresses)))))}))
(rf/reg-event-fx :communities/toggle-share-all-addresses
toggle-share-all-addresses)
(rf/reg-event-fx :communities/reset-selected-permission-addresses
(fn [{:keys [db]} [community-id]]
(when community-id
{:db (assoc-in db
[:communities community-id :selected-permission-addresses]
(get-in db [:communities community-id :previous-permission-addresses]))
{:db (update-in db
[:communities community-id]
assoc
:selected-permission-addresses
(get-in db [:communities community-id :previous-permission-addresses])
:share-all-addresses?
(get-in db [:communities community-id :previous-share-all-addresses?]))
:fx [[:dispatch [:communities/check-permissions-to-join-community community-id]]]})))
(rf/reg-event-fx :communities/share-community-channel-url-with-data
@@ -16,6 +16,8 @@
expected-db {:db (update-in (:db initial-db)
[:communities community-id]
assoc
:share-all-addresses? true
:previous-share-all-addresses? true
:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"}
:airdrop-address "0x1")}]
@@ -39,12 +41,16 @@
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"}
:selected-permission-addresses #{"0x1" "0x2"
"0x3"}
:share-all-addresses? true
:previous-share-all-addresses? false
:airdrop-address "0x1"}}}}
expected-db {:db {:wallet wallet
:communities {community-id {:previous-permission-addresses #{"0x1" "0x2"
"0x3"}
:selected-permission-addresses #{"0x1" "0x2"
"0x3"}
:share-all-addresses? true
:previous-share-all-addresses? true
:airdrop-address "0x1"}}}}]
(is
(match? expected-db
@@ -61,6 +67,40 @@
(match? expected-db
(events/update-previous-permission-addresses initial-db [community-id]))))))
(deftest toggle-share-all-addresses-test
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}
:communities {community-id {:share-all-addresses? true
:previous-share-all-addresses? true
:previous-permission-addresses #{"0x1"}
:selected-permission-addresses #{"0x1"}
:airdrop-address "0x1"}}}}
expected-db (update-in initial-db
[:db :communities community-id]
assoc
:previous-share-all-addresses? true
:share-all-addresses?
false)]
(is (match? expected-db (events/toggle-share-all-addresses initial-db [community-id]))))
(let [initial-db {:db {:wallet {:accounts {"0x1" {:address "0x1"
:position 0}
"0x2" {:address "0x2"
:position 1}}}
:communities {community-id {:share-all-addresses? false
:previous-share-all-addresses? false
:previous-permission-addresses #{"0x1"}
:selected-permission-addresses #{"0x1"}
:airdrop-address "0x1"}}}}
expected-db (update-in initial-db
[:db :communities community-id]
assoc
:selected-permission-addresses #{"0x1" "0x2"}
:previous-share-all-addresses? false
:share-all-addresses? true)]
(is (match? expected-db (events/toggle-share-all-addresses initial-db [community-id])))))
(deftest fetch-community
(testing "with community id"
(testing "update fetching indicator in db"
@@ -10,16 +10,16 @@
{:db (-> db
(assoc-in [:community-channels-permissions community-id]
(data-store/rpc->channel-permissions (:channels response)))
(assoc-in [:communities community-id :checking-all-channels-permissions?] false))}))
(assoc-in [:communities/channel-permissions-check community-id] false))}))
(rf/reg-event-fx :communities/check-all-community-channels-permissions-failed
(fn [{:keys [db]} [community-id]]
{:db (assoc-in db [:communities community-id :checking-all-channels-permissions?] false)}))
{:db (assoc-in db [:communities/channel-permissions-check community-id] false)}))
(rf/reg-event-fx :communities/check-all-community-channels-permissions
(fn [{:keys [db]} [community-id]]
(when (get-in db [:communities community-id])
{:db (assoc-in db [:communities community-id :checking-all-channels-permissions?] true)
{:db (assoc-in db [:communities/channel-permissions-check community-id] true)
:fx [[:json-rpc/call
[{:method "wakuext_checkAllCommunityChannelsPermissions"
:params [{:CommunityID community-id}]
@@ -38,21 +38,19 @@
(let [token-permissions-check (cond-> result
based-on-client-selection? (assoc :based-on-client-selection? true))]
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] false)
(assoc-in [:communities community-id :token-permissions-check]
token-permissions-check))})))
(assoc-in [:communities/permissions-check community-id]
{:checking? false
:check token-permissions-check}))})))
(rf/reg-event-fx :communities/check-permissions-to-join-community-failed
(fn [{:keys [db]} [community-id]]
{:db (assoc-in db [:communities community-id :checking-permissions?] false)}))
{:db (assoc-in db [:communities/permissions-check community-id :checking?] false)}))
(rf/reg-event-fx :communities/check-permissions-to-join-community
(fn [{:keys [db]} [community-id addresses based-on-client-selection?]]
(when-let [community (get-in db [:communities community-id])]
(when-not (:checking-permissions? community)
{:db (-> db
(assoc-in [:communities community-id :checking-permissions?] true)
(assoc-in [:communities community-id :can-request-access?] false))
{:db (assoc-in db [:communities/permissions-check community-id :checking?] true)
:json-rpc/call [{:method "wakuext_checkPermissionsToJoinCommunity"
:params [(cond-> {:communityId community-id}
addresses
@@ -110,66 +110,82 @@
[rn/view
[quo/icon :i/info {:no-color true}]]])
(defn- network-not-supported
[]
[quo/text (i18n/label :t/network-not-supported)])
(defn- request-access-button
[id color]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :show-request-to-join-screen-button
:customization-color color
:icon-left :i/communities}
(i18n/label :t/request-to-join)])
(defn- token-requirements
[{:keys [id color]}]
[{:keys [id color role-permissions?]}]
(let [{:keys [can-request-access?
number-of-hold-tokens tokens
no-member-permission?
tokens
networks-not-supported?
highest-permission-role]} (rf/sub [:community/token-gated-overview id])
highest-role-text
(i18n/label
(communities.utils/role->translation-key highest-permission-role :t/member))]
[rn/view {:style (style/token-gated-container)}
[rn/view
{:style {:padding-horizontal 12
:flex-direction :row
:align-items :center
:justify-content :space-between
:flex 1}}
[quo/text {:weight :medium}
(if can-request-access?
(i18n/label :t/you-eligible-to-join-as {:role highest-role-text})
(i18n/label :t/you-not-eligible-to-join))]
[info-button]]
(when (pos? number-of-hold-tokens)
(cond
networks-not-supported?
[network-not-supported]
(or (not role-permissions?) no-member-permission?)
[request-access-button id color]
:else
[rn/view {:style (style/token-gated-container)}
[rn/view
{:style {:padding-horizontal 12
:flex-direction :row
:align-items :center
:justify-content :space-between
:flex 1}}
[quo/text {:weight :medium}
(if (and can-request-access? highest-permission-role)
(i18n/label :t/you-eligible-to-join-as {:role highest-role-text})
(i18n/label :t/you-not-eligible-to-join))]
[info-button]]
[quo/text {:style {:padding-horizontal 12 :padding-bottom 18} :size :paragraph-2}
(if can-request-access?
(i18n/label :t/you-hold-number-of-hold-tokens-of-these
{:number-of-hold-tokens number-of-hold-tokens})
(i18n/label :t/you-must-hold))])
[quo/token-requirement-list
{:tokens tokens
:padding? true}]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :join-community-button
:customization-color color
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
:disabled? (not can-request-access?)
:icon-left (if can-request-access? :i/unlocked :i/locked)}
(i18n/label :t/join-open-community)]]))
(i18n/label :t/you-hodl)
(i18n/label :t/you-must-hold))]
[quo/token-requirement-list
{:tokens tokens
:padding? true}]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :join-community-button
:customization-color color
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
:disabled? (not can-request-access?)
:icon-left (if can-request-access? :i/unlocked :i/locked)}
(i18n/label :t/join-open-community)]])))
(defn- join-community
[{:keys [id color joined permissions role-permissions? can-join?] :as community}]
[{:keys [id joined permissions role-permissions? can-join?] :as community}]
(let [pending? (rf/sub [:communities/my-pending-request-to-join id])
access-type (get-access-type (:access permissions))
unknown-access? (= access-type :unknown-access)
invite-only? (= access-type :invite-only)]
[:<>
(when-not (or joined pending? invite-only? unknown-access?)
(if role-permissions?
[token-requirements community]
[quo/button
{:on-press (if config/community-accounts-selection-enabled?
#(rf/dispatch [:open-modal :community-account-selection
{:community-id id}])
#(rf/dispatch [:open-modal :community-requests-to-join {:id id}]))
:accessibility-label :show-request-to-join-screen-button
:customization-color color
:icon-left :i/communities}
(i18n/label :t/request-to-join)]))
[token-requirements community])
(when (not (or pending? role-permissions? can-join?))
[quo/text
{:size :paragraph-2
@@ -237,15 +253,17 @@
:description-accessibility-label :community-description}])
(defn- community-content
[{:keys [id]}]
[id]
(rf/dispatch [:communities/check-all-community-channels-permissions id])
(fn [{:keys [name description joined spectated images tags color id membership-permissions?]
:as community}
(fn [id
{:keys [on-category-layout
collapsed?
on-first-channel-height-changed]}]
(let [joined-or-spectated (or joined spectated)
chats-by-category (rf/sub [:communities/categorized-channels id])]
(let [{:keys [name description joined spectated images tags color id membership-permissions?]
:as community}
(rf/sub [:communities/community id])
joined-or-spectated (or joined spectated)
chats-by-category (rf/sub [:communities/categorized-channels id])]
[:<>
[rn/view {:style style/community-content-container}
(when-not collapsed?
@@ -295,20 +313,24 @@
(and (>= scroll-height (+ height first-channel-height))
category)))))
(defn- community-scroll-page
[{:keys [joined]}]
(let [scroll-height (reagent/atom 0)
categories-heights (reagent/atom {})
first-channel-height (reagent/atom 0)
;; We track the initial value of joined
;; as we open the page to avoid switching
;; from not collapsed to collapsed if the
;; user is on this page
initial-joined? joined]
(fn [{:keys [id name images] :as community}]
(defn- community-scroll-page
[_ initial-joined? _ _]
(let [scroll-height (reagent/atom 0)
categories-heights (reagent/atom {})
first-channel-height (reagent/atom 0)
on-category-layout (partial add-category-height categories-heights)
on-first-channel-height-changed (fn [height categories]
(swap! categories-heights select-keys categories)
(reset! first-channel-height height))]
(fn [id joined name images]
(let [cover {:uri (get-in images [:banner :uri])}
logo {:uri (get-in images [:thumbnail :uri])}
collapsed? (and initial-joined? (:joined community))
collapsed? (and initial-joined? joined)
overlay-shown? (boolean (:sheets (rf/sub [:bottom-sheet])))]
[scroll-page/scroll-page
{:cover-image cover
@@ -331,24 +353,22 @@
@first-channel-height
@categories-heights)}]}
[community-content
community
{:on-category-layout (partial add-category-height categories-heights)
id
{:on-category-layout on-category-layout
:collapsed? collapsed?
:on-first-channel-height-changed
;; Here we set the height of the component and we filter out the categories, as some
;; might have been removed.
(fn [height categories]
(swap! categories-heights select-keys categories)
(reset! first-channel-height height))}]]))))
on-first-channel-height-changed}]]))))
(defn- community-card-page-view
[id]
(let [{:keys [id joined]
(let [{:keys [id joined name images]
:as community} (rf/sub [:communities/community id])]
(when community
(when joined
(rf/dispatch [:activity-center.notifications/dismiss-community-overview id]))
[community-scroll-page community])))
[community-scroll-page id joined name images])))
(defn view
[id]
@@ -11,3 +11,10 @@
constants/community-token-permission-become-admin :t/admin
constants/community-token-permission-become-member :t/member
fallback-to)))
(defn sorted-non-watch-only-accounts
[db]
(->> (get-in db [:wallet :accounts])
(vals)
(remove :watch-only?)
(sort-by :position)))
@@ -8,30 +8,8 @@
(def heading-subtitle {:color colors/white})
(def heading-title (assoc heading-subtitle :margin-bottom 8))
(def label-container
{:margin-top 8
:flex-direction :row
:align-items :center
:height 16})
(def label-icon
{:width 16
:height 18
:margin-right 4})
(defn label-icon-color
[status]
(get {:neutral colors/neutral-40
:success colors/success-60
:danger colors/danger-60}
status))
(defn label-color
[status]
(let [colors {:neutral colors/white-opa-70
:success colors/success-60
:danger colors/danger-60}]
{:color (get colors status)}))
(def info-message
{:margin-top 8})
(def space-between-inputs {:height 16})
@@ -2,6 +2,7 @@
(:require
[oops.core :refer [ocall]]
[quo.core :as quo]
[quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
@@ -33,24 +34,25 @@
(dissoc :hint)
(assoc :type :password
:blur? true))]
[rn/view {:style style/label-container}
[rn/view {:style style/info-message}
(when shown
[:<>
[quo/icon (if (= status :success) :i/check-circle :i/info)
{:container-style style/label-icon
:color (style/label-icon-color status)
:size 16}]
[quo/text
{:style (style/label-color status)
:size :paragraph-2}
text]])]])
[quo/info-message
{:type status
:size :default
:icon (if (= status :success) :i/positive-state :i/info)
:text-color (when (= status :default)
colors/white-70-blur)
:icon-color (when (= status :default)
colors/white-70-blur)
:style {}}
text])]])
(defn password-inputs
[{:keys [passwords-match? on-change-password on-change-repeat-password on-input-focus
password-long-enough? empty-password? show-password-validation?
on-blur-repeat-password]}]
(let [hint-1-status (if password-long-enough? :success :neutral)
hint-2-status (if passwords-match? :success :danger)
(let [hint-1-status (if password-long-enough? :success :default)
hint-2-status (if passwords-match? :success :error)
hint-2-text (if passwords-match?
(i18n/label :t/password-creation-match)
(i18n/label :t/password-creation-dont-match))
@@ -1,6 +1,5 @@
(ns status-im.contexts.preview.quo.tags.collectible-tag
(:require
[oops.core :refer [oget]]
[quo.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
@@ -16,9 +15,7 @@
:value "Size 32"}]}
{:key :options
:type :select
:options [{:key false
:value false}
{:key :add
:options [{:key :add
:value :add}
{:key :hold
:value :hold}]}
@@ -31,16 +28,11 @@
(defn view
[]
(let [state (reagent/atom {:size :size-24
:collectible-name "Collectible"
:collectible-id "#123"
:collectible-img-src (resources/mock-images :collectible)
:options false
:blur? false
:container-width 0})
on-layout #(swap! state assoc
:container-width
(oget % :nativeEvent :layout :width))]
(let [state (reagent/atom {:size :size-24
:collectible-name "Collectible"
:collectible-id "#123"
:collectible-img-src (resources/mock-images :collectible)
:blur? false})]
(fn []
[preview/preview-container
{:state state
@@ -48,4 +40,4 @@
:show-blur-background? true
:descriptor descriptor}
[rn/view {:style {:align-items :center}}
[quo/collectible-tag (assoc @state :on-layout on-layout)]]])))
[quo/collectible-tag @state]]])))
@@ -24,7 +24,8 @@
{:key :empty-token-list}
{:key :1-token}
{:key :3-tokens}
{:key :5-tokens}]}])
{:key :5-tokens}]}
(preview/customization-color-option {:key :customization-color})])
(def ^:private token-details
{:no-tokens nil
@@ -50,23 +51,25 @@
(defn view
[]
(let [state (reagent/atom {:name "Trip to Vegas"
:address "0x2f0fbf0a93c5999e9b4410848403a02b38983eb2"
:emoji "😊"
:account-color :blue
:token-details :no-tokens
:keycard? true
:checked? true
:disabled? false})]
(let [state (reagent/atom {:name "Trip to Vegas"
:address "0x2f0fbf0a93c5999e9b4410848403a02b38983eb2"
:emoji "😊"
:account-color :blue
:token-details :no-tokens
:customization-color :blue
:keycard? true
:checked? true
:disabled? false})]
(fn []
[preview/preview-container {:state state :descriptor descriptor}
[quo/account-permissions
{:account {:name (:name @state)
:address (:address @state)
:emoji (:emoji @state)
:customization-color (:account-color @state)}
:token-details (token-details (:token-details @state))
:keycard? (:keycard? @state)
:checked? (:checked? @state)
:disabled? (:disabled? @state)
:on-change (fn [checked?] (swap! state assoc :checked? checked?))}]])))
{:account {:name (:name @state)
:address (:address @state)
:emoji (:emoji @state)
:customization-color (:account-color @state)}
:token-details (token-details (:token-details @state))
:keycard? (:keycard? @state)
:checked? (:checked? @state)
:disabled? (:disabled? @state)
:customization-color (:customization-color @state)
:on-change (fn [checked?] (swap! state assoc :checked? checked?))}]])))
@@ -69,7 +69,7 @@
(stop-interval)))
[(:state @state)])
[preview/preview-container {:state state :descriptor descriptor}
[quo/confirmation-propgress
[quo/confirmation-progress
(assoc @state
:counter
@counter)]]))
+1 -1
View File
@@ -43,7 +43,7 @@
:upstreamConfig config/default-network-rpc-url
:networkId config/default-network-id
:currentNetwork config/default-network
:wakuV2LightClient true
:wakuV2LightClient false
:previewPrivacy config/blank-preview?})))
(defn strip-file-prefix
@@ -0,0 +1,22 @@
(ns status-im.contexts.profile.edit.bio.events
(:require [utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :profile/edit-profile-bio-success
(fn [_]
{:fx [[:dispatch [:navigate-back]]
[:dispatch
[:toasts/upsert
{:type :positive
:theme :dark
:text (i18n/label :t/bio-added)}]]]}))
(defn edit-profile-bio
[{:keys [db]} [bio]]
{:db (assoc-in db [:profile/profile :bio] bio)
:fx [[:json-rpc/call
[{:method "wakuext_setBio"
:params [bio]
:on-success [:profile/edit-profile-bio-success]}]]]})
(rf/reg-event-fx :profile/edit-bio edit-profile-bio)
@@ -0,0 +1,15 @@
(ns status-im.contexts.profile.edit.bio.events-test
(:require [cljs.test :refer [deftest is]]
matcher-combinators.test
[status-im.contexts.profile.edit.bio.events :as sut]))
(deftest edit-bio-test
(let [new-bio "New Bio text"
cofx {:db {:profile/profile {:bio "Old Bio text"}}}
expected {:db {:profile/profile {:bio new-bio}}
:fx [[:json-rpc/call
[{:method "wakuext_setBio"
:params [new-bio]
:on-success [:profile/edit-profile-bio-success]}]]]}]
(is (match? expected
(sut/edit-profile-bio cofx [new-bio])))))
@@ -0,0 +1,17 @@
(ns status-im.contexts.profile.edit.bio.style)
(defn page-wrapper
[insets]
{:padding-top (:top insets)
:padding-bottom (:bottom insets)
:padding-horizontal 1
:flex 1})
(def screen-container
{:flex 1
:padding-top 14
:padding-horizontal 20
:justify-content :space-between})
(def button-wrapper
{:margin-vertical 12})
@@ -0,0 +1,71 @@
(ns status-im.contexts.profile.edit.bio.view
(:require [clojure.string :as string]
[quo.core :as quo]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.common.validation.profile :as profile-validator]
[status-im.constants :as constants]
[status-im.contexts.profile.edit.bio.style :as style]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [insets (safe-area/get-insets)
profile (rf/sub [:profile/profile-with-image])
customization-color (rf/sub [:profile/customization-color])
profile-bio (:bio profile)
unsaved-bio (reagent/atom profile-bio)
error-msg (reagent/atom nil)
typing? (reagent/atom false)
validate-bio (debounce/debounce (fn [bio]
(reset! error-msg
(profile-validator/validation-bio bio))
(reset! typing? false))
300)
on-change-text (fn [s]
(reset! typing? true)
(reset! unsaved-bio s)
(validate-bio s))]
(fn []
[quo/overlay
{:type :shell
:container-style (style/page-wrapper insets)}
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])}]
[rn/keyboard-avoiding-view
{:key :content
:style style/screen-container}
[rn/view {:style {:gap 22}}
[quo/text-combinations {:title (i18n/label :t/bio)}]
[quo/input
{:theme :dark
:blur? true
:multiline? true
:error? (not (string/blank? @error-msg))
:container-style {:margin-bottom -11}
:default-value @unsaved-bio
:auto-focus true
:char-limit constants/profile-bio-max-length
:label (i18n/label :t/profile-bio)
:placeholder (i18n/label :t/something-about-you)
:on-change-text on-change-text}]
(when-not (string/blank? @error-msg)
[quo/info-message
{:type :error
:size :default
:icon :i/info}
@error-msg])]
[rn/view {:style style/button-wrapper}
[quo/button
{:type :primary
:customization-color customization-color
:on-press (fn []
(rf/dispatch [:profile/edit-bio @unsaved-bio]))
:disabled? (boolean (or @typing? (not (string/blank? @error-msg))))}
(i18n/label :t/save-bio)]]]])))
@@ -1,5 +1,6 @@
(ns status-im.contexts.profile.edit.list-items
(:require [quo.foundations.colors :as colors]
(:require [legacy.status-im.utils.core :as utils]
[quo.foundations.colors :as colors]
[status-im.common.not-implemented :as not-implemented]
[status-im.contexts.profile.edit.style :as style]
[status-im.contexts.profile.utils :as profile.utils]
@@ -10,6 +11,7 @@
[theme]
(let [profile (rf/sub [:profile/profile-with-image])
customization-color (rf/sub [:profile/customization-color])
bio (:bio profile)
full-name (profile.utils/displayed-name profile)]
[{:label (i18n/label :t/profile)
:items [{:title (i18n/label :t/name)
@@ -20,8 +22,10 @@
:action :arrow
:container-style style/item-container}
{:title (i18n/label :t/bio)
:on-press not-implemented/alert
:on-press #(rf/dispatch [:open-modal :edit-bio])
:blur? true
:label :text
:label-props (utils/truncate-str bio 15)
:action :arrow
:container-style style/item-container}
{:title (i18n/label :t/accent-colour)
@@ -4,6 +4,7 @@
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[status-im.contexts.profile.edit.accent-colour.events]
[status-im.contexts.profile.edit.bio.events]
[status-im.contexts.profile.edit.header.events]
[status-im.contexts.profile.edit.name.events]
[status-im.contexts.profile.login.events :as profile.login]
@@ -1,36 +1,34 @@
(ns ^:workletize status-im.contexts.profile.settings.header.avatar
(ns status-im.contexts.profile.settings.header.avatar
(:require [quo.core :as quo]
[quo.theme :as quo.theme]
[react-native.reanimated :as reanimated]
[status-im.contexts.profile.settings.header.style :as style]))
(def scroll-animation-input-range [0 50])
(def header-extrapolation-option
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})
(defn f-avatar
[{:keys [scroll-y full-name online? profile-picture customization-color]}]
(let [avatar-total-size 88
border-height 4
translation-to-bottom (fn [scale inverse-scale]
(js* "'worklet'")
(let [current-avatar-size (* avatar-total-size (- 1 scale))
current-center (/ current-avatar-size 2)]
(* current-center inverse-scale)))
transform (reanimated/use-animated-style
(fn []
(js* "'worklet'")
(let [scale (reanimated/interpolate*
(.-value scroll-y)
#js [0 48]
#js [1 0.4]
"clamp")
inverse-scale (/ 1 scale)
translation (translation-to-bottom scale inverse-scale)
bottom (* border-height inverse-scale (- 1 scale))]
#js
{:transform #js
[#js {:scale scale}
#js {:translateX (- translation)}
#js {:translateY (- translation bottom)}]})))
theme (quo.theme/get-theme)]
[reanimated/view {:style [transform (style/avatar-container theme)]}
(let [image-scale-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[1 0.4]
header-extrapolation-option)
image-top-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[0 20]
header-extrapolation-option)
image-side-margin-animation (reanimated/interpolate scroll-y
scroll-animation-input-range
[0 -20]
header-extrapolation-option)
theme (quo.theme/get-theme)]
[reanimated/view
{:style (style/avatar-container theme
image-scale-animation
image-top-margin-animation
image-side-margin-animation)}
[quo/user-avatar
{:full-name full-name
:online? online?
@@ -1,11 +1,10 @@
(ns ^:workletize status-im.contexts.profile.settings.header.header-shape
(ns status-im.contexts.profile.settings.header.header-shape
(:require [quo.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[react-native.svg :as svg]
[status-im.contexts.profile.settings.header.style :as style]))
(defn left-radius
[background-color]
[svg/svg {:width "20" :height "20" :viewBox "0 0 20 20" :fill "none"}
@@ -22,17 +21,13 @@
(defn f-view
[{:keys [scroll-y customization-color theme]}]
(let [background-color (colors/resolve-color customization-color theme 40)
opacity (reanimated/use-animated-style
(fn []
(js* "'worklet'")
#js
{:opacity (reanimated/interpolate* (.-value scroll-y)
#js [0 45 50]
#js [1 1 0])}))]
(let [background-color (colors/resolve-color customization-color theme 40)
opacity-animation (reanimated/interpolate scroll-y
[0 45 50]
[1 1 0])]
[:<>
[rn/view {:style (style/header-middle-shape background-color)}]
[reanimated/view {:style [opacity style/radius-container]}
[reanimated/view {:style (style/radius-container opacity-animation)}
[left-radius background-color]
[right-radius background-color]]]))
@@ -27,13 +27,19 @@
:height 48
:flex-grow 1})
(def radius-container
{:flex-direction :row
(defn radius-container
[opacity-animation]
{:opacity opacity-animation
:flex-direction :row
:justify-content :space-between})
(defn avatar-container
[theme]
{:align-items :flex-start
:border-width 4
:border-color (colors/theme-colors colors/border-avatar-light colors/neutral-80-opa-80 theme)
:border-radius 44})
[theme scale-animation top-margin-animation side-margin-animation]
[{:transform [{:scale scale-animation}]
:margin-top top-margin-animation
:margin-left side-margin-animation
:margin-bottom side-margin-animation}
{:align-items :flex-start
:border-width 4
:border-color (colors/theme-colors colors/border-avatar-light colors/neutral-80-opa-80 theme)
:border-radius 100}])
@@ -20,6 +20,7 @@
[:visibility-status-updates/visibility-status-update
public-key])
customization-color (rf/sub [:profile/customization-color])
bio (:bio profile)
full-name (profile.utils/displayed-name profile)
profile-picture (profile.utils/photo profile)
emoji-string (string/join emoji-hash)
@@ -53,6 +54,7 @@
{:title-accessibility-label :username
:container-style style/title-container
:emoji-hash emoji-string
:description bio
:title full-name}]]))
(def view (quo.theme/with-theme f-view))
@@ -40,9 +40,10 @@
:size 32
:accessibility-label :activity-center-open-more
:on-press #(rf/dispatch [:show-bottom-sheet
{:content drawer/options
:theme :dark
:shell? true}])}
{:content drawer/options
:theme :dark
:shell? true
:blur-radius 20}])}
:i/options]]
[quo/text
{:size :heading-1
@@ -0,0 +1,126 @@
(ns status-im.contexts.shell.qr-reader.view
(:require
[clojure.string :as string]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[status-im.common.router :as router]
[status-im.common.scan-qr-code.view :as scan-qr-code]
[status-im.common.validators :as validators]
[status-im.contexts.communities.events]
[status-im.contexts.wallet.common.validation :as wallet-validation]
[utils.debounce :as debounce]
[utils.ethereum.eip.eip681 :as eip681]
[utils.i18n :as i18n]
[utils.url :as url]))
(def invalid-qr-toast
{:type :negative
:theme :dark
:text (i18n/label :t/invalid-qr)})
(defn- text-for-url-path?
[text path]
(some #(string/starts-with? text %) (router/path-urls path)))
(defn- extract-id
[scanned-text]
(let [index (string/index-of scanned-text "#")]
(subs scanned-text (inc index))))
(defn eth-address?
[scanned-text]
(wallet-validation/eth-address? scanned-text))
(defn eip681-address?
[scanned-text]
(-> scanned-text
eip681/parse-uri
:address
boolean))
(defn pairing-qr-code?
[_]
false)
(defn wallet-connect-code?
[scanned-text]
(string/starts-with? scanned-text "wc:"))
(defn url?
[scanned-text]
(url/url? scanned-text))
(defn load-and-show-profile
[address]
(debounce/debounce-and-dispatch
[:contacts/set-new-identity
{:input address
:build-success-fn (fn [{:keys [public-key ens-name]}]
{:dispatch-n [[:chat.ui/show-profile public-key ens-name]
[:contacts/clear-new-identity]]})
:failure-fn (fn []
{:dispatch [:toasts/upsert invalid-qr-toast]})}]
300))
(defn show-invalid-qr-toast
[]
(debounce/debounce-and-dispatch
[:toasts/upsert invalid-qr-toast]
300))
(defn on-qr-code-scanned
[scanned-text]
(cond
(text-for-url-path? scanned-text router/community-with-data-path)
;; TODO: https://github.com/status-im/status-mobile/issues/18743
nil
(text-for-url-path? scanned-text router/channel-path)
;; TODO: https://github.com/status-im/status-mobile/issues/18743
nil
(text-for-url-path? scanned-text router/user-with-data-path)
(let [address (extract-id scanned-text)]
(load-and-show-profile address))
(or (validators/valid-public-key? scanned-text)
(validators/valid-compressed-key? scanned-text))
(load-and-show-profile scanned-text)
(eth-address? scanned-text)
(debounce/debounce-and-dispatch [:navigate-to :wallet-accounts scanned-text] 300)
(eip681-address? scanned-text)
(do
(debounce/debounce-and-dispatch [:wallet-legacy/request-uri-parsed
(eip681/parse-uri scanned-text)]
300)
(debounce/debounce-and-dispatch [:navigate-change-tab :wallet-stack] 300))
(pairing-qr-code? scanned-text)
;; TODO: https://github.com/status-im/status-mobile/issues/18744
nil
(wallet-connect-code? scanned-text)
;; WalletConnect is not working yet, this flow should be updated once WalletConnect is ready
nil
(url? scanned-text)
(debounce/debounce-and-dispatch [:browser.ui/open-url scanned-text] 300)
:else
(show-invalid-qr-toast)))
(defn- f-internal-view
[]
(let [{:keys [keyboard-shown]} (hooks/use-keyboard)]
[:<>
(when keyboard-shown
(rn/dismiss-keyboard!))
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:on-success-scan on-qr-code-scanned}]]))
(defn view
[]
[:f> f-internal-view])
+3 -1
View File
@@ -29,7 +29,9 @@
:background :blur
:size 32
:accessibility-label :shell-scan-button
:on-press #(rf/dispatch [:navigate-back])}
:on-press (fn []
(rf/dispatch [:navigate-back])
(rf/dispatch [:open-modal :shell-qr-reader]))}
:i/scan]]
[quo/text
{:size :heading-1
@@ -31,4 +31,3 @@
(rf/dispatch [:wallet/bridge-select-token
{:token token
:stack-id :wallet-bridge}]))}]])))
@@ -0,0 +1,4 @@
(ns status-im.contexts.wallet.account.bridge-send.style)
(def bridge-send-wrapper
{:flex 1})
@@ -0,0 +1,19 @@
(ns status-im.contexts.wallet.account.bridge-send.view
(:require
[quo.theme]
[react-native.core :as rn]
[status-im.contexts.wallet.account.bridge-send.style :as style]
[status-im.contexts.wallet.send.input-amount.view :as input-amount]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- view-internal
[]
[rn/view {:style style/bridge-send-wrapper}
[input-amount/view
{:button-one-label (i18n/label :t/confirm-bridge)
:button-one-props {:icon-left :i/bridge}
:on-navigate-back (fn []
(rf/dispatch [:navigate-back-within-stack :wallet-bridge-send]))}]])
(def view (quo.theme/with-theme view-internal))
@@ -28,7 +28,10 @@
{:label (name network-name)
:network-image (quo.resources/get-network (:network-name network))
:token-value (str crypto-formatted " " (:symbol token))
:fiat-value fiat-formatted}])))
:fiat-value fiat-formatted
:on-press #(rf/dispatch [:wallet/select-bridge-network
{:network-chain-id chain-id
:stack-id :wallet-bridge}])}])))
(defn- view-internal
[]
@@ -50,7 +53,7 @@
:accessibility-label :top-bar}]
[quo/text-combinations
{:container-style style/header-container
:title (i18n/label :t/bridge-to {:name (string/upper-case (str (:label token)))})}]
:title (i18n/label :t/bridge-to {:name (string/upper-case (str (:name token)))})}]
[rn/view style/content-container
[bridge-token-component (assoc mainnet :network-name :t/mainnet) account-token]]
@@ -38,7 +38,9 @@
(let [{:keys [name color formatted-balance
watch-only?]} (rf/sub [:wallet/current-viewing-account])]
[rn/view {:style {:flex 1}}
[account-switcher/view {:on-press #(rf/dispatch [:wallet/close-account-page])}]
[account-switcher/view
{:type :wallet-networks
:on-press #(rf/dispatch [:wallet/close-account-page])}]
[quo/account-overview
{:current-value formatted-balance
:account-name name
@@ -54,7 +56,7 @@
:buy-action #(rf/dispatch [:show-bottom-sheet
{:content buy-drawer}])
:bridge-action #(ff/alert ::ff/wallet.bridge-token
(fn [] (rf/dispatch [:open-modal :wallet-bridge])))}])
(fn [] (rf/dispatch [:wallet/start-bridge])))}])
[quo/tabs
{:style style/tabs
:size 32
@@ -1,20 +1,14 @@
(ns status-im.contexts.wallet.add-address-to-watch.confirm-address.component-spec
(:require
[status-im.contexts.wallet.add-address-to-watch.confirm-address.view :as confirm-address]
[test-helpers.component :as h]
[utils.re-frame :as rf]))
[test-helpers.component :as h]))
(h/describe "Add Watch Only Account Page"
(h/setup-restorable-re-frame)
(h/test "Create Account button is disabled while no account name exists"
(let [callback (h/mock-fn)]
(with-redefs [rf/dispatch #(callback)]
(h/setup-subs {:profile/wallet-accounts []
:get-screen-params {:address "0xmock-address"}})
(h/render [confirm-address/view {}])
(h/is-truthy (h/get-by-text "0xmock-address"))
(h/was-not-called callback)
(h/fire-event :change-text (h/get-by-label-text :profile-title-input) "NAME")
(h/fire-event :press (h/get-by-translation-text :t/add-watched-address))
(h/was-called callback)))))
(h/setup-subs {:wallet/watch-only-accounts []
:get-screen-params {:address "0xmock-address"}})
(h/render [confirm-address/view])
(h/is-truthy (h/get-by-text "0xmock-address"))
(h/is-disabled (h/get-by-label-text :confirm-button-label))))

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