Compare commits

...
Author SHA1 Message Date
Omar Basem 85d9909084 updates 2023-07-04 11:27:11 +04:00
Omar Basem 21ce4aabd8 updates 2023-07-04 11:24:34 +04:00
Omar Basem b9247cb517 updates 2023-07-04 11:15:32 +04:00
Omar Basem 24b8349b95 updates 2023-07-04 11:01:03 +04:00
Omar Basem e9adebc3fb updates 2023-07-04 10:47:31 +04:00
Omar Basem 531e63e2ea updates 2023-07-04 10:33:25 +04:00
Omar Basem 47b5470a91 updates 2023-07-04 10:23:21 +04:00
Omar Basem 3b0a7911e3 updates 2023-07-04 09:45:02 +04:00
Omar Basem bf7d36b899 updates 2023-07-04 09:19:57 +04:00
Omar Basem b9ba4fdf42 updates 2023-07-04 09:10:29 +04:00
Omar Basem b16c45f2fc updates 2023-07-04 08:56:57 +04:00
Omar Basem 0255eb051e fix 2023-07-03 18:59:25 +04:00
Omar Basem 1fd1d0ee79 feat: lightbox text 2023-07-03 17:21:01 +04:00
Omar Basem 2cc844111c feat: lightbox text 2023-07-03 16:08:41 +04:00
Omar Basem 75926edb81 feat: lightbox text 2023-07-03 11:22:44 +04:00
Anton Iakimov a6e6716311 ci: add shebang to jenkinsfiles 2023-07-02 09:11:54 +02:00
Anton Iakimov 07d037f2e1 nix: downgrade watchman to 4.9.0
watchman was upgraded significantly during the last #14944 (4.9.0 (Aug 16, 2017) to 2023.01.30.00 - 6 years between):
status-im/nixpkgs@4e9c02b

Probably causing developers to have "too many files open" issue #16341

This PR is an attempt to fix the issue by downgrading the watchman

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-07-02 08:46:28 +02:00
Andrea Maria Piana 36a72f2d63 Set nameserver on login 2023-07-01 08:39:12 +01:00
Jamie Caprani 4c0a8d9f6d chore: use with theme for step component (#16399) 2023-06-30 09:02:46 -07:00
Brian Sztamfater 2d860c363a feat: allow navigation inside different stacks (#16419)
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-06-30 11:48:35 -03:00
Icaro Motta 186ac482ee Comment time bomb test out (#16452) 2023-06-30 12:47:24 +00:00
Andrea Maria Piana f015eb929a [Fixes: #16203] Fix delete for me replies images
https://github.com/status-im/status-go/compare/09c5223d...b058ab41
2023-06-30 11:14:49 +01:00
Volodymyr Kozieiev bca7ab7925 Use only counter (no unread indicator) for chats bottom bar tab (#16417) 2023-06-29 16:42:08 +01:00
Yevheniia Berdnyk 5f441dfa93 e2e: Reactions in 1-1 chats 2023-06-29 17:49:15 +03:00
Parvesh Monu 5d0aa6a2f7 fix App crashes when jump-to has group chat card (#16431) 2023-06-29 18:10:58 +05:30
flexsurfer d9f7510d13 key-storage cleanup (#16427) 2023-06-29 14:29:39 +02:00
Roman Volosovskyi b953ddb5af [#15944] Set installation name on account creation 2023-06-29 14:06:23 +02:00
Tetiana Churikova 3058ebe018 e2e: small adjustments (#16439) 2023-06-29 14:05:13 +02:00
frank a7ddda40c4 fix: ROW_NUMBER() not work on ios for some reason (#16426)
* fix: ROW_NUMBER() not work on ios for some reason

* update status-go-version.json

* update status-go-version.json

* update status-go-version.json
2023-06-29 19:11:15 +08:00
Tetiana Churikova ba8c08650b e2e: updated wait_to (#16416) 2023-06-28 14:27:57 +02:00
flexsurfer c5a7bf39d7 multiaccounts refactoring part1 (#16414) 2023-06-28 13:48:34 +02:00
Ibrahem Khalil e0a0c6331f [16352] [Bugfix] New message indicator not showing on bottom navigation for unmuted chats and another bug (#16380) 2023-06-27 19:44:28 +04:00
Parvesh Monu b5a96a254a Implement Swipe navigation for floating screen (#16390) 2023-06-27 21:02:54 +05:30
Rahul Pratap 6b0a51720e Update animation for onboarding carousel. (#16294)
* Update animation for onboarding carousel.

* Fixed issues with long press while swipe.

* Fixed issues after generating keys.
2023-06-27 20:45:13 +05:30
Jamie Caprani e0e693791f chore: small refactor to remove some uses of status-im in status-im2 (#16358) 2023-06-27 07:11:07 -07:00
watson cebc50d409 Adjust identifiers page to do highlighting (#15752) 2023-06-27 14:45:10 +01:00
jakub 1503f6b250 nix: use Darwin stat command explicitly
Otherwise if in Nix context we can accidentally use GNU stat which
results in a different output due to different command line flags:
```
[nix-shell:~/status-mobile]$ stat -Lf "%Sg" "/nix/store"
stat: cannot read file system information for '%Sg': No such file or directory
  File: "/nix/store"
    ID: 10000110000001a Namelen: ?       Type: apfs
Block size: 4096       Fundamental block size: 4096
Blocks: Total: 242837545  Free: 199242283  Available: 199242283
Inodes: Total: 7971454780 Free: 7969691320
```
And it should be just owner group name or ID. Which in turn results in:
```
Unknown Nix installtion type!
```

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-06-27 13:25:41 +02:00
Jamie Caprani 46182ad308 chore: move activity centre and share into shell namespace (#16395) 2023-06-27 03:48:23 -07:00
Jamie Caprani fa698dbc30 feat: add parallax to biometrics page for whitelisted devices (#16296) 2023-06-27 02:50:27 -07:00
Ibrahem Khalil 79151ee85d Disable image description in lightbox (#16405) 2023-06-27 12:15:04 +03:00
Ibrahem Khalil 4c8671caa0 [15902] BUGFIX - Resolve public keys into the user's name in the confirmation drawer and image description (#16176) 2023-06-27 10:42:01 +03:00
Omar Basem 86219dbad8 feat: save image (#16268)
* feat: save image
2023-06-27 11:03:29 +04:00
Yevheniia Berdnyk cd32806c96 e2e: Updated error message in 702783 2023-06-27 02:52:28 +03:00
frank ab16ca34dd improve: enable collect logs before login (#16392) 2023-06-27 07:42:53 +08:00
Ulises Manuel Cárdenas e2b7a299b4 [#16322] Add carousel tap gesture
* Add tap gesture to carousel

* Updates uses of carousel

* Gestures only detected on carousel content instead of full screen on Android
2023-06-26 14:19:09 -06:00
Anton Iakimov 5dcd64c478 nix: fix Android SDK on Darwin with nixpkgs system override
Android SDK in nixpkg doesn't support `aarch64-darwin`, for details see
https://github.com/status-im/status-mobile/issues/12794

The workaround was to run terminal application with Rosetta or make with `aarch` tool.

This PR overrides system architecture to always be `x86_64` for Android shell and build targets ran by make.
CI is not affected as it runs `nix` directly.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-06-26 17:33:44 +02:00
Brian Sztamfater 6d6e6b1eff fix: calibrate duration of recorded audio (#15543)
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-06-26 11:02:13 -03:00
Brian Sztamfater 60a8b944d9 fix: send user to settings if audio permission is rejected (#16049) 2023-06-26 10:35:13 -03:00
Brian Sztamfater 437cfa9a77 feat: add blur effect on scroll for buttons inside gallery view (#16319)
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-06-26 10:19:54 -03:00
Andrea Maria Piana 36aefd0e5a Fix race condition on sending messages
https://github.com/status-im/status-go/compare/d3e650d5...f23cb406
2023-06-26 13:37:20 +01:00
Mohamed Javid ce82e87cd0 Update broken Status development link in ide-setup.md (#16391)
This commit updates the broken link of `Status development` in the `Start and connect the REPL` section of `ide-setup.md`.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2023-06-26 16:43:58 +05:30
Parvesh Monu 8f21cecf81 fix deleted message remains in preview at Jump to section (#16385) 2023-06-26 16:19:32 +05:30
Parvesh Monu 4a4974b541 Animate floating screen border radius (#16384) 2023-06-26 15:59:43 +05:30
276 changed files with 2891 additions and 2226 deletions
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
/* Options section can't access functions in objects. */
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
/* Options section can't access functions in objects. */
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
/* Options section can't access functions in objects. */
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
/**
* This job runs daily and executes `pod repo update` on MacOS
* This is done to avoid issues with out of date repo causing errors like:
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.9'
pipeline {
+1 -1
View File
@@ -169,7 +169,7 @@ For VS Code users.
### Start and connect the REPL
1. Open the `status-mobile` folder.
1. Start [Status development](STARTING_GUIDE.md#development) (Starting the `run-clojure` and `run-metro` jobs in split view in the VS Code integrated terminal works great.)
1. Start [Status development](starting-guide.md#development) (Starting the `run-clojure` and `run-metro` jobs in split view in the VS Code integrated terminal works great.)
1. Run the VS Code command: **Calva: Connect to a running REPL Server in the project**
1. Select the project type `shadow-cljs`
1. Accept the suggested connection `host:port`
@@ -1156,23 +1156,7 @@ RCT_EXPORT_METHOD(deactivateKeepAwake)
- (NSString*) deviceName
{
NSString* deviceName = nil;
if ([self.deviceId rangeOfString:@"iPod"].location != NSNotFound) {
deviceName = @"iPod Touch";
}
else if([self.deviceId rangeOfString:@"iPad"].location != NSNotFound) {
deviceName = @"iPad";
}
else if([self.deviceId rangeOfString:@"iPhone"].location != NSNotFound){
deviceName = @"iPhone";
}
else if([self.deviceId rangeOfString:@"AppleTV"].location != NSNotFound){
deviceName = @"Apple TV";
}
return deviceName;
return [[UIDevice currentDevice] name];;
}
- (NSDictionary *)constantsToExport
+6
View File
@@ -49,6 +49,12 @@ in {
doCheck = false;
});
# Downgrade watchman in attempt to fix "too many files open issue"
watchman = callPackage ./pkgs/watchman {
inherit (super.darwin.apple_sdk.frameworks) CoreServices;
autoconf = super.buildPackages.autoconf269;
};
# Package version adjustments
gradle = super.gradle_7;
nodejs = super.nodejs-18_x;
+11
View File
@@ -17,9 +17,20 @@ let
# Override some packages and utilities
pkgsOverlay = import ./overlay.nix;
# Fix for lack of Android SDK for M1 Macs.
systemOverride = let
inherit (builtins) currentSystem getEnv;
envSystemOverride = getEnv "NIXPKGS_SYSTEM_OVERRIDE";
in
if envSystemOverride != "" then
envSystemOverride
else
currentSystem;
in
# import nixpkgs with a config override
(import nixpkgsSrc) {
config = defaultConfig // config;
system = systemOverride;
overlays = [ pkgsOverlay ];
}
+4 -1
View File
@@ -3,7 +3,10 @@
# for the Android development environment.
#
{ androidenv }:
{ androidenv, lib, stdenv }:
assert lib.assertMsg (stdenv.system != "aarch64-darwin")
"aarch64-darwin not supported for Android SDK. Use: NIXPKGS_SYSTEM_OVERRIDE=x86_64-darwin";
# The "android-sdk-license" license is accepted
# by setting android_sdk.accept_license = true.
+23
View File
@@ -0,0 +1,23 @@
# Issue
`watchman` was upgraded significantly during the last nixpkgs upgrade (`4.9.0` (Aug 16, 2017) to `2023.01.30.00` - 6 years between):
- https://github.com/status-im/status-mobile/pull/14944
- https://github.com/status-im/nixpkgs/commit/4e9c02bcc709fe1737a746add0e8e0109133d808
Probably causing developers to have "too many files open" issue:
https://github.com/status-im/status-mobile/issues/16341
```
Error: A non-recoverable condition has triggered. Watchman needs your help!
The triggering condition was at timestamp=1687286390: opendir(/Users/javid/Projects/status-mobile/node_modules/metro-core/node_modules/jest-regex-util/build) -> Too many open files
All requests will continue to fail with this message until you resolve
the underlying problem. You will find more information on fixing this at
https://facebook.github.io/watchman/docs/troubleshooting.html#poison-opendir
```
# Fix
This is an attempt to fix the issue by downgrading the watchman
# Upgrade
When upgrading in the future, please read the comments:
https://github.com/status-im/status-mobile/issues/16341
+48
View File
@@ -0,0 +1,48 @@
{ stdenv, lib, config, fetchFromGitHub, autoconf, automake, pcre
, libtool, pkg-config, openssl
, confFile ? config.watchman.confFile or null
, withApple ? stdenv.isDarwin, CoreServices
}:
stdenv.mkDerivation rec {
pname = "watchman";
version = "4.9.0";
src = fetchFromGitHub {
owner = "facebook";
repo = "watchman";
rev = "v${version}";
sha256 = "0fdaj5pmicm6j17d5q7px800m5rmam1a400x3hv1iiifnmhgnkal";
};
nativeBuildInputs = [ autoconf automake pkg-config libtool ];
buildInputs = [ pcre openssl ]
#++ lib.optionals withApple [ CoreServices ];
++ lib.optionals stdenv.isDarwin [ CoreServices ];
configureFlags = [
"--enable-lenient"
"--enable-conffile=${if confFile == null then "no" else confFile}"
"--with-pcre=yes"
# For security considerations re: --disable-statedir, see:
# https://github.com/facebook/watchman/issues/178
"--disable-statedir"
];
prePatch = ''
patchShebangs .
'';
preConfigure = ''
./autogen.sh
'';
meta = with lib; {
description = "Watches files and takes action when they change";
homepage = "https://facebook.github.io/watchman";
maintainers = with maintainers; [ cstrahan ];
platforms = with platforms; linux ++ darwin;
license = licenses.asl20;
};
}
+7 -1
View File
@@ -25,7 +25,7 @@ cleanup() {
# If you want to clean after every build set _NIX_CLEAN=true
if [[ -n "${_NIX_CLEAN}" ]]; then
trap cleanup EXIT ERR INT QUIT
trap cleanup EXIT ERR INT QUIT
fi
# build output will end up under /nix, we have to extract it
@@ -44,6 +44,12 @@ if [[ -z "${TARGET}" ]]; then
exit 1
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
os=$(uname -s | tr '[:upper:]' '[:lower:]')
export NIXPKGS_SYSTEM_OVERRIDE="x86_64-${os}"
fi
# Some defaults flags, --pure could be optional in the future.
# NOTE: The --keep-failed flag can be used for debugging issues.
nixOpts=(
+2 -1
View File
@@ -8,7 +8,8 @@ file_group() {
if [[ "${UNAME}" == "Linux" ]]; then
stat -Lc "%G" "${1}" 2>/dev/null
elif [[ "${UNAME}" == "Darwin" ]]; then
stat -Lf "%Sg" "${1}" 2>/dev/null
# Avoid using Nix GNU stat when in Nix shell.
/usr/bin/stat -Lf "%Sg" "${1}" 2>/dev/null
fi
}
+6 -1
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env bash
#
# This script is used by the Makefile to have an implicit nix-shell.
# The following environment variables modify the script behavior:
# - TARGET: This attribute is passed via --attr to Nix, defining the scope.
@@ -64,6 +63,12 @@ if [[ -n "${_NIX_PURE}" ]]; then
pureDesc='pure '
fi
# Hack fix for missing Android SDK for aarch64 on Darwin. See systemOverride in `nix/pkgs.nix`.
if [[ "${TARGET}" =~ ^(android-sdk|android|gradle|keytool|status-go)$ ]]; then
os=$(uname -s | tr '[:upper:]' '[:lower:]')
export NIXPKGS_SYSTEM_OVERRIDE="x86_64-${os}"
fi
echo -e "${GRN}Configuring ${pureDesc}Nix shell for target '${TARGET}'...${RST}" 1>&2
# Save derivation from being garbage collected
Binary file not shown.

After

Width:  |  Height:  |  Size: 593 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,92 @@
import { useAnimatedStyle, useDerivedValue } from 'react-native-reanimated';
export function background(color, progress) {
return useDerivedValue(function () {
'worklet';
const r = parseInt(color.substring(1, 3), 16);
const g = parseInt(color.substring(3, 5), 16);
const b = parseInt(color.substring(5, 7), 16);
return progress.value <= 25 ? `rgba(${r}, ${g}, ${b}, .4)` : `rgba(${r}, ${g}, ${b}, .2)`;
});
}
export function opacity(progress) {
return useDerivedValue(function () {
'worklet';
return progress.value <= 25 ? 1 : 0.3;
});
}
export function avatarOpacity(progress) {
return useDerivedValue(function () {
'worklet';
const progressValue = progress.value;
switch (true) {
case progressValue <= 25:
return 1;
case progressValue <= 50:
return 0.1;
default:
return 0.3;
}
});
}
export function ringOpacity(progress) {
return useDerivedValue(function () {
'worklet';
return progress.value <= 50 ? 1 : 0.3;
});
}
export function userHashOpacity(progress) {
return useDerivedValue(function () {
'worklet';
const progressValue = progress.value;
switch (true) {
case progressValue <= 25:
return 1;
case progressValue <= 50:
return 0.3;
case progressValue <= 75:
return 1;
default:
return 0.3;
}
});
}
export function userHashColor(progress) {
return useDerivedValue(function () {
'worklet';
const progressValue = progress.value;
switch (true) {
case progressValue <= 25:
return 'rgba(255, 255, 255, .6)';
case progressValue <= 50:
return 'rgba(255, 255, 255, .6)';
case progressValue <= 75:
return 'rgb(255, 255, 255)';
default:
return 'rgba(255, 255, 255, .6)';
}
});
}
export function emojiHashStyle(progress) {
return useAnimatedStyle(function () {
'worklet';
const progressValue = progress.value;
switch (true) {
case progressValue <= 25:
return { opacity: 1 };
case progressValue <= 75:
return { opacity: 0.3 };
default:
return { opacity: 1 };
}
});
}
+7
View File
@@ -6,3 +6,10 @@ export function infoLayout(input, isTop) {
return isTop ? input.value : -input.value;
});
}
export function textSheet(input, isHeight) {
return useDerivedValue(function () {
'worklet';
return isHeight ? input.value : -input.value;
});
}
+9 -21
View File
@@ -1,6 +1,8 @@
import { useDerivedValue, withTiming, Easing } from 'react-native-reanimated';
const slideAnimationDuration = 300;
const totalPages = 4;
const pageSize = 100 / totalPages;
const easeOut = {
duration: slideAnimationDuration,
@@ -15,29 +17,15 @@ export function dynamicProgressBarWidth(staticProgressBarWidth, progress) {
});
}
export function carouselLeftPosition(windowWidth, progress) {
export function carouselLeftPosition(windowWidth, progress, isDragging, dragAmount) {
return useDerivedValue(function () {
'worklet';
const progressValue = progress.value;
switch (true) {
case progressValue < 25:
return 0;
case progressValue === 25:
return withTiming(-windowWidth, easeOut);
case progressValue < 50:
return -windowWidth;
case progressValue === 50:
return withTiming(-2 * windowWidth, easeOut);
case progressValue < 75:
return -2 * windowWidth;
case progressValue === 75:
return withTiming(-3 * windowWidth, easeOut);
case progressValue < 100:
return -3 * windowWidth;
case progressValue === 100:
return withTiming(-4 * windowWidth, easeOut);
default:
return 0;
}
const dragAmountValue = dragAmount.value;
const baseOffset = (Math.floor(progressValue / pageSize) % totalPages) * windowWidth;
const adjustedOffset = baseOffset === 0 && dragAmountValue > 0 ? baseOffset : -baseOffset + dragAmountValue;
return isDragging.value ? withTiming(adjustedOffset, easeOut) : withTiming(-baseOffset, easeOut);
});
}
+1
View File
@@ -13,6 +13,7 @@ which is explained in better detail in this video
https://www.youtube.com/watch?v=iEBoZDHCN5Y&t=2205s
there is a bug with the pitch and roll calculations provided directly from the sensor data so the calculation had to
be done using the quaternions directly.
This link is useful to understand this: https://engineering.stackexchange.com/questions/3348/calculating-pitch-yaw-and-roll-from-mag-acc-and-gyro-data
*/
export function sensorAnimatedImage(zIndex, offset, stretch) {
'worklet';
+59 -1
View File
@@ -1,4 +1,4 @@
import { useDerivedValue, withTiming, withSequence, withDelay, Easing } from 'react-native-reanimated';
import { useDerivedValue, withTiming, withSequence, withDelay, Easing, runOnJS } from 'react-native-reanimated';
import * as constants from './constants';
// Derived Values
@@ -88,3 +88,61 @@ export function screenZIndex(screenState) {
}
});
}
export function screenBorderRadius(screenState) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(0, { duration: 0 }));
case constants.OPEN_SCREEN_WITH_SLIDE_ANIMATION:
case constants.OPEN_SCREEN_WITHOUT_ANIMATION:
return 0;
case constants.CLOSE_SCREEN_WITH_SLIDE_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(20, { duration: 0 }));
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return 20;
}
});
}
export function screenGestureOnUpdate(screenLeft) {
return function (event) {
'worklet';
const absoluteX = event.absoluteX;
if (absoluteX !== null) {
screenLeft.value = event.absoluteX;
}
};
}
export function screenGestureOnEnd(data) {
return function (event) {
'worklet';
const { screenLeft, screenState, screenWidth, leftVelocity, rightVelocity, screenClosedCallback } = data;
const absoluteX = event.absoluteX ?? 0;
const velocityX = event.velocityX ?? 0;
const closeScreen = velocityX > rightVelocity || (velocityX > leftVelocity && absoluteX >= screenWidth / 2);
// Velocity (points/sec) = Distance/time
var animationVelocity = (screenWidth * 1000) / constants.SHELL_ANIMATION_TIME;
if (Math.abs(velocityX) > animationVelocity) {
animationVelocity = velocityX; // Faster fling
}
const newDistance = closeScreen ? screenWidth - absoluteX : absoluteX;
const animationTime = (newDistance * 1000) / animationVelocity;
screenLeft.value = withTiming(closeScreen ? screenWidth : 0, {
duration: animationTime,
easing: Easing.bezier(0, 0, 0.58, 1),
});
if (closeScreen) {
runOnJS(screenClosedCallback)(animationTime);
}
};
}
+75 -73
View File
@@ -364,77 +364,79 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(defn mock
[module]
(case module
"react-native-languages" react-native-languages
"react-native-background-timer" background-timer
"react-native-image-crop-picker" image-crop-picker
"react-native-gesture-handler" react-native-gesture-handler
"react-native-static-safe-area-insets" react-native-static-safe-area-insets
"react-native-config" config
"react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn [])
:getBottomSpace (fn [])})
"react-native-screens" (clj->js {})
"react-native-reanimated" react-native-reanimated
"react-native-redash/lib/module/v1" react-native-redash
"react-native-redash" react-native-redash
"react-native-fetch-polyfill" fetch
"react-native-status-keycard" status-keycard
"react-native-keychain" keychain
"react-native-touch-id" touchid
"@react-native-community/netinfo" net-info
"react-native-dialogs" dialogs
"react-native" react-native
"react-native-fs" fs
"react-native-mail" react-native-mail
"react-native-image-resizer" image-resizer
"react-native-haptic-feedback" react-native-haptic-feedback
"react-native-device-info" react-native-device-info
"react-native-push-notification" react-native-push-notification
"react-native-linear-gradient" react-native-gradien
"@react-native-community/masked-view" masked-view
"react-native-blob-util" react-native-blob-util
"react-native-navigation" react-native-navigation
"@react-native-community/push-notification-ios" push-notification-ios
"@react-native-community/blur" react-native-blur
"@react-native-community/cameraroll" react-native-camera-roll
"react-native-camera-kit" react-native-camera-kit
"react-native-permissions" react-native-permissions
"rn-emoji-keyboard" rn-emoji-keyboard
"react-native-hole-view" react-native-hole-view
"react-native-draggable-flatlist" react-native-draggable-flatlist
"react-native-webview" react-native-webview
"@react-native-community/audio-toolkit" react-native-audio-toolkit
"react-native-image-viewing" react-native-image-viewing
"react-native-share" react-native-share
"@react-native-async-storage/async-storage" async-storage
"react-native-svg" react-native-svg
"react-native-transparent-video" react-native-transparent-video
"react-native-orientation-locker" react-native-orientation-locker
"../src/js/worklets/core.js" worklet-factory
"../src/js/worklets/shell/bottom_tabs.js" #js {}
"../src/js/worklets/shell/home_stack.js" #js {}
"../src/js/worklets/shell/floating_screen.js" #js {}
"../src/js/worklets/bottom_sheet.js" #js {}
"../src/js/worklets/record_audio.js" #js {}
"../src/js/worklets/scroll_view.js" #js {}
"../src/js/worklets/onboarding_carousel.js" #js {}
"../src/js/worklets/lightbox.js" #js {}
"../src/js/worklets/parallax.js" #js {}
"./fleets.js" default-fleets
"@walletconnect/client" wallet-connect-client
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
"../translations/de.json" (js/JSON.parse (slurp "./translations/de.json"))
"../translations/en.json" (js/JSON.parse (slurp "./translations/en.json"))
"../translations/es.json" (js/JSON.parse (slurp "./translations/es.json"))
"../translations/es_419.json" (js/JSON.parse (slurp "./translations/es_419.json"))
"../translations/fil.json" (js/JSON.parse (slurp "./translations/fil.json"))
"../translations/fr.json" (js/JSON.parse (slurp "./translations/fr.json"))
"../translations/id.json" (js/JSON.parse (slurp "./translations/id.json"))
"../translations/it.json" (js/JSON.parse (slurp "./translations/it.json"))
"../translations/ko.json" (js/JSON.parse (slurp "./translations/ko.json"))
"../translations/pt_BR.json" (js/JSON.parse (slurp "./translations/pt_BR.json"))
"../translations/ru.json" (js/JSON.parse (slurp "./translations/ru.json"))
"../translations/tr.json" (js/JSON.parse (slurp "./translations/tr.json"))
"../translations/zh.json" (js/JSON.parse (slurp "./translations/zh.json"))
"../translations/zh_hant.json" (js/JSON.parse (slurp "./translations/zh_hant.json"))
"../translations/zh_TW.json" (js/JSON.parse (slurp "./translations/zh_TW.json"))
"react-native-languages" react-native-languages
"react-native-background-timer" background-timer
"react-native-image-crop-picker" image-crop-picker
"react-native-gesture-handler" react-native-gesture-handler
"react-native-static-safe-area-insets" react-native-static-safe-area-insets
"react-native-config" config
"react-native-iphone-x-helper" (clj->js {:getStatusBarHeight (fn [])
:getBottomSpace (fn [])})
"react-native-screens" (clj->js {})
"react-native-reanimated" react-native-reanimated
"react-native-redash/lib/module/v1" react-native-redash
"react-native-redash" react-native-redash
"react-native-fetch-polyfill" fetch
"react-native-status-keycard" status-keycard
"react-native-keychain" keychain
"react-native-touch-id" touchid
"@react-native-community/netinfo" net-info
"react-native-dialogs" dialogs
"react-native" react-native
"react-native-fs" fs
"react-native-mail" react-native-mail
"react-native-image-resizer" image-resizer
"react-native-haptic-feedback" react-native-haptic-feedback
"react-native-device-info" react-native-device-info
"react-native-push-notification" react-native-push-notification
"react-native-linear-gradient" react-native-gradien
"@react-native-community/masked-view" masked-view
"react-native-blob-util" react-native-blob-util
"react-native-navigation" react-native-navigation
"@react-native-community/push-notification-ios" push-notification-ios
"@react-native-community/blur" react-native-blur
"@react-native-community/cameraroll" react-native-camera-roll
"react-native-camera-kit" react-native-camera-kit
"react-native-permissions" react-native-permissions
"rn-emoji-keyboard" rn-emoji-keyboard
"react-native-hole-view" react-native-hole-view
"react-native-draggable-flatlist" react-native-draggable-flatlist
"react-native-webview" react-native-webview
"@react-native-community/audio-toolkit" react-native-audio-toolkit
"react-native-image-viewing" react-native-image-viewing
"react-native-share" react-native-share
"@react-native-async-storage/async-storage" async-storage
"react-native-svg" react-native-svg
"react-native-transparent-video" react-native-transparent-video
"react-native-orientation-locker" react-native-orientation-locker
"../src/js/worklets/core.js" worklet-factory
"../src/js/worklets/shell/bottom_tabs.js" #js {}
"../src/js/worklets/shell/home_stack.js" #js {}
"../src/js/worklets/shell/floating_screen.js" #js {}
"../src/js/worklets/bottom_sheet.js" #js {}
"../src/js/worklets/record_audio.js" #js {}
"../src/js/worklets/scroll_view.js" #js {}
"../src/js/worklets/onboarding_carousel.js" #js {}
"../src/js/worklets/lightbox.js" #js {}
"../src/js/worklets/parallax.js" #js {}
"../src/js/worklets/identifiers_highlighting.js" #js {}
"./fleets.js" default-fleets
"@walletconnect/client" wallet-connect-client
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
"../translations/de.json" (js/JSON.parse (slurp "./translations/de.json"))
"../translations/en.json" (js/JSON.parse (slurp "./translations/en.json"))
"../translations/es.json" (js/JSON.parse (slurp "./translations/es.json"))
"../translations/es_419.json" (js/JSON.parse (slurp "./translations/es_419.json"))
"../translations/fil.json" (js/JSON.parse (slurp "./translations/fil.json"))
"../translations/fr.json" (js/JSON.parse (slurp "./translations/fr.json"))
"../translations/id.json" (js/JSON.parse (slurp "./translations/id.json"))
"../translations/it.json" (js/JSON.parse (slurp "./translations/it.json"))
"../translations/ko.json" (js/JSON.parse (slurp "./translations/ko.json"))
"../translations/pt_BR.json" (js/JSON.parse (slurp "./translations/pt_BR.json"))
"../translations/ru.json" (js/JSON.parse (slurp "./translations/ru.json"))
"../translations/tr.json" (js/JSON.parse (slurp "./translations/tr.json"))
"../translations/zh.json" (js/JSON.parse (slurp "./translations/zh.json"))
"../translations/zh_hant.json" (js/JSON.parse (slurp
"./translations/zh_hant.json"))
"../translations/zh_TW.json" (js/JSON.parse (slurp "./translations/zh_TW.json"))
nil))
+10 -1
View File
@@ -4,7 +4,8 @@
[taoensso.timbre :as log]
[react-native.platform :as platform]
[react-native.core :as rn]
[utils.transforms :as types]))
[utils.transforms :as types]
[clojure.string :as string]))
(defn status
[]
@@ -387,6 +388,14 @@
:build-id (.-buildId status)
:device-id (.-deviceId status)}))
(defn get-installation-name
[]
;; NOTE(rasom): Only needed for android devices currently
(when platform/android?
(string/join " "
((juxt :model :device-id)
(get-device-model-info)))))
(defn get-node-config
[callback]
(log/debug "[native-module] get-node-config")
+66 -18
View File
@@ -4,7 +4,9 @@
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
[react-native.blur :as blur]
[reagent.core :as reagent]
[quo2.components.buttons.style :as style]))
(defn themes
[customization-color]
@@ -66,6 +68,16 @@
:background-color {:default colors/neutral-80-opa-5
:pressed colors/neutral-80-opa-10
:disabled colors/neutral-80-opa-5}}
:blurred {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-100
:icon-background-color {:default colors/neutral-20
:blurred colors/neutral-80-opa-10}
:label-color colors/neutral-100
:background-color {:default colors/neutral-10
:pressed colors/neutral-10
:disabled colors/neutral-10-opa-10-blur}
:blur-overlay-color colors/neutral-10-opa-40-blur
:blur-type :light}
:blur-bg-outline {:icon-color colors/neutral-100
:icon-secondary-color colors/neutral-80-opa-40
:label-color colors/neutral-100
@@ -135,6 +147,16 @@
:background-color {:default colors/white-opa-5
:pressed colors/white-opa-10
:disabled colors/white-opa-5}}
:blurred {:icon-color colors/white
:icon-secondary-color colors/white
:icon-background-color {:default colors/neutral-80
:blurred colors/white-opa-10}
:label-color colors/white
:background-color {:default colors/neutral-90
:pressed colors/neutral-90
:disabled colors/neutral-90-opa-10-blur}
:blur-overlay-color colors/neutral-80-opa-40
:blur-type :dark}
:blur-bg-outline {:icon-color colors/white
:icon-secondary-color colors/white-opa-40
:label-color colors/white
@@ -157,12 +179,11 @@
24 8))})
(defn style-container
[type size disabled background-color border-color icon above width before after]
[type size disabled background-color border-color icon above width before after blur-active?]
(merge {:height size
:align-items :center
:justify-content :center
:flex-direction (if above :column :row)
:background-color background-color
:padding-horizontal (when-not (or icon before after)
(case size
56 16
@@ -192,7 +213,11 @@
56 0
40 9
32 5
24 4))}
24 4))
:overflow :hidden}
(when (or (and (= type :blurred) (not blur-active?))
(not= type :blurred))
{:background-color background-color})
(shape-style-container type icon size)
(when width
{:width width})
@@ -224,18 +249,23 @@
(fn
[{:keys [on-press disabled type size before after above icon-secondary-no-color
width customization-color theme override-background-color pressed
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
on-long-press accessibility-label icon icon-no-color style inner-style test-ID
blur-active? override-before-margins override-after-margins icon-size icon-container-size
icon-container-rounded?]
:or {type :primary
size 40
customization-color :primary}}
customization-color :primary
blur-active? true}}
children]
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color]}
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color blur-type
blur-overlay-color icon-background-color]}
(get-in (themes customization-color)
[theme type])
state (cond disabled :disabled
(or @pressed-in pressed) :pressed
:else :default)
icon-size (when (= 24 size) 12)
blur-state (if blur-active? :blurred :default)
icon-size (or icon-size (when (= 24 size) 12))
icon-secondary-color (or icon-secondary-color icon-color)]
[rn/touchable-without-feedback
(merge {:test-ID test-ID
@@ -264,9 +294,17 @@
above
width
before
after)
after
blur-active?)
(when (= state :pressed) {:opacity 0.9})
inner-style)}
(when (and (= type :blurred)
blur-active?)
[blur/view
{:blur-radius 20
:blur-type blur-type
:overlay-color blur-overlay-color
:style style/blur-view}])
(when above
[rn/view
[quo2.icons/icon above
@@ -275,11 +313,16 @@
:size icon-size}]])
(when before
[rn/view
{:style (style/before-icon-style
{:override-margins override-before-margins
:size size
:icon-container-size icon-container-size
:icon-background-color (get icon-background-color blur-state)
:icon-container-rounded? icon-container-rounded?
:icon-size icon-size})}
[quo2.icons/icon before
{:container-style {:margin-left (if (= size 40) 12 8)
:margin-right 4}
:color icon-secondary-color
:size icon-size}]])
{:color icon-secondary-color
:size icon-size}]])
[rn/view
(cond
(or icon icon-no-color)
@@ -301,11 +344,16 @@
children)]
(when after
[rn/view
{:style (style/after-icon-style
{:override-margins override-after-margins
:size size
:icon-container-size icon-container-size
:icon-background-color (get icon-background-color blur-state)
:icon-container-rounded? icon-container-rounded?
:icon-size icon-size})}
[quo2.icons/icon after
{:container-style {:margin-left 4
:margin-right (if (= size 40) 12 8)}
:no-color icon-secondary-no-color
:color icon-secondary-color
:size icon-size}]])]]]))))
{:no-color icon-secondary-no-color
:color icon-secondary-color
:size icon-size}]])]]]))))
(def button (theme/with-theme button-internal))
+42
View File
@@ -0,0 +1,42 @@
(ns quo2.components.buttons.style)
(def blur-view
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0})
(defn before-icon-style
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
icon-size]}]
(merge
{:margin-left (or (get override-margins :left)
(if (= size 40) 12 8))
:margin-right (or (get override-margins :right) 4)
:align-items :center
:justify-content :center}
(when icon-container-size
{:width icon-container-size
:height icon-container-size})
(when icon-background-color
{:background-color icon-background-color})
(when icon-container-rounded?
{:border-radius (/ (or icon-container-size icon-size) 2)})))
(defn after-icon-style
[{:keys [override-margins size icon-container-size icon-background-color icon-container-rounded?
icon-size]}]
(merge
{:margin-left (or (get override-margins :left) 4)
:margin-right (or (get override-margins :right)
(if (= size 40) 12 8))
:align-items :center
:justify-content :center}
(when icon-container-size
{:width icon-container-size
:height icon-container-size})
(when icon-background-color
{:background-color icon-background-color})
(when icon-container-rounded?
{:border-radius (/ (or icon-container-size icon-size) 2)})))
+7 -7
View File
@@ -9,23 +9,23 @@
:height 20})
(defn neutral-border-color
[in-blur-view? override-theme]
[in-blur-view? theme]
(if in-blur-view?
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-10 override-theme)
(colors/theme-colors colors/neutral-20 colors/neutral-80 override-theme)))
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-10 theme)
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)))
(def active-background-color (colors/custom-color :blue 50 10))
(def complete-background-color (colors/custom-color :blue 50))
(defn container
[size type in-blur-view? override-theme]
[size type in-blur-view? theme]
(cond-> container-base
(#{1 2} size) (assoc :width 20)
(= size 3) (assoc :width 28)
(= type :neutral)
(assoc :border-width 1
:border-color (neutral-border-color in-blur-view? override-theme))
:border-color (neutral-border-color in-blur-view? theme))
(= type :active)
(assoc :background-color active-background-color)
@@ -35,7 +35,7 @@
(defn text-color
([type] (text-color type nil))
([type override-theme]
([type theme]
(case type
(:neutral :active) (colors/theme-colors colors/neutral-100-opa-100 colors/white override-theme)
(:neutral :active) (colors/theme-colors colors/neutral-100-opa-100 colors/white theme)
:complete colors/white)))
+7 -4
View File
@@ -2,11 +2,12 @@
(:require
[quo2.components.counter.step.style :as style]
[quo2.components.markdown.text :as text]
[quo2.theme :as theme]
[react-native.core :as rn]
[utils.number]))
(defn step
[{:keys [type accessibility-label override-theme in-blur-view?]} value]
(defn themed-step
[{:keys [type accessibility-label theme in-blur-view?]} value]
(let [type (or type :neutral)
value (utils.number/parse-int value)
label (str value)
@@ -14,8 +15,10 @@
[rn/view
{:accessible true
:accessibility-label (or accessibility-label :step-counter)
:style (style/container size type in-blur-view? override-theme)}
:style (style/container size type in-blur-view? theme)}
[text/text
{:weight :medium
:size :label
:style {:color (style/text-color type override-theme)}} label]]))
:style {:color (style/text-color type theme)}} label]]))
(def step (theme/with-theme themed-step))
+6 -2
View File
@@ -7,8 +7,12 @@
[button/button
(merge
opts
{:after (if selected :i/pullup :i/dropdown)
:icon-secondary-no-color true
{:after (if selected :i/chevron-top :i/chevron-down)
:icon-size 12
:icon-container-size 14
:icon-container-rounded? true
:override-after-margins {:left 7
:right 9}
:pressed selected
:on-press #(when on-change (on-change selected))})
children]))
+4 -2
View File
@@ -56,8 +56,10 @@
(when (and (not locked?)
muted?)
[quo2.icons/icon :i/muted
{:size 20
:color colors/neutral-40}])
{:size 20
:color colors/neutral-40
:container-style {:margin-right 1
:margin-top 2}}])
(when (and (not locked?)
(not muted?)
(pos? (int mentions-count)))
@@ -1,7 +1,9 @@
(ns quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec
(:require [quo2.components.record-audio.record-audio.view :as record-audio]
[react-native.audio-toolkit :as audio]
[test-helpers.component :as h]))
[test-helpers.component :as h]
[reagent.core :as reagent]
[utils.datetime :as datetime]))
(h/describe "record audio component"
(h/before-each
@@ -34,12 +36,16 @@
(.toHaveBeenCalledTimes 1))))
(h/test "record-audio on-reviewing-audio works"
(let [event (js/jest.fn)]
(let [event (js/jest.fn)
on-meter (reagent/atom nil)]
(h/render [record-audio/record-audio
{:on-reviewing-audio event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
(with-redefs [audio/new-recorder (fn [_ on-meter-fn _]
(reset! on-meter on-meter-fn))
audio/start-recording (fn [_ on-start _]
(on-start)
(js/setInterval #(@on-meter) 100))
audio/get-recorder-file-path (fn [] "file-path")]
(h/fire-event
:on-start-should-set-responder
@@ -48,25 +54,30 @@
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (h/expect event)
(.toHaveBeenCalledTimes 1)))))
(with-redefs [datetime/timestamp (fn [] (+ (.now js/Date) 1000))]
(h/advance-timers-by-time 100)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (h/expect event)
(.toHaveBeenCalledTimes 1))))))
(h/test "record-audio on-send works after reviewing audio"
(let [event (js/jest.fn)]
(let [event (js/jest.fn)
on-meter (reagent/atom nil)]
(h/render [record-audio/record-audio
{:on-send event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
(with-redefs [audio/new-recorder (fn [_ on-meter-fn _]
(reset! on-meter on-meter-fn))
audio/start-recording (fn [_ on-start _]
(on-start)
(js/setInterval #(@on-meter) 100))
audio/get-recorder-file-path (fn [] "audio-file-path")
audio/get-player-duration (fn [] 5000)]
(h/fire-event
@@ -76,46 +87,57 @@
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 200
:identifier 0}})
(h/fire-event
:on-start-should-set-responder
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 80
:locationY 80
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1))
(-> (js/expect event)
(.toHaveBeenCalledWith {:file-path "audio-file-path"
:duration 5000})))))
(with-redefs [datetime/timestamp (fn [] (+ (.now js/Date) 1000))]
(h/advance-timers-by-time 100)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 200
:identifier 0}})
(h/fire-event
:on-start-should-set-responder
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 80
:locationY 80
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1))
(-> (js/expect event)
(.toHaveBeenCalledWith {:file-path "audio-file-path"
:duration 5000}))))))
(h/test "record-audio on-send works after sliding to the send button"
(let [event (js/jest.fn)]
(let [event (js/jest.fn)
on-meter (reagent/atom nil)
last-now-ms (atom nil)
duration-ms (atom nil)]
(h/render [record-audio/record-audio
{:on-send event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
(with-redefs [audio/new-recorder (fn [_ on-meter-fn _]
(reset! on-meter on-meter-fn))
audio/start-recording (fn [_ on-start _]
(on-start)
(js/setInterval #(@on-meter) 100))
audio/stop-recording (fn [_ on-stop _]
(on-stop))
audio/get-recorder-file-path (fn [] "audio-file-path")]
audio/get-recorder-file-path (fn [] "audio-file-path")
datetime/timestamp (fn []
(let [now-ms (.now js/Date)]
(reset! last-now-ms now-ms)
now-ms))]
(h/fire-event
:on-start-should-set-responder
(h/get-by-test-id "record-audio")
@@ -123,36 +145,46 @@
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-move
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 80
:locationY -30
:pageX 80
:pageY -30
:identifier 0}})
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 40
:locationY 80
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1))
(-> (js/expect event)
(.toHaveBeenCalledWith {:file-path "audio-file-path"
:duration 500})))))
(with-redefs [datetime/timestamp (fn []
(let [now-plus-ms (+ (.now js/Date) 1000)
time-diff-ms (- now-plus-ms @last-now-ms)]
(when-not @duration-ms
(reset! duration-ms time-diff-ms))
now-plus-ms))]
(h/advance-timers-by-time 100)
(h/fire-event
:on-responder-move
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 80
:locationY -30
:pageX 80
:pageY -30
:identifier 0}})
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 40
:locationY 80
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1))
(-> (js/expect event)
(.toHaveBeenCalledWith {:file-path "audio-file-path"
:duration @duration-ms}))))))
(h/test "record-audio on-cancel works after reviewing audio"
(let [event (js/jest.fn)]
(let [event (js/jest.fn)
on-meter (reagent/atom nil)]
(h/render [record-audio/record-audio
{:on-cancel event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))]
(with-redefs [audio/new-recorder (fn [_ on-meter-fn _]
(reset! on-meter on-meter-fn))
audio/start-recording (fn [_ on-start _]
(on-start)
(js/setInterval #(@on-meter) 100))]
(h/fire-event
:on-start-should-set-responder
(h/get-by-test-id "record-audio")
@@ -160,32 +192,37 @@
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 200
:identifier 0}})
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 40
:locationY 80
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1)))))
(with-redefs [datetime/timestamp (fn [] (+ (.now js/Date) 1000))]
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 70
:locationY 70
:timestamp 200
:identifier 0}})
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX 40
:locationY 80
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1))))))
(h/test "cord-audio on-cancel works after sliding to the cancel button"
(let [event (js/jest.fn)]
(h/test "record-audio on-cancel works after sliding to the cancel button"
(let [event (js/jest.fn)
on-meter (reagent/atom nil)]
(h/render [record-audio/record-audio
{:on-cancel event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
(with-redefs [audio/new-recorder (fn [_ on-meter-fn _]
(reset! on-meter on-meter-fn))
audio/start-recording (fn [_ on-start _]
(on-start)
(js/setInterval #(@on-meter) 100))
audio/stop-recording (fn [_ on-stop _]
(on-stop))]
(h/fire-event
@@ -195,22 +232,25 @@
:locationY 70
:timestamp 0
:identifier 0}})
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-move
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX -30
:locationY 80
:pageX -30
:pageY 80
:identifier 0}})
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX -10
:locationY 70
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1))))))
(with-redefs [datetime/timestamp (fn [] (+ (.now js/Date) 1000))]
(h/advance-timers-by-time 500)
(h/fire-event
:on-responder-move
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX -30
:locationY 80
:pageX -30
:pageY 80
:identifier 0}})
(h/fire-event
:on-responder-release
(h/get-by-test-id "record-audio")
{:nativeEvent {:locationX -10
:locationY 70
:timestamp 200
:identifier 0}})
(h/advance-timers-by-time 250)
(-> (js/expect event)
(.toHaveBeenCalledTimes 1)))))))
@@ -29,7 +29,7 @@
(defn f-record-button-big
[recording? ready-to-send? ready-to-lock? ready-to-delete? record-button-is-animating?
record-button-at-initial-position? locked? reviewing-audio? recording-timer recording-length-ms
record-button-at-initial-position? locked? reviewing-audio? recording-length-ms
clear-timeout touch-active? recorder-ref reload-recorder-fn idle? on-send on-cancel]
(let [scale (reanimated/use-shared-value 1)
opacity (reanimated/use-shared-value 0)
@@ -82,7 +82,6 @@
(reset! ready-to-lock? false)
(reset! idle? true)
(js/setTimeout #(reset! idle? false) 1000)
(js/clearInterval @recording-timer)
(reset! recording-length-ms 0)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))))
@@ -15,11 +15,13 @@
[quo2.components.record-audio.record-audio.buttons.lock-button :as lock-button]
[quo2.components.record-audio.record-audio.buttons.delete-button :as delete-button]
[quo2.components.record-audio.record-audio.buttons.record-button :as record-button]
[clojure.string :as string]))
[clojure.string :as string]
[utils.datetime :as datetime]
[react-native.platform :as platform]))
(def ^:private min-audio-duration-ms 500)
(def ^:private max-audio-duration-ms 120000)
(def ^:private metering-interval 100)
(def ^:private min-audio-duration-ms 1000)
(def ^:private max-audio-duration-ms (if platform/ios? 120800 120500))
(def ^:private metering-interval 25)
(def ^:private base-filename "am")
(def ^:private default-format ".aac")
@@ -108,7 +110,7 @@
time-str]]))
(defn- f-play-button
[playing-audio? player-ref playing-timer audio-current-time-ms seeking-audio?]
[playing-audio? player-ref playing-timer audio-current-time-ms seeking-audio? max-duration-ms]
(let [on-play (fn []
(reset! playing-audio? true)
(reset! playing-timer
@@ -117,8 +119,22 @@
(let [current-time (audio/get-player-current-time @player-ref)
player-state (audio/get-state @player-ref)
playing? (= player-state audio/PLAYING)]
(when (and playing? (not @seeking-audio?) (> current-time 0))
(reset! audio-current-time-ms current-time))))
(when (and playing?
(not @seeking-audio?)
(> current-time 0)
(< current-time max-duration-ms))
(reset! audio-current-time-ms current-time))
(when (>= current-time max-duration-ms)
(audio/stop-playing
@player-ref
(fn []
(reset! playing-audio? false)
(when @playing-timer
(js/clearInterval @playing-timer)
(reset! playing-timer nil)
(reset! audio-current-time-ms 0)
(reset! seeking-audio? false)))
#(log/error "[record-audio] stop player - error: " %)))))
100)))
on-pause (fn []
(reset! playing-audio? false)
@@ -143,7 +159,7 @@
[{:keys [on-init on-start-recording on-send on-cancel on-reviewing-audio
record-audio-permission-granted
on-request-record-audio-permission on-check-audio-permissions
audio-file on-lock]}]
audio-file on-lock max-duration-ms]}]
[:f>
;; TODO we need to refactor this, and use :f> with defined function, currenly state is reseted each
;; time parent component
@@ -160,6 +176,7 @@
audio-current-time-ms (reagent/atom 0)
seeking-audio? (reagent/atom false)
force-show-controls? (reagent/atom (some? audio-file))
recording-start-ms (atom (datetime/timestamp))
clear-timeout (atom nil)
record-button-at-initial-position? (atom true)
record-button-is-animating? (atom false)
@@ -167,7 +184,6 @@
recorder-ref (atom nil)
player-ref (atom nil)
touch-active? (atom false)
recording-timer (atom nil)
playing-timer (atom nil)
output-file (atom audio-file)
reached-max-duration? (atom false)
@@ -178,7 +194,7 @@
rec-options
(merge
audio/default-recorder-options
{:filename (str base-filename (.now js/Date) default-format)
{:filename (str base-filename (datetime/timestamp) default-format)
:meteringInterval metering-interval})
destroy-player
(fn []
@@ -209,13 +225,44 @@
(fn []
(audio/destroy-recorder @recorder-ref)
(reset! recorder-ref nil))
recorder-on-meter
(fn []
(when @recording-start-ms
(let [now-ms (datetime/timestamp)
recording-duration (- now-ms
@recording-start-ms)]
(reset! recording-length-ms recording-duration)
(when (>= recording-duration max-audio-duration-ms)
(reset! reached-max-duration? (not @locked?))
(reset! reviewing-audio? true)
(reset! idle? false)
(reset! locked? false)
(reset! recording? false)
(reset! ready-to-lock? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(audio/stop-recording
@recorder-ref
(fn []
(reset! output-file (audio/get-recorder-file-path
@recorder-ref))
(reload-player nil)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))
(js/setTimeout #(reset! idle? false) 1000)
(reset! recording-length-ms 0)
(reset! recording-start-ms nil)
(when on-reviewing-audio
(on-reviewing-audio (audio/get-recorder-file-path
@recorder-ref))))
(log/debug "[record-audio] new recorder - on meter"))))
reload-recorder
(fn []
(when @recorder-ref
(destroy-recorder))
(reset! recorder-ref (audio/new-recorder
rec-options
#(log/debug "[record-audio] new recorder - on meter")
recorder-on-meter
#(log/debug "[record-audio] new recorder - on ended"))))
reset-recorder
(fn []
@@ -238,9 +285,6 @@
(when @clear-timeout
(js/clearTimeout @clear-timeout)
(reset! clear-timeout nil))
(when @recording-timer
(js/clearInterval @recording-timer)
(reset! recording-timer nil))
(when @playing-timer
(js/clearInterval @playing-timer)
(reset! playing-timer nil))
@@ -258,7 +302,7 @@
record-button-area)
new-recorder (audio/new-recorder
rec-options
#(log/debug "[record-audio] new recorder - on meter")
recorder-on-meter
#(log/debug "[record-audio] new recorder - on ended"))]
(reset! touch-timestamp (oops/oget e "nativeEvent.timestamp"))
(reset! touch-identifier (oops/oget e "nativeEvent.identifier"))
@@ -269,44 +313,13 @@
(reset! recording? pressed-record-button?))
(when pressed-record-button?
(reset! playing-audio? false)
(when @recording-timer
(js/clearInterval @recording-timer))
(reset! output-file nil)
(reset! recorder-ref new-recorder)
(audio/start-recording
new-recorder
(fn []
(reset! recording-start-ms (datetime/timestamp))
(reset! audio-current-time-ms 0)
(reset! recording-timer
(js/setInterval
(fn []
(if (< @recording-length-ms max-audio-duration-ms)
(reset! recording-length-ms
(+ @recording-length-ms metering-interval))
(do
(reset! reached-max-duration? (not @locked?))
(reset! reviewing-audio? true)
(reset! idle? false)
(reset! locked? false)
(reset! recording? false)
(reset! ready-to-lock? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(audio/stop-recording
new-recorder
(fn []
(reset! output-file (audio/get-recorder-file-path
new-recorder))
(reload-player nil)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))
(js/setTimeout #(reset! idle? false) 1000)
(js/clearInterval @recording-timer)
(reset! recording-length-ms 0)
(when on-reviewing-audio
(on-reviewing-audio (audio/get-recorder-file-path
new-recorder))))))
metering-interval))
(log/debug "[record-audio] start recording - success"))
#(log/error "[record-audio] start recording - error: " %))
(when on-start-recording
@@ -424,7 +437,8 @@
(reset! force-show-controls? false)
(when on-send
(on-send {:file-path @output-file
:duration (int (audio/get-player-duration @player-ref))}))
:duration (min max-audio-duration-ms
(int (audio/get-player-duration @player-ref)))}))
(when @player-ref
(audio/stop-playing
@player-ref
@@ -475,8 +489,8 @@
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %))
(js/setTimeout #(reset! idle? false) 1000)
(js/clearInterval @recording-timer)
(reset! recording-length-ms 0)
(reset! recording-start-ms nil)
(reset! disabled? false))
(if (> touch-timestamp-diff min-touch-duration) 0 250)))
(and (not @locked?) (not @reviewing-audio?) (not @record-button-is-animating?))
@@ -501,8 +515,8 @@
(reset! ready-to-lock? false)
(reset! idle? true)
(js/setTimeout #(reset! idle? false) 1000)
(js/clearInterval @recording-timer)
(reset! recording-length-ms 0)
(reset! recording-start-ms nil)
(reset! disabled? false)
(log/debug "[record-audio] stop recording - success"))
#(log/error "[record-audio] stop recording - error: " %)))
@@ -532,11 +546,12 @@
(when @reviewing-audio?
[:<>
[:f> f-play-button playing-audio? player-ref playing-timer audio-current-time-ms
seeking-audio?]
seeking-audio? max-duration-ms]
[:f> soundtrack/f-soundtrack
{:audio-current-time-ms audio-current-time-ms
:player-ref @player-ref
:seeking-audio? seeking-audio?}]])
:seeking-audio? seeking-audio?
:max-audio-duration-ms max-duration-ms}]])
(when (or @recording? @reviewing-audio?)
[:f> f-time-counter @recording? @recording-length-ms @ready-to-delete? @reviewing-audio?
@audio-current-time-ms])
@@ -567,7 +582,6 @@
record-button-at-initial-position?
locked?
reviewing-audio?
recording-timer
recording-length-ms
clear-timeout
touch-active?
@@ -10,8 +10,8 @@
(def ^:private thumb-dark (js/require "../resources/images/icons2/12x12/thumb-dark.png"))
(defn f-soundtrack
[{:keys [audio-current-time-ms player-ref style seeking-audio?]}]
(let [audio-duration-ms (audio/get-player-duration player-ref)]
[{:keys [audio-current-time-ms player-ref style seeking-audio? max-audio-duration-ms]}]
(let [audio-duration-ms (min max-audio-duration-ms (audio/get-player-duration player-ref))]
[:<>
[slider/slider
{:test-ID "soundtrack"
+6
View File
@@ -88,6 +88,8 @@
(def neutral-100-opa-5 (alpha neutral-100 0.05))
(def neutral-100-opa-10 (alpha neutral-100 0.1))
(def neutral-100-opa-30 (alpha neutral-100 0.3))
(def neutral-100-opa-50 (alpha neutral-100 0.5))
(def neutral-100-opa-60 (alpha neutral-100 0.6))
(def neutral-100-opa-70 (alpha neutral-100 0.7))
(def neutral-100-opa-80 (alpha neutral-100 0.8))
@@ -121,7 +123,11 @@
(def white-70-blur (alpha white 0.7))
(def neutral-80-opa-1-blur (alpha "#192438" 0.1))
(def neutral-5-opa-70-blur (alpha neutral-5 0.7))
(def neutral-10-opa-10-blur (alpha neutral-10 0.1))
(def neutral-10-opa-40-blur (alpha neutral-10 0.4))
(def neutral-80-opa-80-blur (alpha "#192438" 0.8))
(def neutral-90-opa-10-blur (alpha neutral-90 0.1))
(def neutral-90-opa-40-blur (alpha neutral-90 0.4))
(def neutral-90-opa-70-blur (alpha neutral-90 0.7))
(def neutral-95-opa-70-blur neutral-95-opa-70)
(def neutral-100-opa-70-blur neutral-100-opa-70)
+7
View File
@@ -1,5 +1,6 @@
(ns react-native.cameraroll
(:require ["@react-native-community/cameraroll" :as CameraRoll]
[react-native.fs :as fs]
[utils.transforms :as transforms]
[taoensso.timbre :as log]))
@@ -14,3 +15,9 @@
(-> (.getAlbums CameraRoll (clj->js opts))
(.then #(callback (transforms/js->clj %)))
(.catch #(log/warn "could not get camera roll albums" %))))
(defn save-image
[path]
(-> (.save CameraRoll (clj->js path))
(.then #(fs/unlink path))
(.catch #(fs/unlink path))))
+4
View File
@@ -68,6 +68,10 @@
(fn []
(js->clj (.get (.-Dimensions ^js react-native) "screen") :keywordize-keys true))))
(def small-screen?
(let [height (:height (get-screen))]
(< height 700)))
(defn hw-back-add-listener
[callback]
(.addEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
+6
View File
@@ -19,6 +19,8 @@
(defn gesture-pan [] (.Pan ^js Gesture))
(defn gesture-long-press [] (.LongPress ^js Gesture))
(defn gesture-pinch [] (.Pinch ^js Gesture))
(defn on-begin [gesture handler] (.onBegin ^js gesture handler))
@@ -35,6 +37,10 @@
(defn min-distance [gesture dist] (.minDistance ^js gesture dist))
(defn fail-offset-x [gesture offset] (.failOffsetX ^js gesture offset))
(defn hit-slop [gesture settings] (.hitSlop ^js gesture settings))
(defn number-of-taps [gesture count] (.numberOfTaps ^js gesture count))
(defn enabled [gesture enabled?] (.enabled ^js gesture enabled?))
+4
View File
@@ -33,6 +33,10 @@
[comp]
(.showOverlay Navigation (clj->js comp)))
(defn pop-to
[comp]
(.popTo Navigation (clj->js comp)))
(defn pop-to-root
[tab]
(.popToRoot Navigation (clj->js tab)))
+3 -1
View File
@@ -1,5 +1,5 @@
(ns react-native.permissions
(:require ["react-native-permissions" :refer (check requestMultiple PERMISSIONS RESULTS)]
(:require ["react-native-permissions" :refer (check openSettings requestMultiple PERMISSIONS RESULTS)]
[react-native.platform :as platform]))
(def permissions-map
@@ -38,3 +38,5 @@
(-> (check (get permissions-map permission))
(.then #(on-result (not (#{(.-BLOCKED RESULTS) (.-DENIED RESULTS)} %))))
(.catch #(on-error %))))
(def open-settings openSettings)
+1
View File
@@ -34,6 +34,7 @@
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
(def view (reagent/adapt-react-class (.-View reanimated)))
(def text (reagent/adapt-react-class (.-Text reanimated)))
(def scroll-view (reagent/adapt-react-class (.-ScrollView reanimated)))
(def image (reagent/adapt-react-class (.-Image reanimated)))
+12 -12
View File
@@ -22,7 +22,7 @@
(rf/defn fetch
[cofx id]
(let [network (get-in cofx [:db :networks/current-network])]
(get-in cofx [:db :multiaccount :custom-bootnodes network id])))
(get-in cofx [:db :profile/profile :custom-bootnodes network id])))
(rf/defn set-input
{:events [:bootnodes.ui/input-changed]}
@@ -54,26 +54,26 @@
(defn custom-bootnodes-in-use?
[{:keys [db]}]
(let [network (:networks/current-network db)]
(get-in db [:multiaccount :custom-bootnodes-enabled? network])))
(get-in db [:profile/profile :custom-bootnodes-enabled? network])))
(rf/defn delete
[{{:keys [multiaccount] :as db} :db :as cofx} id]
(let [network (:networks/current-network db)
new-multiaccount (update-in multiaccount [:custom-bootnodes network] dissoc id)]
[{{:profile/keys [profile] :as db} :db :as cofx} id]
(let [network (:networks/current-network db)
new-profile (update-in profile [:custom-bootnodes network] dissoc id)]
(rf/merge cofx
{:db (assoc db :multiaccount new-multiaccount)}
{:db (assoc db :profile/profile new-profile)}
(multiaccounts.update/multiaccount-update
:custom-bootnodes
(:custom-bootnodes new-multiaccount)
(:custom-bootnodes new-profile)
{:success-event (when (custom-bootnodes-in-use? cofx)
[:multiaccounts.update.callback/save-settings-success])}))))
(rf/defn upsert
{:events [:bootnodes.ui/save-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:bootnodes/keys [manage] :keys [multiaccount] :as db} :db
random-id-generator :random-id-generator
:as cofx}]
[{{:bootnodes/keys [manage] :profile/keys [profile] :as db} :db
random-id-generator :random-id-generator
:as cofx}]
(let [{:keys [name id url]} manage
network (:networks/current-network db)
bootnode (build
@@ -82,7 +82,7 @@
(:value url)
network)
new-bootnodes (assoc-in
(:custom-bootnodes multiaccount)
(:custom-bootnodes profile)
[network (:id bootnode)]
bootnode)]
@@ -99,7 +99,7 @@
{:events [:bootnodes.ui/custom-bootnodes-switch-toggled]}
[{:keys [db] :as cofx} value]
(let [current-network (:networks/current-network db)
bootnodes-settings (get-in db [:multiaccount :custom-bootnodes-enabled?])]
bootnodes-settings (get-in db [:profile/profile :custom-bootnodes-enabled?])]
(multiaccounts.update/multiaccount-update
cofx
:custom-bootnodes-enabled?
+11 -11
View File
@@ -20,9 +20,9 @@
{:random-id-generator (constantly "some-id")
:db {:bootnodes/manage new-bootnode
:networks/current-network "mainnet_rpc"
:multiaccount {:not-empty
"would throw an error if was empty"}}})]
(is (= expected (get-in actual [:db :multiaccount :custom-bootnodes])))))
:profile/profile {:not-empty
"would throw an error if was empty"}}})]
(is (= expected (get-in actual [:db :profile/profile :custom-bootnodes])))))
(testing "adding an existing bootnode"
(let [new-bootnode {:id {:value "a"}
:name {:value "new-name"}
@@ -35,13 +35,13 @@
{:random-id-generator (constantly "some-id")
:db {:bootnodes/manage new-bootnode
:networks/current-network "mainnet_rpc"
:multiaccount {:custom-bootnodes
:profile/profile {:custom-bootnodes
{"mainnet_rpc"
{"a" {:name "name"
:address "url"
:chain "mainnet_rpc"
:id "a"}}}}}})]
(is (= expected (get-in actual [:db :multiaccount :custom-bootnodes]))))))
(is (= expected (get-in actual [:db :profile/profile :custom-bootnodes]))))))
(deftest set-input-bootnode
(testing "it validates names"
@@ -72,7 +72,7 @@
(deftest edit-bootnode
(let [db {:networks/current-network "mainnet_rpc"
:multiaccount
:profile/profile
{:custom-bootnodes
{"mainnet_rpc"
{"a" {:id "a"
@@ -123,7 +123,7 @@
(deftest fetch-bootnode
(testing "it fetches the bootnode from the db"
(let [cofx {:db {:networks/current-network "mainnet_rpc"
:multiaccount {:custom-bootnodes
:profile/profile {:custom-bootnodes
{"mainnet_rpc"
{"a" {:id "a"
:name "name"
@@ -138,7 +138,7 @@
(testing "it returns true when enabled"
(is (model/custom-bootnodes-in-use?
{:db {:networks/current-network "mainnet_rpc"
:multiaccount {:custom-bootnodes-enabled?
:profile/profile {:custom-bootnodes-enabled?
{"mainnet_rpc" true}}}}))))
(testing "is on a different network"
(testing "it returns false when not enabled"
@@ -146,13 +146,13 @@
(testing "it returns true when enabled"
(is (not (model/custom-bootnodes-in-use?
{:db {:networks/current-network "goerli_rpc"
:multiaccount {:custom-bootnodes-enabled?
:profile/profile {:custom-bootnodes-enabled?
{"mainnnet_rpc" true}}}}))))))
(deftest delete-bootnode
(testing "non existing bootnode"
(let [cofx {:db {:networks/current-network "mainnet_rpc"
:multiaccount {:custom-bootnodes
:profile/profile {:custom-bootnodes
{"mainnet_rpc"
{"a" {:id "a"
:name "name"
@@ -165,7 +165,7 @@
(is (model/fetch actual "a")))))
(testing "existing bootnode"
(let [cofx {:db {:networks/current-network "mainnet_rpc"
:multiaccount {:custom-bootnodes
:profile/profile {:custom-bootnodes
{"mainnet_rpc"
{"a" {:id "a"
:name "name"
+1 -1
View File
@@ -385,7 +385,7 @@
(rf/defn web3-send-async
[cofx dapp-name {:keys [method params id] :as payload} message-id]
(let [message? (web3-sign-message? method)
dapps-address (get-in cofx [:db :multiaccount :dapps-address])
dapps-address (get-in cofx [:db :profile/profile :dapps-address])
typed? (and (not= constants/web3-personal-sign method)
(not= constants/web3-eth-sign method))]
(if (or message? (= constants/web3-send-transaction method))
+1 -1
View File
@@ -42,7 +42,7 @@
(defn get-permission-data
[cofx allowed-permission]
(let [multiaccount (get-in cofx [:db :multiaccount])]
(let [multiaccount (get-in cofx [:db :profile/profile])]
(get {constants/dapp-permission-contact-code (:public-key multiaccount)
constants/dapp-permission-web3 [(:dapps-address multiaccount)]}
allowed-permission)))
+1 -1
View File
@@ -9,7 +9,7 @@
(let [dapp-name "test.com"
dapp-name2 "test2.org"
cofx {:db (assoc-in (:db (browser/open-url {:db {}} dapp-name))
[:multiaccount :public-key]
[:profile/profile :public-key]
"public-key")}
dapp-id (core.tests/get-dapp-id cofx dapp-name)]
(testing "dapps permissions are initialized"
+8 -23
View File
@@ -1,16 +1,13 @@
(ns status-im.chat.models.images
(:require ["@react-native-community/cameraroll" :as CameraRoll]
["react-native-blob-util" :default ReactNativeBlobUtil]
(:require ["react-native-blob-util" :default ReactNativeBlobUtil]
[re-frame.core :as re-frame]
[react-native.share :as share]
[utils.i18n :as i18n]
[react-native.permissions :as permissions]
[react-native.cameraroll :as cameraroll]
[status-im.ui.components.react :as react]
[status-im2.config :as config]
[react-native.fs :as fs]
[utils.re-frame :as rf]
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
(def temp-image-url (str (fs/cache-dir) "/StatusIm_Image.jpeg"))
@@ -22,7 +19,7 @@
:path temp-image-url}))
(.fetch "GET" base64-uri)
(.then #(on-success (.path %)))
(.catch #(log/error "could not save image"))))
(.catch #(log/error "could not download image" {:error %}))))
(defn share-image
[uri]
@@ -33,23 +30,11 @@
#(fs/unlink downloaded-url)
#(fs/unlink downloaded-url)))))
(defn save-to-gallery [path] (.save CameraRoll path))
(re-frame/reg-fx
::save-image-to-gallery
(fn [base64-uri]
(if platform/ios?
(-> (download-image-http base64-uri save-to-gallery)
(.catch #(utils/show-popup (i18n/label :t/error)
(i18n/label :t/external-storage-denied))))
(permissions/request-permissions
{:permissions [:write-external-storage]
:on-allowed #(download-image-http base64-uri save-to-gallery)
:on-denied (fn []
(utils/set-timeout
#(utils/show-popup (i18n/label :t/error)
(i18n/label :t/external-storage-denied))
50))}))))
(defn save-image-to-gallery
[base64-uri on-success]
(-> (download-image-http base64-uri cameraroll/save-image)
(.then on-success)
(.catch #(log/error (str "could not save image to gallery" %)))))
(re-frame/reg-fx
::chat-open-image-picker-camera
+10 -9
View File
@@ -11,17 +11,18 @@
[status-im2.contexts.chat.composer.link-preview.events :as link-preview]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.string :as utils.string]))
(defn text->emoji
"Replaces emojis in a specified `text`"
[text]
(utils/safe-replace text
#":([a-z_\-+0-9]*):"
(fn [[original emoji-id]]
(if-let [emoji-map (object/get (.-lib emojis) emoji-id)]
(.-char ^js emoji-map)
original))))
(utils.string/safe-replace text
#":([a-z_\-+0-9]*):"
(fn [[original emoji-id]]
(if-let [emoji-map (object/get (.-lib emojis) emoji-id)]
(.-char ^js emoji-map)
original))))
;; effects
(re-frame/reg-fx
@@ -147,7 +148,7 @@
(when-not (string/blank? input-text)
(let [{:keys [message-id]}
(get-in db [:chat/inputs current-chat-id :metadata :responding-to-message])
preferred-name (get-in db [:multiaccount :preferred-name])
preferred-name (get-in db [:profile/profile :preferred-name])
emoji? (message-content/emoji-only-content? {:text input-text
:response-to message-id})]
{:chat-id current-chat-id
@@ -169,7 +170,7 @@
{:chat-id chat-id
:album-id album-id
:content-type constants/content-type-image
:image-path (utils/safe-replace resized-uri #"file://" "")
:image-path (utils.string/safe-replace resized-uri #"file://" "")
:image-width width
:image-height height
:text input-text
+2 -2
View File
@@ -83,7 +83,7 @@
[{db :db} chat-id]
{:db (mark-chat-all-read db chat-id)
:clear-message-notifications [[chat-id]
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
(get-in db [:profile/profile :remote-push-notifications-enabled?])]
:json-rpc/call [{:method "wakuext_markAllRead"
:params [chat-id]
:on-success #(re-frame/dispatch [::mark-all-read-successful])}]})
@@ -94,7 +94,7 @@
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
(get-in db [:profile/profile :remote-push-notifications-enabled?])]
:json-rpc/call [{:method "wakuext_markAllReadInCommunity"
:params [community-id]
:on-success #(re-frame/dispatch
+1 -1
View File
@@ -9,7 +9,7 @@
{:db (assoc db
:commands/select-account
{:message message
:from (ethereum/get-default-account (:multiaccount/accounts db))})
:from (ethereum/get-default-account (:profile/wallet-accounts db))})
:show-select-acc-sheet nil})
(rf/defn set-selected-account
+6 -6
View File
@@ -11,7 +11,7 @@
[status-im.bottom-sheet.events :as bottom-sheet]
[status-im2.common.toasts.events :as toasts]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.contexts.shell.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
@@ -102,7 +102,7 @@
(rf/defn handle-requests-to-join
[{:keys [db]} requests]
(let [my-public-key (get-in db [:multiaccount :public-key])]
(let [my-public-key (get-in db [:profile/profile :public-key])]
{:db (reduce (fn [db {:keys [public-key] :as request}]
(let [my-request? (= my-public-key public-key)]
(if my-request?
@@ -278,7 +278,7 @@
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
(get-in db [:profile/profile :remote-push-notifications-enabled?])]
:dispatch [:shell/close-switcher-card community-id]
:json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
@@ -795,14 +795,14 @@
(rf/defn store-category-state
{:events [::store-category-state]}
[{:keys [db]} community-id category-id state-open?]
(let [public-key (get-in db [:multiaccount :public-key])
(let [public-key (get-in db [:profile/profile :public-key])
hash (category-hash public-key community-id category-id)]
{::async-storage/set! {hash state-open?}}))
(rf/defn update-category-states-in-db
{:events [::category-states-loaded]}
[{:keys [db]} community-id hashes states]
(let [public-key (get-in db [:multiaccount :public-key])
(let [public-key (get-in db [:profile/profile :public-key])
categories-old (get-in db [:communities community-id :categories])
categories (reduce (fn [acc [category-id category]]
(let [hash (get hashes category-id)
@@ -816,7 +816,7 @@
(rf/defn load-category-states
{:events [:communities/load-category-states]}
[{:keys [db]} community-id]
(let [public-key (get-in db [:multiaccount :public-key])
(let [public-key (get-in db [:profile/profile :public-key])
categories (get-in db [:communities community-id :categories])
{:keys [keys hashes]} (reduce (fn [acc category]
(let [category-id (get category 0)
+2 -2
View File
@@ -6,7 +6,7 @@
[status-im2.contexts.contacts.events :as contacts-store]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.contexts.shell.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]))
(rf/defn clean-up-chat
@@ -49,7 +49,7 @@
(assoc-in [:contacts/contacts public-key :added?] false))
:dispatch [:shell/close-switcher-card public-key]
:clear-message-notifications
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
[[public-key] (get-in db [:profile/profile :remote-push-notifications-enabled?])]}
(activity-center/notifications-fetch-unread-count)
fxs)))
+1 -1
View File
@@ -5,7 +5,7 @@
(defn get-currency
[db]
(get-in db [:multiaccount :currency] :usd))
(get-in db [:profile/profile :currency] :usd))
(rf/defn set-currency
{:events [:wallet.settings.ui/currency-selected]}
+9 -7
View File
@@ -3,16 +3,18 @@
[status-im.currency.core :as models]))
(deftest get-currency
(is (= :usd (models/get-currency {:multiaccount {:currency :usd}})))
(is (= :usd (models/get-currency {:multiaccount {:not-empty "would throw an error if was empty"}})))
(is (= :aud (models/get-currency {:multiaccount {:currency :aud}}))))
(is (= :usd (models/get-currency {:profile/profile {:currency :usd}})))
(is (= :usd (models/get-currency {:profile/profile {:not-empty "would throw an error if was empty"}})))
(is (= :aud (models/get-currency {:profile/profile {:currency :aud}}))))
(deftest set-currency
(let [cofx (models/set-currency {:db {:multiaccount {:not-empty "would throw an error if was empty"}}}
(let [cofx (models/set-currency {:db {:profile/profile {:not-empty
"would throw an error if was empty"}}}
:usd)]
(is (= :usd (get-in cofx [:db :multiaccount :currency]))))
(is (= :usd (get-in cofx [:db :profile/profile :currency]))))
(is
(= :jpy
(get-in (models/set-currency {:db {:multiaccount {:not-empty "would throw an error if was empty"}}}
(get-in (models/set-currency {:db {:profile/profile {:not-empty
"would throw an error if was empty"}}}
:jpy)
[:db :multiaccount :currency]))))
[:db :profile/profile :currency]))))
+1 -1
View File
@@ -2,7 +2,7 @@
(:require [clojure.set :as set]
[status-im.data-store.messages :as messages]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.notification-types :as notification-types]))
[status-im2.contexts.shell.activity-center.notification-types :as notification-types]))
(defn mark-notifications-as-read
[notifications]
@@ -2,7 +2,7 @@
(:require [cljs.test :refer [deftest is testing]]
[status-im2.constants :as constants]
[status-im.data-store.activities :as store]
[status-im2.contexts.activity-center.notification-types :as notification-types]))
[status-im2.contexts.shell.activity-center.notification-types :as notification-types]))
(def chat-id
"0x04c66155")
+10 -10
View File
@@ -83,7 +83,7 @@
{:events [::save-username]}
[{:keys [db] :as cofx} custom-domain? username redirectToSummary]
(let [name (fullname custom-domain? username)
names (get-in db [:multiaccount :usernames] [])
names (get-in db [:profile/profile :usernames] [])
new-names (conj names name)]
(rf/merge cofx
(multiaccounts.update/multiaccount-update
@@ -102,7 +102,7 @@
[{:keys [db]}]
(let [{:keys [username address custom-domain?]} (:ens/registration db)
address (or address (ethereum/default-address db))
{:keys [public-key]} (:multiaccount db)
{:keys [public-key]} (:profile/profile db)
chain-id (ethereum/chain-id db)
username (fullname custom-domain? username)]
(ens/set-pub-key-prepare-tx
@@ -169,7 +169,7 @@
[{:keys [db]} address]
(let [{:keys [username]}
(:ens/registration db)
{:keys [public-key]} (:multiaccount db)
{:keys [public-key]} (:profile/profile db)
chain-id (ethereum/chain-id db)]
(ens/register-prepare-tx
chain-id
@@ -211,7 +211,7 @@
{:events [::set-username-candidate]}
[{:keys [db]} username]
(let [{:keys [custom-domain?]} (:ens/registration db)
usernames (into #{} (get-in db [:multiaccount :usernames]))
usernames (into #{} (get-in db [:profile/profile :usernames]))
state (state custom-domain? username usernames)]
(reset! resolve-last-id (random/id))
(merge
@@ -220,10 +220,10 @@
:username username
:state state)}
(when (= state :searching)
(let [{:keys [multiaccount]} db
{:keys [public-key]} multiaccount
addresses (ethereum/addresses-without-watch db)
chain-id (ethereum/chain-id db)]
(let [{:profile/keys [profile]} db
{:keys [public-key]} profile
addresses (ethereum/addresses-without-watch db)
chain-id (ethereum/chain-id db)]
{::resolve-owner [chain-id
(fullname custom-domain? username)
#(on-resolve-owner
@@ -323,8 +323,8 @@
(rf/defn remove-username
{:events [::remove-username]}
[{:keys [db] :as cofx} name]
(let [names (get-in db [:multiaccount :usernames] [])
preferred-name (get-in db [:multiaccount :preferred-name])
(let [names (get-in db [:profile/profile :usernames] [])
preferred-name (get-in db [:profile/profile :preferred-name])
new-names (remove #(= name %) names)]
(rf/merge cofx
(multiaccounts.update/multiaccount-update
+3 -3
View File
@@ -82,7 +82,7 @@
(defn current-address
[db]
(-> (get-in db [:multiaccount :address])
(-> (get-in db [:profile/profile :address])
normalized-hex))
(defn get-default-account
@@ -91,7 +91,7 @@
(defn default-address
[db]
(-> (get db :multiaccount/accounts)
(-> (get db :profile/wallet-accounts)
get-default-account
:address))
@@ -99,7 +99,7 @@
[db]
(into #{}
(remove #(= (:type %) :watch)
(map #(eip55/address->checksum (:address %)) (get db :multiaccount/accounts)))))
(map #(eip55/address->checksum (:address %)) (get db :profile/wallet-accounts)))))
(defn naked-address
[s]
@@ -401,5 +401,5 @@
[{:keys [db]}]
{:transactions/get-transfers
{:chain-tokens (:wallet/all-tokens db)
:addresses (map :address (get db :multiaccount/accounts))
:addresses (map :address (get db :profile/wallet-accounts))
:fetch-more? false}})
+8 -8
View File
@@ -52,8 +52,8 @@
status-im.wallet.choose-recipient.core
[status-im.wallet.core :as wallet]
status-im.wallet.custom-tokens.core
status-im2.contexts.activity-center.events
status-im2.contexts.activity-center.notification.contact-requests.events
status-im2.contexts.shell.activity-center.events
status-im2.contexts.shell.activity-center.notification.contact-requests.events
status-im2.contexts.shell.jump-to.events
status-im2.contexts.onboarding.events
status-im.chat.models.gaps
@@ -117,11 +117,11 @@
(rf/defn system-theme-mode-changed
{:events [:system-theme-mode-changed]}
[{:keys [db] :as cofx} _]
(let [current-theme-type (get-in cofx [:db :multiaccount :appearance])]
(let [current-theme-type (get-in cofx [:db :profile/profile :appearance])]
(when (and (multiaccounts.model/logged-in? db)
(= current-theme-type status-im2.constants/theme-type-system))
{:multiaccounts.ui/switch-theme-fx
[(get-in db [:multiaccount :appearance])
[(get-in db [:profile/profile :appearance])
(:view-id db) true]})))
(def authentication-options
@@ -146,7 +146,7 @@
[{:keys [db now] :as cofx}]
(let [new-account? (get db :onboarding-2/new-account?)
app-in-background-since (get db :app-in-background-since)
signed-up? (get-in db [:multiaccount :signed-up?])
signed-up? (get-in db [:profile/profile :signed-up?])
biometric-auth? (= (:auth-method db) "biometric")
requires-bio-auth (and
signed-up?
@@ -202,7 +202,7 @@
(cond
(= :chat view-id)
{::async-storage/set! {:chat-id (get-in cofx [:db :current-chat-id])
:key-uid (get-in cofx [:db :multiaccount :key-uid])}
:key-uid (get-in cofx [:db :profile/profile :key-uid])}
:db (assoc db :screens/was-focused-once? true)}
(= :login view-id)
@@ -291,7 +291,7 @@
(rf/defn close-information-box
{:events [:close-information-box]}
[{:keys [db]} id global?]
(let [public-key (get-in db [:multiaccount :public-key])
(let [public-key (get-in db [:profile/profile :public-key])
hash (information-box-id-hash id public-key global?)]
{::async-storage/set! {hash true}
:db (assoc-in db [:information-box-states id] true)}))
@@ -310,7 +310,7 @@
(rf/defn load-information-box-states
{:events [:load-information-box-states]}
[{:keys [db]}]
(let [public-key (get-in db [:multiaccount :public-key])
(let [public-key (get-in db [:profile/profile :public-key])
{:keys [keys hashes]} (reduce (fn [acc {:keys [id global?]}]
(let [hash (information-box-id-hash
id
+1 -1
View File
@@ -75,7 +75,7 @@
(rf/defn save
{:events [:fleet.ui/save-fleet-confirmed]}
[{:keys [db now] :as cofx} fleet]
(let [old-fleet (get-in db [:multiaccount :fleet])]
(let [old-fleet (get-in db [:profile/profile :fleet])]
(when (not= fleet old-fleet)
(rf/merge
cofx
+1 -1
View File
@@ -7,7 +7,7 @@
[re-frame.core :as re-frame]
[status-im2.contexts.chat.events :as chat.events]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.contexts.shell.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
+27 -88
View File
@@ -12,7 +12,6 @@
status-im2.navigation.core
status-im2.subs.root ; so integration tests can run independently
[taoensso.timbre :as log]
[utils.security.core :as security]
[status-im2.constants :as constants]))
(def password "testabc")
@@ -25,7 +24,7 @@
(defn initialize-app!
[]
(rf/dispatch [:setup/app-started]))
(rf/dispatch [:app-started]))
(defn generate-and-derive-addresses!
[]
@@ -37,20 +36,8 @@
(defn assert-app-initialized
[]
(let [app-state @(rf/subscribe [:app-state])
multiaccounts-loading? @(rf/subscribe [:multiaccounts/loading])]
(is (= "active" app-state))
(is (false? multiaccounts-loading?))))
(defn assert-logout
[]
(let [multiaccounts-loading? @(rf/subscribe [:multiaccounts/loading])]
(is multiaccounts-loading?)))
(defn assert-multiaccounts-generated
[]
(let [wizard-state @(rf/subscribe [:intro-wizard/choose-key])]
(is (= 5 (count (:multiaccounts wizard-state))))))
(let [app-state @(rf/subscribe [:app-state])]
(is (= "active" app-state))))
(defn messenger-started
[]
@@ -60,10 +47,6 @@
[]
(is (messenger-started)))
(defn assert-multiaccount-loaded
[]
(is (false? @(rf/subscribe [:multiaccounts/loading]))))
(defn assert-community-created
[]
(is (= @(rf/subscribe [:communities/create]) community)))
@@ -77,7 +60,7 @@
(defn assert-new-account-created
[]
(is (true? (some #(= (:name %) account-name)
@(rf/subscribe [:multiaccount/accounts])))))
@(rf/subscribe [:profile/wallet-accounts])))))
(defn logout!
[]
@@ -86,11 +69,11 @@
(deftest initialize-app-test
(log/info "========= initialize-app-test ==================")
(rf-test/run-test-async
(rf/dispatch [:setup/app-started])
(rf/dispatch [:app-started])
(rf-test/wait-for
;; use initialize-view because it has the longest avg. time and
;; is dispatched by initialize-multiaccounts (last non-view event)
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(assert-app-initialized))))
(deftest create-account-test
@@ -98,29 +81,26 @@
(rf-test/run-test-async
(initialize-app!) ; initialize app
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!) ; generate 5 new keys
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success] ; wait for the keys
(assert-multiaccount-loaded) ; assert keys are generated
(create-multiaccount!) ; create a multiaccount
(rf-test/wait-for ; wait for login
[::transport/messenger-started]
(assert-messenger-started)
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))
(rf-test/wait-for [::logout/logout-method]))))))
(deftest create-community-test
(log/info "====== create-community-test ==================")
(rf-test/run-test-async
(initialize-app!) ; initialize app
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!) ; generate 5 new keys
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded) ; assert keys are generated
(create-multiaccount!) ; create a multiaccount
(rf-test/wait-for ; wait for login
[::transport/messenger-started]
@@ -133,19 +113,17 @@
[:status-im.communities.core/community-created]
(assert-community-created)
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(rf-test/wait-for [::logout/logout-method])))))))
(deftest create-wallet-account-test
(log/info "====== create-wallet-account-test ==================")
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!) ; generate 5 new keys
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded) ; assert keys are generated
(create-multiaccount!) ; create a multiaccount
(rf-test/wait-for ; wait for login
[::transport/messenger-started]
@@ -155,30 +133,28 @@
[:wallet.accounts/account-stored]
(assert-new-account-created) ; assert account was created
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(rf-test/wait-for [::logout/logout-method])))))))
(deftest back-up-seed-phrase-test
(log/info "========= back-up-seed-phrase-test ==================")
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
(assert-messenger-started)
(rf/dispatch-sync [:set-in [:my-profile/seed :step] :12-words]) ; display seed phrase to user
(rf/dispatch-sync [:my-profile/enter-two-random-words]) ; begin prompting user for seed words
(let [ma @(rf/subscribe [:multiaccount])
seed @(rf/subscribe [:my-profile/seed])
word1 (second (:first-word seed))
word2 (second (:second-word seed))]
(is (= 12 (count (string/split (:mnemonic ma) #" ")))) ; assert 12-word seed phrase
(let [{:keys [mnemonic]} @(rf/subscribe [:profile/profile])
seed @(rf/subscribe [:my-profile/seed])
word1 (second (:first-word seed))
word2 (second (:second-word seed))]
(is (= 12 (count (string/split mnemonic #" ")))) ; assert 12-word seed phrase
(rf/dispatch-sync [:set-in [:my-profile/seed :word] word1])
(rf/dispatch-sync [:my-profile/set-step :second-word])
(rf/dispatch-sync [:set-in [:my-profile/seed :word] word2])
@@ -188,42 +164,13 @@
[:my-profile/finish-success]
(is (nil? @(rf/subscribe [:mnemonic]))) ; assert seed phrase has been removed
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))))
(rf-test/wait-for [::logout/logout-method]))))))))
(def multiaccount-name "Narrow Frail Lemming")
(def multiaccount-mnemonic
"tattoo ramp health green tongue universe style vapor become tape lava reason")
(def multiaccount-key-uid "0x694b8229524820a3a00a6e211141561d61b251ad99d6b65daf82a73c9a57697b")
(deftest recover-multiaccount-test
(log/info "========= recover-multiaccount-test ==================")
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
(rf/dispatch-sync [:init-root :onboarding])
(rf/dispatch-sync [:multiaccounts.recover.ui/recover-multiaccount-button-pressed])
(rf/dispatch-sync [:status-im.multiaccounts.recover.core/enter-phrase-pressed])
(rf/dispatch-sync [:multiaccounts.recover/enter-phrase-input-changed
(security/mask-data multiaccount-mnemonic)])
(rf/dispatch [:multiaccounts.recover/enter-phrase-next-pressed])
(rf-test/wait-for
[:status-im.multiaccounts.recover.core/import-multiaccount-success]
(rf/dispatch-sync [:multiaccounts.recover/re-encrypt-pressed])
(rf/dispatch [:multiaccounts.recover/enter-password-next-pressed password])
(rf-test/wait-for
[:status-im.multiaccounts.recover.core/store-multiaccount-success]
(let [multiaccount @(rf/subscribe [:multiaccount])] ; assert multiaccount is recovered
(is (= multiaccount-key-uid (:key-uid multiaccount)))
(is (= multiaccount-name (:name multiaccount))))
(rf-test/wait-for ; wait for login
[::transport/messenger-started]
(assert-messenger-started)
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(def chat-id
"0x0402905bed83f0bbf993cee8239012ccb1a8bc86907ead834c1e38476a0eda71414eed0e25f525f270592a2eebb01c9119a4ed6429ba114e51f5cb0a28dae1adfd")
@@ -232,11 +179,10 @@
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success] ; wait for the keys
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
@@ -247,19 +193,17 @@
(rf/dispatch-sync [:chat/navigate-to-chat chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(rf-test/wait-for [::logout/logout-method])))))))
(deftest delete-chat-test
(log/info "========= delete-chat-test ==================")
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success] ; wait for the keys
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
@@ -273,19 +217,17 @@
(rf/dispatch-sync [:chat.ui/show-remove-confirmation chat-id])
(rf/dispatch-sync [:chat.ui/remove-chat chat-id])
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(rf-test/wait-for [::logout/logout-method])))))))
(deftest mute-chat-test
(log/info "========= mute-chat-test ==================")
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success] ; wait for the keys
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
@@ -305,8 +247,7 @@
[:chat/mute-successfully]
(is (not @(rf/subscribe [:chats/muted chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))))
(rf-test/wait-for [::logout/logout-method])))))))))
(deftest add-contact-test
(log/info "========= add-contact-test ==================")
@@ -318,11 +259,10 @@
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
[:profile/get-profiles-overview-success]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
@@ -343,5 +283,4 @@
(let [contact @(rf/subscribe [:contacts/current-contact])]
(is (= three-words-name (:primary-name contact))))
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))))))
(rf-test/wait-for [::logout/logout-method]))))))))))
+3 -3
View File
@@ -17,7 +17,7 @@
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :creating-backup?] backup-type))}
(when (:multiaccount db)
(when (:profile/profile db)
(navigation/navigate-to :my-profile nil))
(navigation/navigate-to :seed-phrase nil)))
@@ -48,7 +48,7 @@
{:events [::start-keycard-backup]}
[{:keys [db] :as cofx}]
{::multiaccounts.recover/import-multiaccount {:passphrase (-> db
:multiaccounts/key-storage
:profile/key-storage
:seed-phrase
mnemonic/sanitize-passphrase)
:password nil
@@ -66,7 +66,7 @@
:recovering? true
:selected-storage-type :advanced)
(assoc-in [:keycard :flow] :recovery)
(update :multiaccounts/key-storage dissoc :seed-phrase))
(update :profile/key-storage dissoc :seed-phrase))
:dismiss-keyboard nil}
(common/listen-to-hardware-back-button)
(navigation/navigate-to :keycard-onboarding-intro nil)))
+1 -1
View File
@@ -152,7 +152,7 @@
(if puk-restore?
(navigation/navigate-to :multiaccounts nil)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))
(when (:multiaccounts/login db)
(when (:profile/login db)
(common/get-keys-from-keycard)))))
(rf/defn on-change-puk-success
+14 -14
View File
@@ -52,7 +52,7 @@
:init
has-master-key?
:multiaccount
:profile/profile
(and (not paired?)
(zero? free-pairing-slots))
@@ -68,7 +68,7 @@
(defn find-multiaccount-by-keycard-instance-uid
[db keycard-instance-uid]
(when keycard-instance-uid
(->> (:multiaccounts/multiaccounts db)
(->> (:profile/profiles-overview db)
vals
(filter #(= keycard-instance-uid (:keycard-instance-uid %)))
first)))
@@ -76,7 +76,7 @@
(defn find-multiaccount-by-key-uid
[db key-uid]
(when key-uid
(->> (:multiaccounts/multiaccounts db)
(->> (:profile/profiles-overview db)
vals
(filter #(= (ethereum/normalized-hex key-uid) (:key-uid %)))
first)))
@@ -86,7 +86,7 @@
(get-pairing db (get-in db [:keycard :application-info :key-uid])))
([db key-uid]
(or
(get-in db [:multiaccount :keycard-pairing])
(get-in db [:profile/profile :keycard-pairing])
(get-in db [:keycard :secrets :pairing])
(when key-uid
(:keycard-pairing
@@ -324,7 +324,7 @@
(rf/defn get-keys-from-keycard
[{:keys [db]}]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
(let [key-uid (get-in db [:profile/login :key-uid])
pin (string/join (get-in db [:keycard :pin :login]))]
(log/debug "[keycard] get-keys-from-keycard"
", not empty pin:"
@@ -339,11 +339,11 @@
(let [{:keys [key-uid encryption-public-key whisper-private-key]
:as account-data}
(js->clj data :keywordize-keys true)
{:keys [name]} (get-in db [:multiaccounts/multiaccounts key-uid])
{:keys [name]} (get-in db [:profile/profiles-overview key-uid])
key-uid (get-in db [:keycard :application-info :key-uid])
multiaccount-data (types/clj->json {:name name
:key-uid key-uid})
save-keys? (get-in db [:multiaccounts/login :save-password?])]
save-keys? (get-in db [:profile/login :save-password?])]
(rf/merge cofx
{:db
(-> db
@@ -353,13 +353,13 @@
assoc
:puk-retry-counter 5
:pin-retry-counter 3)
(assoc-in [:keycard :multiaccount]
(assoc-in [:keycard :profile/profile]
(update account-data :whisper-public-key ethereum/normalized-hex))
(assoc-in [:keycard :flow] nil)
(update :multiaccounts/login assoc
:password encryption-public-key
:key-uid key-uid
:name name))
(update :profile/login assoc
:password encryption-public-key
:key-uid key-uid
:name name))
:keycard/login-with-keycard {:multiaccount-data multiaccount-data
:password encryption-public-key
@@ -379,7 +379,7 @@
(hide-connection-sheet)
; do not try to display the popover if it is already open or
; we are in the login interface (which has a different handling)
(when-not (or (:multiaccounts/login db) (:popover/popover db))
(when-not (or (:profile/login db) (:popover/popover db))
(popover/show-popover {:view card-status}))))
(rf/defn blocked-keycard-popup
@@ -536,7 +536,7 @@
(defn keycard-multiaccount?
[db]
(boolean (get-in db [:multiaccount :keycard-pairing])))
(boolean (get-in db [:profile/profile :keycard-pairing])))
(rf/defn verify-pin
{:events [:keycard/verify-pin]}
+3 -3
View File
@@ -543,7 +543,7 @@
:not-paired :pair
:no-pairing-slots :no-slots
:init :card-ready
:multiaccount :import-multiaccount
:profile/profile :import-multiaccount
:begin))})
(rf/defn show-no-keycard-applet-alert
@@ -586,7 +586,7 @@
(common/clear-on-card-read)
(load-pin-screen)))))
(when (and (= card-state :multiaccount)
(when (and (= card-state :profile/profile)
(= flow :import))
(if (common/find-multiaccount-by-key-uid db key-uid)
(multiaccounts.recover/show-existing-multiaccount-alert key-uid)
@@ -599,7 +599,7 @@
(navigation/navigate-to :keycard-recovery-no-key nil)
(show-no-keycard-applet-alert)))
(when (and (= card-state :multiaccount)
(when (and (= card-state :profile/profile)
(#{:create :recovery} flow))
(show-keycard-has-multiaccount-alert)))))
+1 -1
View File
@@ -62,7 +62,7 @@
"04f2a432677a1b7c4f1bb22078135821d1d10fce23422297b5c808a545f2b61cdba38ee7394762172fc6ff5e9e28db7535e555efe2812905ffd4e0c25e82a98ae8"
"whisper-address" "87df2285f90b71221fab6267b7cb37532fedbb1f"
"wallet-address" "7e92236392a850980d00d0cd2a4b92886bd7fe7b"})
[:db :keycard :multiaccount])
[:db :keycard :profile/profile])
[:whisper-private-key
:whisper-public-key
:encryption-public-key
+1 -1
View File
@@ -11,7 +11,7 @@
(rf/defn delete-card
[{:keys [db] :as cofx}]
(let [key-uid (get-in db [:keycard :application-info :key-uid])
multiaccount-key-uid (get-in db [:multiaccount :key-uid])]
multiaccount-key-uid (get-in db [:profile/profile :key-uid])]
(if (and key-uid
(= key-uid multiaccount-key-uid))
{:keycard/delete nil}
+10 -10
View File
@@ -69,9 +69,9 @@
:error nil
:status nil))
:hide-popover nil})
(when (:multiaccount db)
(when (:profile/profile db)
(navigation/navigate-to :my-profile nil))
(when-not (:multiaccounts/login db)
(when-not (:profile/login db)
(if (:popover/popover db)
(navigation/navigate-replace :keycard-pin nil)
(navigation/navigate-to :keycard-pin nil)))))
@@ -94,7 +94,7 @@
key-uid (get-in db [:keycard :application-info :key-uid])
paired? (get-in db [:keycard :application-info :paired?])
multiaccount (get-in db
[:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :key-uid])])
[:profile/profiles-overview (get-in db [:profile/login :key-uid])])
multiaccount-key-uid (get multiaccount :key-uid)
multiaccount-mismatch? (or (nil? multiaccount)
(not= multiaccount-key-uid key-uid))]
@@ -151,7 +151,7 @@
:multiaccounts-stack
[:multiaccounts
:keycard-login-pin])
(let [{:keys [name]} (get-in db [:multiaccounts/multiaccounts key-uid])
(let [{:keys [name]} (get-in db [:profile/profiles-overview key-uid])
multiaccount-data (types/clj->json {:name name
:key-uid key-uid})
account-data {:key-uid key-uid
@@ -161,14 +161,14 @@
(-> db
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :pin :login] [])
(assoc-in [:keycard :multiaccount]
(assoc-in [:keycard :profile/profile]
(update account-data :whisper-public-key ethereum/normalized-hex))
(assoc-in [:keycard :flow] nil)
(update :multiaccounts/login assoc
:password encryption-public-key
:key-uid key-uid
:name name
:save-password? true))
(update :profile/login assoc
:password encryption-public-key
:key-uid key-uid
:name name
:save-password? true))
:keycard/login-with-keycard
{:multiaccount-data multiaccount-data
:key-uid key-uid
+16 -15
View File
@@ -134,7 +134,7 @@
(rf/defn intro-wizard
{:events [:multiaccounts.create.ui/intro-wizard]}
[{:keys [db] :as cofx}]
(let [accs (get db :multiaccounts/multiaccounts)]
(let [accs (get db :profile/profiles-overview)]
(rf/merge cofx
{:db (-> db
(update :keycard dissoc :flow)
@@ -157,7 +157,7 @@
:interceptors [(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
[{:keys [db] :as cofx}]
(let [{{:keys [multiaccount secrets flow]} :keycard} db
(let [{{:keys [secrets flow] :profile/keys [profile]} :keycard} db
{:keys [address
name
public-key
@@ -172,7 +172,7 @@
instance-uid
key-uid
recovered]}
multiaccount
profile
{:keys [pairing paired-on]} secrets
{:keys [name]}
(if (nil? name)
@@ -238,7 +238,7 @@
(multiaccounts.model/logged-in? db)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
(:multiaccounts/login db)
(:profile/login db)
(return-to-keycard-login)
:else
@@ -263,9 +263,9 @@
[{:keys [db] :as cofx}]
(let [pairing (get-in db [:keycard :secrets :pairing])
paired-on (get-in db [:keycard :secrets :paired-on])
instance-uid (get-in db [:keycard :multiaccount :instance-uid])
instance-uid (get-in db [:keycard :profile/profile :instance-uid])
account (-> db
:multiaccounts/login
:profile/login
(assoc :keycard-pairing pairing)
(assoc :save-password? false))
key-uid (-> account :key-uid)
@@ -275,14 +275,15 @@
password (ethereum/sha3 (security/safe-unmask-data (get-in db
[:keycard
:migration-password])))
encryption-pass (get-in db [:keycard :multiaccount :encryption-public-key])
encryption-pass (get-in db [:keycard :profile/profile :encryption-public-key])
login-params {:key-uid key-uid
:multiaccount-data (types/clj->json account)
:password encryption-pass
:chat-key (get-in db [:keycard :multiaccount :whisper-private-key])}]
:chat-key (get-in db
[:keycard :profile/profile :whisper-private-key])}]
{:db (-> db
(assoc-in [:multiaccounts/multiaccounts key-uid :keycard-pairing] pairing)
(assoc :multiaccounts/login account)
(assoc-in [:profile/profiles-overview key-uid :keycard-pairing] pairing)
(assoc :profile/login account)
(assoc :auth-method keychain/auth-method-none)
(update :keycard dissoc :flow :migration-password)
(dissoc :recovered-account?))
@@ -290,7 +291,7 @@
(rf/defn delete-multiaccount
[{:keys [db]}]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])]
(let [key-uid (get-in db [:profile/login :key-uid])]
{:keycard/delete-multiaccount-before-migration
{:key-uid key-uid
:on-error #(re-frame/dispatch [::delete-multiaccount-error %])
@@ -313,7 +314,7 @@
cofx
{:db (-> db
(assoc-in
[:keycard :multiaccount]
[:keycard :profile/profile]
(-> account-data
(update :address ethereum/normalized-hex)
(update :whisper-address ethereum/normalized-hex)
@@ -323,7 +324,7 @@
(update :whisper-public-key ethereum/normalized-hex)
(update :wallet-public-key ethereum/normalized-hex)
(update :wallet-root-public-key ethereum/normalized-hex)
(update :instance-uid #(get-in db [:keycard :multiaccount :instance-uid] %))))
(update :instance-uid #(get-in db [:keycard :profile/profile :instance-uid] %))))
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
(assoc-in [:keycard :pin :status] nil)
@@ -362,7 +363,7 @@
pin (common/vector->string (get-in db [:keycard :pin :import-multiaccount]))]
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :multiaccount :instance-uid] instance-uid)
(assoc-in [:keycard :profile/profile :instance-uid] instance-uid)
(assoc-in [:keycard :pin :status] :verifying)
(assoc-in [:keycard :secrets]
{:pairing pairing'
@@ -387,7 +388,7 @@
(rf/merge
cofx
{:db (update-in db
[:keycard :multiaccount]
[:keycard :profile/profile]
(fn [multiacc]
(assoc multiacc
:recovered (get db :recovered-account?)
+2 -2
View File
@@ -12,7 +12,7 @@
{:events [:keycard/sign]}
[{:keys [db] :as cofx} hash on-success]
(let [card-connected? (get-in db [:keycard :card-connected?])
key-uid (get-in db [:multiaccount :key-uid])
key-uid (get-in db [:profile/profile :key-uid])
keycard-key-uid (get-in db [:keycard :application-info :key-uid])
keycard-pin-retries (get-in db [:keycard :application-info :pin-retry-counter])
keycard-match? (= key-uid keycard-key-uid)
@@ -28,7 +28,7 @@
(when (ethereum/address= from address)
(reduced path)))
nil
(:multiaccount/accounts db))]
(:profile/wallet-accounts db))]
(cond
(not keycard-match?)
(common/show-wrong-keycard-alert cofx)
+6 -6
View File
@@ -44,7 +44,7 @@
:initialized? true
:pin-retry-counter 3
:puk-retry-counter 5
:key-uid (get-in @re-frame.db/app-db [:multiaccounts/login :key-uid])})
:key-uid (get-in @re-frame.db/app-db [:profile/login :key-uid])})
(swap! state assoc :pin default-pin :puk default-puk :password kk1-password)
(connect-card))
@@ -389,11 +389,11 @@
pin
on-failure
#(let [{:keys [key-uid wallet-root-address]}
(get @re-frame.db/app-db :multiaccount)
accounts (get @re-frame.db/app-db :multiaccount/accounts)
(get @re-frame.db/app-db :profile/profile)
accounts (get @re-frame.db/app-db :profile/wallet-accounts)
hashed-password account-password
path-num (inc (get-in @re-frame.db/app-db
[:multiaccount :latest-derived-path]))
[:profile/profile :latest-derived-path]))
path (str "m/" path-num)]
(native-module/multiaccount-load-account
wallet-root-address
@@ -460,8 +460,8 @@
(when (= path (:path acc))
(reduced address)))
nil
(:multiaccount/accounts @re-frame.db/app-db))
(-> (:multiaccount/accounts @re-frame.db/app-db)
(:profile/wallet-accounts @re-frame.db/app-db))
(-> (:profile/wallet-accounts @re-frame.db/app-db)
first
:address))
password account-password]
+27 -27
View File
@@ -2,7 +2,6 @@
(:require [re-frame.core :as re-frame]
[utils.i18n :as i18n]
[status-im.keycard.common :as common]
[status-im.multiaccounts.key-storage.core :as key-storage]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]
@@ -119,36 +118,37 @@
(defn handle-account-removal
[{:keys [db] :as cofx} keys-removed-from-card?]
(let [key-uid (get-in db [:multiaccount :key-uid])
(let [key-uid (get-in db [:profile/profile :key-uid])
instance-uid (get-in db [:keycard :application-info :instance-uid])
pairings (get-in db [:keycard :pairings])]
(rf/merge
cofx
{:db (-> db
(update :multiaccounts/multiaccounts dissoc key-uid)
(assoc-in [:keycard :secrets] nil)
(update-in [:keycard :pairings]
dissoc
(keyword instance-uid))
(update-in [:keycard :pairings] dissoc instance-uid)
(assoc-in [:keycard :whisper-public-key] nil)
(assoc-in [:keycard :wallet-address] nil)
(assoc-in [:keycard :application-info] nil)
(assoc-in [:keycard :pin]
{:status nil
:error-label nil
:on-verified nil}))
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
:utils/show-popup {:title (i18n/label (if keys-removed-from-card?
:t/profile-deleted-title
:t/database-reset-title))
:content (i18n/label (if keys-removed-from-card?
:t/profile-deleted-keycard
:t/database-reset-content))
:on-dismiss #(re-frame/dispatch [:logout])}
::key-storage/delete-multiaccount {:key-uid key-uid
:on-success #(log/debug "[keycard] remove account ok")
:on-error #(log/warn "[keycard] remove account: " %)}}
{:db (-> db
(update :profile/profiles-overview dissoc key-uid)
(assoc-in [:keycard :secrets] nil)
(update-in [:keycard :pairings]
dissoc
(keyword instance-uid))
(update-in [:keycard :pairings] dissoc instance-uid)
(assoc-in [:keycard :whisper-public-key] nil)
(assoc-in [:keycard :wallet-address] nil)
(assoc-in [:keycard :application-info] nil)
(assoc-in [:keycard :pin]
{:status nil
:error-label nil
:on-verified nil}))
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
:utils/show-popup {:title (i18n/label (if keys-removed-from-card?
:t/profile-deleted-title
:t/database-reset-title))
:content (i18n/label (if keys-removed-from-card?
:t/profile-deleted-keycard
:t/database-reset-content))
:on-dismiss #(re-frame/dispatch [:logout])}}
;;should be reimplemented
;;:key-storage/delete-profile {:key-uid key-uid
;;:on-success #(log/debug "[keycard] remove account ok")
;; :on-error #(log/warn "[keycard] remove account: " %)}
(common/clear-on-card-connected)
(common/hide-connection-sheet))))
+1 -1
View File
@@ -34,7 +34,7 @@
(rf/defn generate-new-keycard-account
{:events [:wallet.accounts/generate-new-keycard-account]}
[{:keys [db]}]
(let [path-num (inc (get-in db [:multiaccount :latest-derived-path]))
(let [path-num (inc (get-in db [:profile/profile :latest-derived-path]))
path (str constants/path-wallet-root "/" path-num)
pin (common/vector->string (get-in db [:keycard :pin :export-key]))]
{:db
+1 -1
View File
@@ -8,7 +8,7 @@
(rf/defn save-log-level
{:events [:log-level.ui/change-log-level-confirmed]}
[{:keys [db now] :as cofx} log-level]
(let [old-log-level (get-in db [:multiaccount :log-level])]
(let [old-log-level (get-in db [:profile/profile :log-level])]
(when (not= old-log-level log-level)
(rf/merge cofx
(multiaccounts.update/multiaccount-update
+9 -9
View File
@@ -36,7 +36,7 @@
(defn preferred-mailserver-id
[db]
(get-in db [:multiaccount :pinned-mailservers (node/current-fleet-key db)]))
(get-in db [:profile/profile :pinned-mailservers (node/current-fleet-key db)]))
(defn connection-error-dismissed
[db]
@@ -61,7 +61,7 @@
(defn fetch-use-mailservers?
[{:keys [db]}]
(get-in db [:multiaccount :use-mailservers?]))
(get-in db [:profile/profile :use-mailservers?]))
(defonce showing-connection-error-popup? (atom false))
@@ -105,7 +105,7 @@
[{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
error-dismissed? (connection-error-dismissed db)
pinned-mailserver (get-in db [:multiaccount :pinned-mailservers current-fleet])]
pinned-mailserver (get-in db [:profile/profile :pinned-mailservers current-fleet])]
(when (and pinned-mailserver
(not error-dismissed?)
(not @showing-connection-error-popup?))
@@ -266,9 +266,9 @@
(rf/defn upsert
{:events [:mailserver.ui/save-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:mailserver.edit/keys [mailserver] :keys [multiaccount] :as db} :db
random-id-generator :random-id-generator
:as cofx}]
[{{:mailserver.edit/keys [mailserver] :profile/keys [profile] :as db} :db
random-id-generator :random-id-generator
:as cofx}]
(let [{:keys [name url id]} mailserver
current-fleet (node/current-fleet-key db)]
@@ -364,7 +364,7 @@
{:events [:mailserver.ui/connect-confirmed]}
[{:keys [db] :as cofx} current-fleet mailserver-id]
(let [pinned-mailservers (-> db
(get-in [:multiaccount :pinned-mailservers])
(get-in [:profile/profile :pinned-mailservers])
(assoc current-fleet mailserver-id))]
(rf/merge cofx
{:db (assoc db :mailserver/current-id mailserver-id)
@@ -379,7 +379,7 @@
[{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
pinned-mailservers (-> db
(get-in [:multiaccount :pinned-mailservers])
(get-in [:profile/profile :pinned-mailservers])
(dissoc current-fleet))]
(rf/merge cofx
{:json-rpc/call [{:method "wakuext_setPinnedMailservers"
@@ -396,7 +396,7 @@
[{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
mailserver-id (:mailserver/current-id db)
pinned-mailservers (get-in db [:multiaccount :pinned-mailservers])]
pinned-mailservers (get-in db [:profile/profile :pinned-mailservers])]
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:pinned-mailservers
+4 -4
View File
@@ -12,7 +12,7 @@
(rf/defn sheet-defaults
[{:keys [db]}]
(let [remember-choice? (get-in db [:multiaccount :remember-syncing-choice?])]
(let [remember-choice? (get-in db [:profile/profile :remember-syncing-choice?])]
{:db (assoc db
:mobile-network/remember-choice?
(or (nil? remember-choice?)
@@ -22,7 +22,7 @@
[{:keys [db] :as cofx}]
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? db)
{:keys [remember-syncing-choice?]} (:multiaccount db)]
{:keys [remember-syncing-choice?]} (:profile/profile db)]
(apply
rf/merge
cofx
@@ -91,13 +91,13 @@
(rf/defn mobile-network-set-syncing
{:events [:mobile-network/set-syncing]}
[{:keys [db] :as cofx} syncing?]
(let [{:keys [remember-syncing-choice?]} (:multiaccount db)]
(let [{:keys [remember-syncing-choice?]} (:profile/profile db)]
((apply-settings syncing? remember-syncing-choice?) cofx)))
(rf/defn mobile-network-ask-on-mobile-network?
{:events [:mobile-network/ask-on-mobile-network?]}
[{:keys [db] :as cofx} ask?]
(let [{:keys [syncing-on-mobile-network?]} (:multiaccount db)]
(let [{:keys [syncing-on-mobile-network?]} (:profile/profile db)]
((apply-settings syncing-on-mobile-network? (not ask?)) cofx)))
(rf/defn mobile-network-restore-defaults
@@ -101,7 +101,7 @@
(.catch #(cb (generate-error-result %))))))
(re-frame/reg-fx
:get-supported-biometric-auth
:biometric/get-supported-biometric-auth
(fn []
(let [callback #(re-frame/dispatch [:init.callback/get-supported-biometric-auth-success %])]
;;NOTE: if we can't save user password, we can't support biometrics
@@ -149,8 +149,8 @@
(rf/defn update-biometric
[{db :db :as cofx} biometric-auth?]
(let [key-uid (or (get-in db [:multiaccount :key-uid])
(get-in db [:multiaccounts/login :key-uid]))]
(let [key-uid (or (get-in db [:profile/profile :key-uid])
(get-in db [:profile/login :key-uid]))]
(rf/merge cofx
(keychain/save-auth-method
key-uid
@@ -214,7 +214,7 @@
cofx
{:db (-> db
(assoc :auth-method keychain/auth-method-none)
(assoc-in [:multiaccounts/login :save-password?] false))}
(assoc-in [:profile/login :save-password?] false))}
(popover/hide-popover)))
(rf/defn setup-done
+6 -6
View File
@@ -120,7 +120,7 @@
(rf/defn switch-preview-privacy-mode-flag
[{:keys [db]}]
(let [private? (get-in db [:multiaccount :preview-privacy?])]
(let [private? (get-in db [:profile/profile :preview-privacy?])]
{::blank-preview-flag-changed private?}))
(re-frame/reg-fx
@@ -153,7 +153,7 @@
{:events [:multiaccounts.ui/switch-theme]}
[cofx theme view-id]
(let [theme (or theme
(get-in cofx [:db :multiaccount :appearance])
(get-in cofx [:db :profile/profile :appearance])
constants/theme-type-dark)]
{:multiaccounts.ui/switch-theme-fx [theme view-id false]}))
@@ -180,7 +180,7 @@
(rf/defn save-profile-picture
{:events [::save-profile-picture]}
[cofx path ax ay bx by]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(let [key-uid (get-in cofx [:db :profile/profile :key-uid])]
(rf/merge cofx
{:json-rpc/call [{:method "multiaccounts_storeIdentityImage"
:params [key-uid (clean-path path) ax ay bx by]
@@ -191,7 +191,7 @@
(rf/defn save-profile-picture-from-url
{:events [::save-profile-picture-from-url]}
[cofx url]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(let [key-uid (get-in cofx [:db :profile/profile :key-uid])]
(rf/merge cofx
{:json-rpc/call [{:method "multiaccounts_storeIdentityImageFromURL"
:params [key-uid url]
@@ -207,7 +207,7 @@
(rf/defn delete-profile-picture
{:events [::delete-profile-picture]}
[cofx name]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(let [key-uid (get-in cofx [:db :profile/profile :key-uid])]
(rf/merge cofx
{:json-rpc/call [{:method "multiaccounts_deleteIdentityImage"
:params [key-uid]
@@ -219,7 +219,7 @@
(rf/defn get-profile-picture
[cofx]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(let [key-uid (get-in cofx [:db :profile/profile :key-uid])]
{:json-rpc/call [{:method "multiaccounts_getIdentityImages"
:params [key-uid]
:on-success #(re-frame/dispatch [::update-local-picture %])}]}))
+3 -3
View File
@@ -225,13 +225,13 @@
:keycard-pairing keycard-pairing
:keycard-paired-on keycard-paired-on))
db (assoc db
:multiaccounts/login {:key-uid key-uid
:profile/login {:key-uid key-uid
:name name
:password password
:creating? true
:processing true}
:multiaccount new-multiaccount
:multiaccount/accounts [wallet-account]
:profile/profile new-multiaccount
:profile/wallet-accounts [wallet-account]
:networks/current-network config/default-network
:networks/networks (data-store.settings/rpc->networks config/default-networks))
settings (assoc new-multiaccount
@@ -1,150 +1,13 @@
(ns status-im.multiaccounts.key-storage.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.events :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.mnemonic :as mnemonic]
[utils.i18n :as i18n]
[status-im.keycard.backup-key :as keycard.backup]
[status-im.keycard.common :as common]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.multiaccounts.logout.core :as multiaccounts.logout]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
[native-module.core :as native-module]
[status-im.popover.core :as popover]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[status-im2.navigation.events :as navigation]
[utils.security.core :as security]))
(rf/defn key-and-storage-management-pressed
"This event can be dispatched before login and from profile and needs to redirect accordingly"
{:events [::key-and-storage-management-pressed]}
[{:keys [db] :as cofx}]
(navigation/navigate-to
cofx
(if (multiaccounts.model/logged-in? db)
:actions-logged-in
:actions-not-logged-in)
nil))
(rf/defn move-keystore-checked
{:events [::move-keystore-checked]}
[{:keys [db] :as cofx} checked?]
{:db (assoc-in db [:multiaccounts/key-storage :move-keystore-checked?] checked?)})
(rf/defn reset-db-checked
{:events [::reset-db-checked]}
[{:keys [db] :as cofx} checked?]
{:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] checked?)})
(rf/defn navigate-back
{:events [::navigate-back]}
[{:keys [db] :as cofx}]
(rf/merge
cofx
{:db (-> db
(dissoc :recovered-account?)
(update :keycard
dissoc
:from-key-storage-and-migration?
:creating-backup?
:factory-reset-card?))}
(navigation/navigate-back)))
(rf/defn enter-seed-pressed
"User is logged out and probably wants to move multiaccount to Keycard. Navigate to enter seed phrase screen"
{:events [::enter-seed-pressed]}
[{:keys [db] :as cofx}]
(rf/merge
cofx
{:db (assoc db :recovered-account? true)}
(navigation/navigate-to :seed-phrase nil)))
(rf/defn seed-phrase-input-changed
{:events [::seed-phrase-input-changed]}
[{:keys [db] :as cofx} masked-seed-phrase]
(let [seed-phrase (security/safe-unmask-data masked-seed-phrase)]
{:db (update db
:multiaccounts/key-storage assoc
:seed-phrase (when seed-phrase
(string/lower-case seed-phrase))
:seed-shape-invalid? (or (empty? seed-phrase)
(not (mnemonic/valid-length? seed-phrase)))
:seed-word-count (mnemonic/words-count seed-phrase))}))
(rf/defn key-uid-seed-mismatch
{:events [::show-seed-key-uid-mismatch-error-popup]}
[cofx _]
(popover/show-popover cofx {:view :seed-key-uid-mismatch}))
(rf/defn key-uid-matches
{:events [::key-uid-matches]}
[{:keys [db] :as cofx} _]
(let [backup? (get-in db [:keycard :creating-backup?])]
(if backup?
(keycard.backup/start-keycard-backup cofx)
(navigation/navigate-to cofx :storage nil))))
(defn validate-seed-against-key-uid
"Check if the key-uid was generated with the given seed-phrase"
[{:keys [import-mnemonic-fn on-success on-error]} {:keys [seed-phrase key-uid]}]
(import-mnemonic-fn
(mnemonic/sanitize-passphrase seed-phrase)
nil
(fn [result]
(let [{:keys [keyUid]} (types/json->clj result)]
;; if the key-uid from app-db is same as the one returned by multiaccount import,
;; it means that this seed was used to generate this multiaccount
(if (= key-uid keyUid)
(on-success)
(on-error))))))
(re-frame/reg-fx
::validate-seed-against-key-uid
(partial validate-seed-against-key-uid
{:import-mnemonic-fn native-module/multiaccount-import-mnemonic
:on-success #(re-frame/dispatch [::key-uid-matches])
:on-error #(re-frame/dispatch [::show-seed-key-uid-mismatch-error-popup])}))
(rf/defn seed-phrase-validated
{:events [::seed-phrase-validated]}
[{:keys [db] :as cofx} validation-error]
(let [error? (-> validation-error
types/json->clj
:error
string/blank?
not)
onboarding? (not (or (:multiaccounts/login db) (:multiaccount db)))]
(if error?
(popover/show-popover cofx {:view :custom-seed-phrase})
{::validate-seed-against-key-uid {:seed-phrase (-> db :multiaccounts/key-storage :seed-phrase)
;; Unique key-uid of the account for which we are going to move
;; keys
:key-uid (or (-> db :multiaccounts/login :key-uid)
(-> db :multiaccount :key-uid)
(and onboarding?
(-> db
:keycard
:application-info
:key-uid)))}})))
(rf/defn choose-storage-pressed
{:events [::choose-storage-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [seed-phrase]} (:multiaccounts/key-storage db)]
{::multiaccounts/validate-mnemonic
[(mnemonic/sanitize-passphrase seed-phrase)
#(re-frame/dispatch [::seed-phrase-validated %])]}))
(rf/defn keycard-storage-pressed
{:events [::keycard-storage-pressed]}
[{:keys [db]} selected?]
{:db (assoc-in db [:multiaccounts/key-storage :keycard-storage-selected?] selected?)})
(re-frame/reg-fx
::delete-imported-key
:key-storage/delete-imported-key
(fn [{:keys [key-uid address password on-success on-error]}]
(let [hashed-pass (ethereum/sha3 (security/safe-unmask-data password))]
(native-module/delete-imported-key
@@ -156,132 +19,3 @@
(if-not (string/blank? error)
(on-error error)
(on-success))))))))
#_"Multiaccount has been deleted from device. We now need to emulate the restore seed phrase process, and make the user land on Keycard setup screen.
To ensure that keycard setup works, we need to:
1. Import multiaccount, derive required keys and save them at the correct location in app-db
2. Take the user to :keycard-onboarding-intro screen in :intro-login-stack
The exact events dispatched for this flow if consumed from the UI are:
:m.r/enter-phrase-input-changed
:m.r/enter-phrase-next-pressed
:m.r/re-encrypt-pressed
:i/on-key-storage-selected ([:intro-wizard :selected-storage-type] is set to :advanced)
:m.r/select-storage-next-pressed
We don't need to take the exact steps, just set the required state and redirect to correct screen
"
(rf/defn import-multiaccount
[{:keys [db] :as cofx}]
{:dispatch [:bottom-sheet/hide-old]
::multiaccounts.recover/import-multiaccount
{:passphrase (get-in db [:multiaccounts/key-storage :seed-phrase])
:password nil
:success-event ::import-multiaccount-success}})
(rf/defn delete-multiaccount-and-init-keycard-onboarding
{:events [::delete-multiaccount-and-init-keycard-onboarding]}
[{:keys [db] :as cofx}]
(rf/merge
{:dispatch [:bottom-sheet/hide-old]
:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] true)}
(import-multiaccount)))
(rf/defn storage-selected
{:events [::storage-selected]}
[{:keys [db] :as cofx}]
(if (get-in db [:multiaccounts/key-storage :reset-db-checked?])
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning})
(bottom-sheet/hide-bottom-sheet-old cofx)))
(rf/defn skip-password-pressed
{:events [::skip-password-pressed]}
[cofx]
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning}))
(rf/defn password-changed
{:events [::password-changed]}
[{db :db} password]
(let [unmasked-pass (security/safe-unmask-data password)]
{:db (update db
:keycard assoc
:migration-password password
:migration-password-error nil
:migration-password-valid? (and unmasked-pass (> (count unmasked-pass) 5)))}))
(rf/defn verify-password-result
{:events [::verify-password-result]}
[{:keys [db] :as cofx} result]
(let [{:keys [error]} (types/json->clj result)]
(if (string/blank? error)
(rf/merge
cofx
{:db (update db :keycard dissoc :migration-password-error :migration-password-valid?)}
(import-multiaccount))
{:db (assoc-in db [:keycard :migration-password-error] (i18n/label :t/wrong-password))})))
(rf/defn verify-password
{:events [::verify-password]}
[{:keys [db] :as cofx}]
(native-module/verify-database-password
(get-in db [:multiaccounts/login :key-uid])
(ethereum/sha3 (security/safe-unmask-data (get-in db [:keycard :migration-password])))
#(re-frame/dispatch [::verify-password-result %])))
(rf/defn handle-multiaccount-import
{:events [::import-multiaccount-success]}
[{:keys [db] :as cofx} root-data derived-data]
(rf/merge cofx
{:db (-> db
(update :intro-wizard
assoc
:root-key root-data
:derived derived-data
:recovering? true
:selected-storage-type :advanced)
(assoc-in [:keycard :flow] :recovery)
(assoc-in [:keycard :from-key-storage-and-migration?] true)
(assoc-in [:keycard :converting-account?]
(not (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
(assoc-in [:keycard :delete-account?]
(true? (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
(dissoc :multiaccounts/key-storage))}
(popover/hide-popover)
(common/listen-to-hardware-back-button)
(navigation/navigate-to :keycard-onboarding-intro nil)))
(rf/defn goto-multiaccounts-screen
{:events [::hide-popover-and-goto-multiaccounts-screen]}
[cofx _]
(rf/merge cofx
(popover/hide-popover)
(navigation/navigate-to :multiaccounts nil)))
(rf/defn confirm-logout-and-goto-key-storage
{:events [::confirm-logout-and-goto-key-storage]}
[{:keys [db] :as cofx}]
(rf/merge cofx
{:db (assoc db :goto-key-storage? true)}
(multiaccounts.logout/logout)))
(rf/defn logout-and-goto-key-storage
{:events [::logout-and-goto-key-storage]}
[_]
{:ui/show-confirmation
{:title (i18n/label :t/logout-title)
:content (i18n/label :t/logout-key-management)
:confirm-button-text (i18n/label :t/logout)
:on-accept #(re-frame/dispatch [::confirm-logout-and-goto-key-storage])
:on-cancel nil}})
(comment
;; check import mnemonic output
(native-module/multiaccount-import-mnemonic
"rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo"
nil
(fn [result]
(prn (types/json->clj result))))
;; check delete account output
(native-module/delete-multiaccount "0x3831d0f22996a65970a214f0a94bfa9a63a21dac235d8dadb91be8e32e7d3ab7"
(fn [result]
(prn ::--delete-account-res-> result))))
@@ -1,67 +0,0 @@
(ns status-im.multiaccounts.key-storage.core-test
(:require [cljs.test :refer-macros [deftest is testing]]
[clojure.string :as string]
[status-im.multiaccounts.key-storage.core :as models]
[utils.security.core :as security]))
(deftest move-keystore-checked
(testing "Checks checkbox on-press"
(let [res (models/move-keystore-checked {:db {}} true)]
(is (= true (get-in res [:db :multiaccounts/key-storage :move-keystore-checked?]))))))
(deftest seed-phrase-input-changed
(testing "nil seed phrase shape is invalid"
(let [res (models/seed-phrase-input-changed {:db {}} (security/mask-data nil))]
(is (get-in res [:db :multiaccounts/key-storage :seed-shape-invalid?]))))
(let [sample-phrase "h h h h h h h h h h h H" ;; 12 characters
res (models/seed-phrase-input-changed {:db {}} (security/mask-data sample-phrase))]
(testing "Seed shape for 12 letter seed phrase is valid"
(is (false? (get-in res [:db :multiaccounts/key-storage :seed-shape-invalid?]))))
(testing "Seed words counted correctly"
(is (= 12 (get-in res [:db :multiaccounts/key-storage :seed-word-count]))))
(testing "Seed phrase is lowercased"
(is (= (get-in res [:db :multiaccounts/key-storage :seed-phrase])
(string/lower-case sample-phrase))))))
(def seed-key-uid-pair
{:seed-phrase "rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo"
:key-uid "0x3831d0f22996a65970a214f0a94bfa9a63a21dac235d8dadb91be8e32e7d3ab7"})
(defn mock-import-mnemonic-fn
[_ _ _]
;; return json with keyUid, the real world will have more info in the response
(str "{\"keyUid\": \"" (:key-uid seed-key-uid-pair) "\"}"))
(deftest validate-seed-against-key-uid
(testing "Success event is triggered if correct seed is entered for selected multiaccount (key-uid)"
(models/validate-seed-against-key-uid
{:import-mnemonic-fn mock-import-mnemonic-fn
:on-success #(is true) ; this callback should be called
:on-error #(is false)}
{:seed-phrase (:seed-phrase seed-key-uid-pair)
:key-uid (:key-uid seed-key-uid-pair)}))
(testing "Error event is triggered if incorrect seed is entered for selected multiaccount"
(models/validate-seed-against-key-uid
{:import-mnemonic-fn mock-import-mnemonic-fn
:on-success #(is false)
:on-error #(is true)}
{:seed-phrase (:seed-phrase seed-key-uid-pair)
:key-uid "0xInvalid-Will-make-the-function-fail"})))
(deftest handle-multiaccount-import
(testing "Sets correct state for Keycard onboarding after multiaccounts seeds are derived"
(let [res (models/handle-multiaccount-import {:db {}} :passed-root-data :passed-derived-data)]
(is (= :passed-root-data (get-in res [:db :intro-wizard :root-key])))
(is (= :passed-derived-data (get-in res [:db :intro-wizard :derived])))
(is (= :advanced (get-in res [:db :intro-wizard :selected-storage-type]))) ; :advanced storage type
; means Keycard
(is (= :recovery (get-in res [:db :keycard :flow])))
(is (get-in res [:db :keycard :from-key-storage-and-migration?])))))
(comment
(security/safe-unmask-data (security/mask-data nil)))
+40 -78
View File
@@ -16,7 +16,6 @@
[status-im.ethereum.transactions.core :as transactions]
[status-im.fleet.core :as fleet]
[utils.i18n :as i18n]
[status-im.keycard.common :as keycard.common]
[status-im.mobile-sync-settings.core :as mobile-network]
[status-im.multiaccounts.biometric.core :as biometric]
[status-im.multiaccounts.core :as multiaccounts]
@@ -37,7 +36,7 @@
[status-im.wallet.core :as wallet]
[status-im.wallet.prices :as prices]
[status-im2.common.json-rpc.events :as json-rpc]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.contexts.shell.activity-center.events :as activity-center]
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
[status-im2.contexts.contacts.events :as contacts]
[status-im2.navigation.events :as navigation]
@@ -46,7 +45,8 @@
[status-im2.common.log :as logging]
[taoensso.timbre :as log]
[status-im2.contexts.shell.jump-to.utils :as shell.utils]
[utils.security.core :as security]))
[utils.security.core :as security]
[status-im.keycard.common :as keycard.common]))
(re-frame/reg-fx
::initialize-transactions-management-enabled
@@ -61,6 +61,7 @@
(fn [[key-uid _ hashed-password]]
(native-module/login-account {:keyUid key-uid
:password hashed-password
:wakuV2Nameserver "1.1.1.1"
:openseaAPIKey config/opensea-api-key
:poktToken config/POKT_TOKEN
@@ -146,7 +147,7 @@
(rf/merge
cofx
{:db (assoc db
:multiaccount/accounts
:profile/wallet-accounts
(rpc->accounts accounts))
;; NOTE: Local notifications should be enabled only after wallet was started
::enable-local-notifications nil}
@@ -179,7 +180,7 @@
(rf/defn login-local-paired-user
{:events [:multiaccounts.login/local-paired-user]}
[{:keys [db]}]
(let [{:keys [key-uid name password]} (get-in db [:syncing :multiaccount])]
(let [{:keys [key-uid name password]} (get-in db [:syncing :profile/profile])]
{::login [key-uid
(types/clj->json {:name name
:key-uid key-uid})
@@ -188,9 +189,9 @@
(rf/defn login
{:events [:multiaccounts.login.ui/password-input-submitted]}
[{:keys [db]}]
(let [{:keys [key-uid password name]} (:multiaccounts/login db)]
(let [{:keys [key-uid password name]} (:profile/login db)]
{:db (-> db
(assoc-in [:multiaccounts/login :processing] true)
(assoc-in [:profile/login :processing] true)
(dissoc :intro-wizard :recovered-account?)
(update :keycard dissoc :flow))
::login [key-uid
@@ -201,7 +202,7 @@
(rf/defn export-db-submitted
{:events [:multiaccounts.login.ui/export-db-submitted]}
[{:keys [db]}]
(let [{:keys [key-uid password name]} (:multiaccounts/login db)]
(let [{:keys [key-uid password name]} (:profile/login db)]
{::export-db [key-uid
(types/clj->json {:name name
:key-uid key-uid})
@@ -216,7 +217,7 @@
(rf/defn import-db-submitted
{:events [:multiaccounts.login.ui/import-db-submitted]}
[{:keys [db]}]
(let [{:keys [key-uid password name]} (:multiaccounts/login db)]
(let [{:keys [key-uid password name]} (:profile/login db)]
{::import-db [key-uid
(types/clj->json {:name name
:key-uid key-uid})
@@ -394,7 +395,7 @@
[{:keys [db] :as cofx} node-config-json]
(let [node-config (types/json->clj node-config-json)]
{:db (assoc-in db
[:multiaccount :wakuv2-config]
[:profile/profile :wakuv2-config]
(get node-config :WakuV2Config))}))
(rf/defn get-node-config
@@ -438,10 +439,10 @@
merged-networks (merge networks config/default-networks-by-id)]
(rf/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)
(dissoc :profile/login)
(assoc :networks/current-network current-network
:networks/networks merged-networks
:multiaccount multiaccount))}
:profile/profile multiaccount))}
(data-store.chats/fetch-chats-rpc
{:on-success
#(do (re-frame/dispatch [:chats-list/load-success %])
@@ -476,29 +477,29 @@
(rf/defn check-last-chat
{:events [::check-last-chat]}
[{:keys [db]}]
{::open-last-chat (get-in db [:multiaccount :key-uid])})
{::open-last-chat (get-in db [:profile/profile :key-uid])})
(rf/defn update-wallet-accounts
[{:keys [db]} accounts]
(let [existing-accounts (into {} (map #(vector (:address %1) %1) (:multiaccount/accounts db)))
(let [existing-accounts (into {} (map #(vector (:address %1) %1) (:profile/wallet-accounts db)))
reduce-fn (fn [existing-accs new-acc]
(let [address (:address new-acc)]
(if (:removed new-acc)
(dissoc existing-accs address)
(assoc existing-accs address new-acc))))
new-accounts (reduce reduce-fn existing-accounts (rpc->accounts accounts))]
{:db (assoc db :multiaccount/accounts (vals new-accounts))}))
{:db (assoc db :profile/wallet-accounts (vals new-accounts))}))
(rf/defn get-chats-callback
{:events [::get-chats-callback]}
[{:keys [db] :as cofx}]
(let [{:networks/keys [current-network networks]} db
notifications-enabled? (get-in db [:multiaccount :notifications-enabled?])
notifications-enabled? (get-in db [:profile/profile :notifications-enabled?])
current-network-config (get networks current-network)
network-id (str (get-in networks
[current-network :config :NetworkId]))
remote-push-notifications-enabled?
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
(get-in db [:profile/profile :remote-push-notifications-enabled?])]
(rf/merge cofx
(cond-> {::eip1559/check-eip1559-activation
{:network-id network-id
@@ -510,7 +511,7 @@
(fn [accounts tokens custom-tokens favourites]
(re-frame/dispatch [::initialize-wallet
accounts tokens custom-tokens favourites]))]
::open-last-chat (get-in db [:multiaccount :key-uid])}
::open-last-chat (get-in db [:profile/profile :key-uid])}
(or notifications-enabled? remote-push-notifications-enabled?)
(assoc ::notifications/enable remote-push-notifications-enabled?))
(transport/start-messenger)
@@ -555,23 +556,21 @@
(rf/defn create-only-events
[{:keys [db] :as cofx} recovered-account?]
(let [{:keys [multiaccount
:multiaccounts/multiaccounts
:multiaccount/accounts]}
(let [{:profile/keys [profile profiles-overview wallet-accounts]}
db
{:keys [creating?]} (:multiaccounts/login db)
first-account? (and creating?
(empty? multiaccounts))
{:keys [creating?]} (:profile/login db)
first-account? (and creating? (empty? profiles-overview))
tos-accepted? (get db :tos/accepted?)
{:networks/keys [current-network networks]} db
network-id (str (get-in networks [current-network :config :NetworkId]))]
(shell.utils/change-selected-stack-id :communities-stack true nil)
(rf/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)
(dissoc :profile/login)
(assoc :tos/next-root :enable-notifications :chats/loading? false)
(assoc-in [:multiaccount :multiaccounts/first-account] first-account?))
::get-tokens [network-id accounts recovered-account?]}
(assoc-in [:profile/profile :multiaccounts/first-account]
first-account?))
::get-tokens [network-id wallet-accounts recovered-account?]}
(finish-keycard-setup)
(transport/start-messenger)
(communities/fetch)
@@ -579,7 +578,7 @@
{:on-success #(re-frame/dispatch [:chats-list/load-success %])})
(multiaccounts/switch-preview-privacy-mode-flag)
(link-preview/request-link-preview-whitelist)
(logging/set-log-level (:log-level multiaccount))
(logging/set-log-level (:log-level profile))
(navigation/init-root :enable-notifications))))
(defn- keycard-setup?
@@ -595,7 +594,7 @@
:on-card-read
:card-read-in-progress?
:pin
:multiaccount)
:profile/profile)
(assoc :tos-accept-next-root
(if login-only?
:shell-stack
@@ -606,9 +605,9 @@
(rf/defn multiaccount-login-success
[{:keys [db now] :as cofx}]
(let [{:keys [key-uid password save-password? creating?]}
(:multiaccounts/login db)
(:profile/login db)
multiaccounts (:multiaccounts/multiaccounts db)
multiaccounts (:profile/profiles-overview db)
recovered-account? (get db :recovered-account?)
login-only? (not (or creating?
recovered-account?
@@ -638,29 +637,12 @@
(login-only-events key-uid password save-password?)
(create-only-events recovered-account?)))))
;; FIXME(Ferossgp): We should not copy keys as we denormalize the database,
;; this create desync between actual accounts and the one on login causing broken state
;; UPDATE(cammellos): This code is copying over some fields explicitly as some values
;; are alreayd in `multiaccounts/login` and should not be overriden, as they come from
;; the keychain (save-password), this is not very explicit and we should probably
;; make it clearer
(rf/defn open-login
[{:keys [db]} override-multiaccount]
{:db (-> db
(update :multiaccounts/login
merge
override-multiaccount)
(update :multiaccounts/login
dissoc
:error
:password))})
(rf/defn open-login-callback
{:events [:multiaccounts.login.callback/get-user-password-success]}
[{:keys [db] :as cofx} password]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
(let [key-uid (get-in db [:profile/login :key-uid])
keycard-account? (boolean (get-in db
[:multiaccounts/multiaccounts
[:profile/profiles-overview
key-uid
:keycard-pairing]))
goto-key-storage? (:goto-key-storage? db)]
@@ -668,7 +650,7 @@
(rf/merge
cofx
{:db (update-in db
[:multiaccounts/login]
[:profile/login]
assoc
:password password
:save-password? true)
@@ -690,7 +672,7 @@
(rf/defn get-credentials
[{:keys [db] :as cofx} key-uid]
(let [keycard-multiaccount? (boolean (get-in db
[:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
[:profile/profiles-overview key-uid :keycard-pairing]))]
(log/debug "[login] get-credentials"
"keycard-multiacc?"
keycard-multiaccount?)
@@ -702,12 +684,8 @@
"Auth method: nil - not supported, \"none\" - not selected, \"password\", \"biometric\", \"biometric-prepare\""
{:events [:multiaccounts.login/get-auth-method-success]}
[{:keys [db] :as cofx} auth-method]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
keycard-multiaccount? (boolean (get-in db
[:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
(log/debug "[login] get-auth-method-success"
"auth-method" auth-method
"keycard-multiacc?" keycard-multiaccount?)
(let [key-uid (get-in db [:profile/login :key-uid])
keycard-profile? (boolean (get-in db [:profile/profiles-overview key-uid :keycard-pairing]))]
(rf/merge
cofx
{:db (assoc db :auth-method auth-method)}
@@ -716,15 +694,14 @@
(biometric/biometric-auth %)
(= auth-method keychain/auth-method-password)
(get-credentials % key-uid)
(and keycard-multiaccount?
(get-in db [:keycard :card-connected?]))
(and keycard-profile? (get-in db [:keycard :card-connected?]))
(keycard.common/get-application-info % nil))
(open-login-callback nil))))
(rf/defn biometric-auth-done
{:events [:biometric-auth-done]}
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
(let [key-uid (get-in db [:profile/login :key-uid])
auth-method (get db :auth-method)]
(log/debug "[biometric] biometric-auth-done"
"bioauth-success" bioauth-success
@@ -734,7 +711,7 @@
(get-credentials cofx key-uid)
(rf/merge cofx
{:db (assoc-in db
[:multiaccounts/login :save-password?]
[:profile/login :save-password?]
(= auth-method keychain/auth-method-biometric))}
(when-not (= auth-method keychain/auth-method-biometric)
(keychain/save-auth-method key-uid keychain/auth-method-none))
@@ -761,7 +738,7 @@
(and (not save-password?)
bioauth-supported?
(= previous-auth-method keychain/auth-method-none)))
(assoc-in [:multiaccounts/login :save-password?] save-password?))}
(assoc-in [:profile/login :save-password?] save-password?))}
(when bioauth-supported?
(if save-password?
(popover/show-popover {:view :secure-with-biometric})
@@ -773,21 +750,6 @@
[_]
{:set-root :shell-stack})
(rf/defn multiaccount-selected
{:events [:multiaccounts.login.ui/multiaccount-selected]}
[{:keys [db] :as cofx} key-uid]
;; We specifically pass a bunch of fields instead of the whole multiaccount
;; as we want store some fields in multiaccount that are not here
(let [multiaccount (get-in db [:multiaccounts/multiaccounts key-uid])
keycard-multiaccount? (boolean (:keycard-pairing multiaccount))]
(rf/merge
cofx
(merge
{:db (update db :keycard dissoc :application-info)}
(when keycard-multiaccount? {:navigate-to :keycard-login-pin}))
(open-login (select-keys multiaccount
[:key-uid :name :public-key :images :customization-color])))))
(rf/defn hide-keycard-banner
{:events [:hide-keycard-banner]}
[{:keys [db]}]
@@ -11,16 +11,16 @@
:supported-biometric-auth false}}
{:keys [db]} (login/save-password initial-cofx true)]
(test/is (= false (contains? db :popover/popover)))
(test/is (= true (get-in db [:multiaccounts/login :save-password?])))
(test/is (= true (get-in db [:profile/login :save-password?])))
(test/testing "uncheck save password"
(let [{:keys [db]} (login/save-password {:db db} false)]
(test/is (= false (contains? db :popover/popover)))
(test/is (= false (get-in db [:multiaccounts/login :save-password?])))))))
(test/is (= false (get-in db [:profile/login :save-password?])))))))
(test/testing "check save password, biometric available"
(let [initial-cofx {:db {:auth-method keychain/auth-method-none
:supported-biometric-auth true}}
{:keys [db]} (login/save-password initial-cofx true)]
(test/is (= true (get-in db [:multiaccounts/login :save-password?])))
(test/is (= true (get-in db [:profile/login :save-password?])))
(test/testing "enable biometric auth"
(let [{:keys [db] :as res} (biometric/enable {:db db})]
(test/is (contains? res :biometric-auth/authenticate))
@@ -53,10 +53,10 @@
:bioauth-message nil
:bioauth-code nil}))
false)]
(test/is (= true (get-in db [:multiaccounts/login :save-password?])))
(test/is (= true (get-in db [:profile/login :save-password?])))
;; case 2 from https://github.com/status-im/status-mobile/issues/9573
(test/is (= keychain/auth-method-biometric-prepare (:auth-method db)))
(test/testing "disable biometric"
(let [{:keys [db]} (biometric/disable {:db db})]
(test/is (= false (get-in db [:multiaccounts/login :save-password?])))
(test/is (= false (get-in db [:profile/login :save-password?])))
(test/is (= keychain/auth-method-none (:auth-method db))))))))
@@ -10,28 +10,28 @@
(deftest on-password-input-submitted
(testing
"handling :multiaccounts.login.ui/password-input-submitted event"
(let [cofx {:db {:multiaccounts/login {:key-uid "key-uid"
:password "password"
:name "user"}}}
(let [cofx {:db {:profile/login {:key-uid "key-uid"
:password "password"
:name "user"}}}
efx (login.core/login cofx)]
(testing "Change multiaccount."
(is (= (::login.core/login efx)
["key-uid" "{\"name\":\"user\",\"key-uid\":\"key-uid\"}"
(ethereum/sha3 "password")])))
(testing "start activity indicator"
(is (= (get-in efx [:db :multiaccounts/login :processing]) true))))))
(is (= (get-in efx [:db :profile/login :processing]) true))))))
(deftest login-success
(testing ":accounts.login.callback/login-success event received."
(let [db {:multiaccounts/login {:address "address"
:password "password"}
:multiaccount data/multiaccount}
(let [db {:profile/login {:address "address"
:password "password"}
:profile/profile data/multiaccount}
cofx {:db db}
efx (login.core/multiaccount-login-success cofx)
json-rpc (into #{} (map :method (:json-rpc/call efx)))]
;; TODO: Account is now cleared only after all sign in fx are executed.
;; (testing ":accounts/login cleared."
;; (is (not (contains? new-db :multiaccounts/login))))
;; (is (not (contains? new-db :profile/login))))
(testing "Check the rest of effects."
(is (json-rpc "web3_clientVersion"))))))
@@ -44,7 +44,7 @@
"04f43da85ff1c333f3e7277b9ac4df92c9120fbb251f1dede7d41286e8c055acfeb845f6d2654821afca25da119daff9043530b296ee0e28e202ba92ec5842d617"
db
{:keycard
{:multiaccount
{:profile/profile
{:encryption-public-key epk
:whisper-private-key wpk
:wallet-address "83278851e290d2488b6add2a257259f5741a3b7d"
+5 -4
View File
@@ -12,7 +12,7 @@
(rf/defn logout-method
{:events [::logout-method]}
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
(let [key-uid (get-in db [:multiaccount :key-uid])]
(let [key-uid (get-in db [:profile/profile :key-uid])]
(rf/merge cofx
{:set-root :progress
:chat.ui/clear-inputs nil
@@ -21,8 +21,9 @@
::logout nil
::multiaccounts/webview-debug-changed false
:keychain/clear-user-password key-uid
:setup/open-multiaccounts #(re-frame/dispatch [:setup/initialize-multiaccounts
% {:logout? logout?}])}
:profile/get-profiles-overview #(re-frame/dispatch
[:profile/get-profiles-overview-success
%])}
(keychain/save-auth-method key-uid auth-method)
(wallet/clear-timeouts)
(init/initialize-app-db))))
@@ -56,7 +57,7 @@
(logout-method {:auth-method keychain/auth-method-biometric-prepare
:logout? false})
(fn [{:keys [db]}]
{:db (assoc-in db [:multiaccounts/login :save-password?] true)})))
{:db (assoc-in db [:profile/login :save-password?] true)})))
(re-frame/reg-fx
::logout
+2 -10
View File
@@ -1,13 +1,5 @@
(ns status-im.multiaccounts.model)
(defn logged-in?
[{:keys [multiaccount]}]
(boolean multiaccount))
(defn credentials
[cofx]
(select-keys (get-in cofx [:db :multiaccounts/login]) [:key-uid :password :save-password?]))
(defn current-public-key
[cofx]
(get-in cofx [:db :multiaccount :public-key]))
[{:keys [profile/profile]}]
(boolean profile))
+1 -1
View File
@@ -4,6 +4,6 @@
(deftest logged-in-test
(testing "multiaccount is defined"
(is (multiaccounts.model/logged-in? {:multiaccount {}})))
(is (multiaccounts.model/logged-in? {:profile/profile {}})))
(testing "multiaccount is not there"
(is (not (multiaccounts.model/logged-in? {})))))

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