Compare commits

..
Author SHA1 Message Date
pavloburykh 839e1f1058 Sign in fix 2023-03-20 18:01:11 +02:00
146 changed files with 1367 additions and 3798 deletions
-29
View File
@@ -61,35 +61,6 @@ the source file. For a real example, see
[rn/view (do-something)]])
```
### Always add styles inside the `:style` key
Although when compiling ReactNative for mobile some components are able work with
their styles in the top-level of the properties map, prefer to add them inside the
`:style` key in order to separate styles from properties:
```clojure
;; bad
[rn/button {:flex 1
:padding-vertical 10
:padding-horizontal 20
:on-press #(js/alert "Hi!")
:title "Button"}]
;; good
[rn/button {:style {:flex 1
:padding-vertical 10
:padding-horizontal 20}
:on-press #(js/alert "Hi!")
:title "Button"}]
;; better
;; (define them in a style ns & place them inside `:style` key)
[rn/button {:style (style/button)
:on-press #(js/alert "Hi!")
:title "Button"}
]
```
### Don't use percents to define width/height
In ReactNative, all layouts use the [flexbox
-10
View File
@@ -35,16 +35,6 @@ abstract_target 'Status' do
target 'StatusImPR' do
end
post_install do |installer|
# some of libs wouldn't be build for x86_64 otherwise and that is
# necessary for ios simulators
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'
end
end
end
use_native_modules!
end
+12 -6
View File
@@ -417,7 +417,9 @@
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = 8B5X2M6H2Y;
LastSwiftMigration = 1140;
ProvisioningStyle = Manual;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
@@ -841,8 +843,9 @@
BUNDLE_ID_SUFFIX = .debug;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = StatusIm/StatusIm.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CUSTOM_PRODUCT_NAME = "Status Debug";
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
@@ -895,7 +898,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum;
PRODUCT_NAME = StatusIm;
PROVISIONING_PROFILE_SPECIFIER = "";
PROVISIONING_PROFILE = "9da75626-9594-43d9-a827-0f6d43c28f54";
PROVISIONING_PROFILE_SPECIFIER = "match Development im.status.ethereum";
SWIFT_OBJC_BRIDGING_HEADER = "StatusIm-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -913,8 +917,9 @@
BUNDLE_ID_SUFFIX = "";
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = StatusIm/StatusIm.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CUSTOM_PRODUCT_NAME = Status;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 8B5X2M6H2Y;
@@ -959,7 +964,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum;
PRODUCT_NAME = StatusIm;
PROVISIONING_PROFILE_SPECIFIER = "";
PROVISIONING_PROFILE = "e2202b12-7a66-4ff7-af3c-a52e35f32dc1";
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc im.status.ethereum";
SWIFT_OBJC_BRIDGING_HEADER = "StatusIm-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
@@ -323,30 +323,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
callback.invoke(finalConfig);
}
@ReactMethod
public void createAccountAndLogin(final String createAccountRequest) {
Log.d(TAG, "createAccountAndLogin");
String result = Statusgo.createAccountAndLogin(createAccountRequest);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "createAccountAndLogin success: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "createAccountAndLogin failed: " + result);
}
}
@ReactMethod
public void restoreAccountAndLogin(final String restoreAccountRequest) {
Log.d(TAG, "restoreAccountAndLogin");
String result = Statusgo.restoreAccountAndLogin(restoreAccountRequest);
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "restoreAccountAndLogin success: " + result);
Log.d(TAG, "Geth node started");
} else {
Log.e(TAG, "restoreAccountAndLogin failed: " + result);
}
}
@ReactMethod
public void saveAccountAndLogin(final String multiaccountData, final String password, final String settings, final String config, final String accountsData) {
try {
@@ -544,8 +520,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
return;
}
Log.d(TAG, "[Opening accounts" + rootDir);
Runnable r = new Runnable() {
@Override
public void run() {
@@ -811,10 +785,9 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
@ReactMethod
public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject(configJSON);
final JSONObject senderConfig = jsonConfig.getJSONObject("senderConfig");
final String keyUID = senderConfig.getString("keyUID");
final String keyUID = jsonConfig.getString("keyUID");
final String keyStorePath = this.getKeyStorePath(keyUID);
senderConfig.put("keystorePath", keyStorePath);
jsonConfig.put("keystorePath", keyStorePath);
executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback);
}
@@ -822,10 +795,9 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
@ReactMethod
public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject(configJSON);
final JSONObject receiverConfig = jsonConfig.getJSONObject("receiverConfig");
final String keyStorePath = pathCombine(this.getNoBackupDirectory(), "/keystore");
receiverConfig.put("keystorePath", keyStorePath);
receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", this.getNoBackupDirectory());
jsonConfig.put("keystorePath", keyStorePath);
jsonConfig.put("rootDataDir", this.getNoBackupDirectory());
executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback);
}
@@ -1157,23 +1129,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
executeRunnableStatusGoMethod(() -> Statusgo.deleteImportedKey(address, password, keyStoreDir), callback);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String keystoreDir() {
final String absRootDirPath = this.getNoBackupDirectory();
return pathCombine(absRootDirPath, "keystore");
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String backupDisabledDataDir() {
return this.getNoBackupDirectory();
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String logFilePath() {
return getLogsFile().getAbsolutePath();
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String generateAlias(final String seed) {
return Statusgo.generateAlias(seed);
@@ -309,14 +309,12 @@ RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)c
callback:(RCTResponseSenderBlock)callback) {
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error];
NSMutableDictionary *senderConfig = configDict[@"senderConfig"];
NSString *keyUID = senderConfig[@"keyUID"];
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
NSString *keyUID = [configDict objectForKey:@"keyUID"];
NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID];
NSString *keystoreDir = multiaccountKeystoreDir.path;
[senderConfig setValue:keystoreDir forKey:@"keystorePath"];
[configDict setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO];
NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON);
@@ -328,20 +326,17 @@ RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
callback:(RCTResponseSenderBlock)callback) {
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error];
NSMutableDictionary *receiverConfig = configDict[@"receiverConfig"];
NSMutableDictionary *nodeConfig = receiverConfig[@"nodeConfig"];
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *rootDataDir = rootUrl.path;
NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSString *keystoreDir = multiaccountKeystoreDir.path;
NSString *rootDataDir = rootUrl.path;
[receiverConfig setValue:keystoreDir forKey:@"keystorePath"];
[nodeConfig setValue:rootDataDir forKey:@"rootDataDir"];
[configDict setValue:keystoreDir forKey:@"keystorePath"];
[configDict setValue:rootDataDir forKey:@"rootDataDir"];
NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO];
NSString *result = StatusgoInputConnectionStringForBootstrapping(cs, modifiedConfigJSON);
NSString *result = StatusgoInputConnectionStringForBootstrapping(cs,modifiedConfigJSON);
callback(@[result]);
}
@@ -862,34 +857,6 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(generateAlias:(NSString *)publicKey) {
return StatusgoGenerateAlias(publicKey);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
return commonKeystoreDir.path;
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(backupDisabledDataDir) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
return rootUrl.path;
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFilePath) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
return rootUrl.path;
}
RCT_EXPORT_METHOD(generateAliasAsync:(NSString *)publicKey
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -967,20 +934,6 @@ RCT_EXPORT_METHOD(identiconAsync:(NSString *)publicKey
callback(@[result]);
}
RCT_EXPORT_METHOD(createAccountAndLogin:(NSString *)request) {
#if DEBUG
NSLog(@"createAccountAndLogin() method called");
#endif
StatusgoCreateAccountAndLogin(request);
}
RCT_EXPORT_METHOD(restoreAccountAndLogin:(NSString *)request) {
#if DEBUG
NSLog(@"restoreAccountAndLogin() method called");
#endif
StatusgoRestoreAccountAndLogin(request);
}
RCT_EXPORT_METHOD(generateAliasAndIdenticonAsync:(NSString *)publicKey
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
+25 -25
View File
@@ -11572,57 +11572,57 @@
},
{
"path": "org/slf4j/jcl-over-slf4j/2.0.7",
"path": "org/slf4j/jcl-over-slf4j/2.0.6",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"jcl-over-slf4j-2.0.7.pom": {
"sha1": "15536e4a74a7aa317322a3d7814db8251de60d6f",
"sha256": "1rzjwbmzf2hb85j6c41mch803vqwqdq1rfrrirfhp1lfpfnzyd23"
"jcl-over-slf4j-2.0.6.pom": {
"sha1": "c9d9caedcca2a1564e47b55614960958c5f78773",
"sha256": "1swgy5hwv54b1i1117shn3wmwba3v78qvy6cnv8v243j7ac6vzqq"
},
"jcl-over-slf4j-2.0.7.jar": {
"sha1": "f127fe5ee53404a8b3697cdd032dd1dd6a29dd77",
"sha256": "0hhpc2qdl4aa9mb8dk89wzbd5vkna557vjmjdmfswvfjw5bng021"
"jcl-over-slf4j-2.0.6.jar": {
"sha1": "839ff57e112f2e28ef372e96d135696a6896b9ad",
"sha256": "0s9scdwkxwj3al87ihanj10rscrjh44kligr5asb7qpl28d1xvks"
}
}
},
{
"path": "org/slf4j/slf4j-api/2.0.7",
"path": "org/slf4j/slf4j-api/2.0.6",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"slf4j-api-2.0.7.pom": {
"sha1": "facf002401dbff2065d4257690651e3fa775e3f4",
"sha256": "10br4q2w50fn3mkvk1xji81wdpy86cm0wyv6m30xa0ha1v7kqh1d"
"slf4j-api-2.0.6.pom": {
"sha1": "2b93d5f66ad2ba259bf4b2c94da39f0d6c544400",
"sha256": "0dipzawn8rxikciij2z06c25rb2vdj83s8ga3a7n10r77p2qcklb"
},
"slf4j-api-2.0.7.jar": {
"sha1": "41eb7184ea9d556f23e18b5cb99cad1f8581fc00",
"sha256": "1x26v62ypzpp84yfad8mx53llbacq6580y34v8nc618r7awrhqjx"
"slf4j-api-2.0.6.jar": {
"sha1": "88c40d8b4f33326f19a7d3c0aaf2c7e8721d4953",
"sha256": "1nkv0z4dpkvp6pr9ph8087z5r691bv95xdv3gnfi6s5j23a94aig"
}
}
},
{
"path": "org/slf4j/slf4j-jdk14/2.0.7",
"path": "org/slf4j/slf4j-jdk14/2.0.6",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"slf4j-jdk14-2.0.7.pom": {
"sha1": "31039eac9f263c48bda14efd90aef0fb7a5a0e6a",
"sha256": "1vx1ziyx36zf2lrpkvvm4c75hp8pw8vjpiyr5120ss8nwpd33qal"
"slf4j-jdk14-2.0.6.pom": {
"sha1": "96ac9d6ab608e787d54892b35205bc6a560aa007",
"sha256": "0gnsyy1n5v8xqdy6a6p1752m5c4afihpw0n36n6aqw01y9l86q1h"
},
"slf4j-jdk14-2.0.7.jar": {
"sha1": "d91cd16b55ffbd5f46c60d0173fd4eeccacfee2d",
"sha256": "1xvphj12jpnvr1sw8zx42p49in4xi61mjvpxrkk3q3qpyad7017r"
"slf4j-jdk14-2.0.6.jar": {
"sha1": "13056cb341f2d8795120f8027766a058da874f85",
"sha256": "0jncm8a2ppliqpzkbqm26sn98mwif8c1nligc1zh4jbzr8mxyzhy"
}
}
},
{
"path": "org/slf4j/slf4j-parent/2.0.7",
"path": "org/slf4j/slf4j-parent/2.0.6",
"repo": "https://repo.maven.apache.org/maven2",
"files": {
"slf4j-parent-2.0.7.pom": {
"sha1": "3f97e066227cc2353d212b8c43440b0bf4c033f3",
"sha256": "1rs55v9gqda5lks89dd81frps5c9g3zgxk832qyckw9srlvbp0n1"
"slf4j-parent-2.0.6.pom": {
"sha1": "0f99f8426c64fc5e0c4b6749245e50484a16c372",
"sha256": "091il49sidk0lcmzdy0vl3a4l16kw6x1q0l9vk0hir1ipq66b0hl"
}
}
},
+4 -4
View File
@@ -802,9 +802,9 @@ https://repo.maven.apache.org/maven2/org/ow2/asm/asm/6.0/asm-6.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm/9.4/asm-9.4.pom
https://repo.maven.apache.org/maven2/org/ow2/ow2/1.3/ow2-1.3.pom
https://repo.maven.apache.org/maven2/org/ow2/ow2/1.5.1/ow2-1.5.1.pom
https://repo.maven.apache.org/maven2/org/slf4j/jcl-over-slf4j/2.0.7/jcl-over-slf4j-2.0.7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-api/2.0.7/slf4j-api-2.0.7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-jdk14/2.0.7/slf4j-jdk14-2.0.7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-parent/2.0.7/slf4j-parent-2.0.7.pom
https://repo.maven.apache.org/maven2/org/slf4j/jcl-over-slf4j/2.0.6/jcl-over-slf4j-2.0.6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-api/2.0.6/slf4j-api-2.0.6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-jdk14/2.0.6/slf4j-jdk14-2.0.6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-parent/2.0.6/slf4j-parent-2.0.6.pom
https://repo.maven.apache.org/maven2/org/sonatype/oss/oss-parent/7/oss-parent-7.pom
https://repo.maven.apache.org/maven2/org/sonatype/oss/oss-parent/9/oss-parent-9.pom
+3 -3
View File
@@ -29,17 +29,17 @@ function findPackage(line, regex) {
if (line ~ "com.facebook.react:react-native") { continue }
# Example: +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.50
if (findPackage(line, "--- ([^ :]+):([^ :]+):([^ :]+)$")) {
if (findPackage(line, "--- ([^:]+):([^:]+):([^ ]+)$")) {
continue
}
# Example: +--- androidx.lifecycle:lifecycle-common:{strictly 2.0.0} -> 2.0.0 (c)
if (findPackage(line, "--- ([^ :]+):([^ :]+):[^:]+ -> ([^ :]+) ?(\\([*c]\\))?$")) {
if (findPackage(line, "--- ([^:]+):([^:]+):[^ ]+ -> ([^: ]+) ?(\\([*c]\\))?$")) {
continue
}
# Example: +--- com.android.support:appcompat-v7:28.0.0 -> androidx.appcompat:appcompat:1.0.2
if (findPackage(line, "--- [^ :]+:[^ :]+:[^ ]+ -> ([^ :]+):([^ :]+):([^ :]+)$")) {
if (findPackage(line, "--- [^:]+:[^:]+:[^ ]+ -> ([^:]+):([^:]+):([^ ]+)$")) {
continue
}
}
+2 -2
View File
@@ -46,8 +46,8 @@ in {
# Package version adjustments
gradle = super.gradle_5;
nodejs = super.nodejs-18_x;
yarn = super.yarn.override { nodejs = super.nodejs-18_x; };
nodejs = super.nodejs-16_x;
yarn = super.yarn.override { nodejs = super.nodejs-16_x; };
openjdk = super.openjdk8_headless;
xcodeWrapper = callPackage ./pkgs/xcodeenv/compose-xcodewrapper.nix { } {
version = "13.3";
+1 -8
View File
@@ -42,19 +42,12 @@ let
# for running gradle by hand
gradle = mkShell {
buildInputs = with pkgs; [ gradle maven goMavenResolver ];
inputsFrom = [ nodejs-sh ];
shellHook = ''
export STATUS_GO_ANDROID_LIBDIR="DUMMY"
export STATUS_NIX_MAVEN_REPO="${pkgs.deps.gradle}"
export ANDROID_SDK_ROOT="${pkgs.androidPkgs.sdk}"
export ANDROID_NDK_ROOT="${pkgs.androidPkgs.ndk}"
export STATUS_MOBILE_HOME=$(git rev-parse --show-toplevel)
# WARNING: Unpatched Node.js deps allow Gradle to use remote repos.
"$STATUS_MOBILE_HOME/nix/scripts/node_modules.sh" ${pkgs.deps.nodejs}
function restore_patched_modules() {
"$STATUS_MOBILE_HOME/nix/scripts/node_modules.sh" ${pkgs.deps.nodejs-patched}
}
trap restore_patched_modules EXIT
'';
};
+1 -1
View File
@@ -19,7 +19,7 @@
"@babel/preset-typescript": "^7.17.12",
"@react-native-async-storage/async-storage": "^1.17.9",
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#refs/tags/v2.0.3-status-v6",
"@react-native-community/blur": "git+https://github.com/status-im/react-native-blur#refs/tags/v4.3.2-status",
"@react-native-community/blur": "git+https://github.com/status-im/react-native-blur#refs/tags/v4.3.1-status",
"@react-native-community/cameraroll": "git+https://github.com/status-im/react-native-cameraroll.git#refs/tags/v4.0.4-status.0",
"@react-native-community/clipboard": "^1.2.2",
"@react-native-community/hooks": "^2.5.1",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

+1 -7
View File
@@ -45,13 +45,7 @@
:devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]}
:dev {:devtools {:after-load status-im2.setup.hot-reload/reload
:build-notify status-im2.setup.hot-reload/build-notify
:preloads [re-frisk-remote.preload
;; In order to use component test helpers in
;; the REPL we need to preload namespaces
;; that are not normally required by
;; production code, such as
;; @testing-library/react-native.
test-helpers.component]}
:preloads [re-frisk-remote.preload]}
:closure-defines
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
@@ -58,18 +58,6 @@
(h/test "Size :small"
(h/render (user-avatar-component :small))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Two letters with excess whitespace"
(h/render [user-avatar/user-avatar
{:full-name "New User"
:size :big}])
(h/is-truthy (h/get-by-text "NU")))
(h/test "Two letters with leading whitespace"
(h/render [user-avatar/user-avatar
{:full-name " New User"
:size :big}])
(h/is-truthy (h/get-by-text "NU"))))
(h/describe "One letter"
@@ -5,18 +5,14 @@
[react-native.core :as rn]
[react-native.fast-image :as fast-image]))
(defn trim-whitespace [s] (string/join " " (string/split (string/trim s) #"\s+")))
(defn- extract-initials
[full-name amount-initials]
(let [upper-case-first-letter (comp string/upper-case first)
names-list (string/split (trim-whitespace full-name) " ")]
(if (= (first names-list) "")
""
(->> names-list
(map upper-case-first-letter)
(take amount-initials)
(string/join)))))
names-list (string/split full-name " ")]
(->> names-list
(map upper-case-first-letter)
(take amount-initials)
(string/join))))
(defn initials-avatar
[{:keys [full-name size draw-ring? customization-color]}]
+16 -14
View File
@@ -6,13 +6,12 @@
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn themes
[customization-color]
(def themes
{:light {:primary {:icon-color colors/white
:label-color colors/white
:background-color {:default (colors/custom-color customization-color 50)
:pressed (colors/custom-color customization-color 60)
:disabled (colors/custom-color customization-color 50)}}
:background-color {:default colors/primary-50
:pressed colors/primary-60
:disabled colors/primary-50}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
@@ -75,9 +74,9 @@
:disabled colors/neutral-95}}}
:dark {:primary {:icon-color colors/white
:label-color colors/white
:background-color {:default (colors/custom-color customization-color 60)
:pressed (colors/custom-color customization-color 50)
:disabled (colors/custom-color customization-color 60)}}
:background-color {:default colors/primary-60
:pressed colors/primary-50
:disabled colors/primary-60}}
:secondary {:icon-color colors/primary-50
:label-color colors/primary-50
:background-color {:default colors/primary-50-opa-20
@@ -219,15 +218,14 @@
(let [pressed (reagent/atom false)]
(fn
[{:keys [on-press disabled type size community-color community-text-color before after above
width customization-color
width
override-theme override-background-color
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
:or {type :primary
size 40
customization-color :primary}}
:or {type :primary
size 40}}
children]
(let [{:keys [icon-color icon-secondary-color background-color label-color border-color]}
(get-in (themes customization-color)
(get-in themes
[(or
override-theme
(theme/get-theme)) type])
@@ -254,7 +252,11 @@
[rn/view
{:style (merge
(shape-style-container type icon size)
{:width width}
{:background-color
(if (= state :pressed)
(colors/theme-colors colors/neutral-100 colors/white)
:transparent)
:width width}
style)}
[rn/view
{:style (merge
@@ -16,13 +16,15 @@
:height 230
:border-radius 20}
:on-press on-press}
[rn/view {:flex 1}
[rn/view
{:flex 1}
[rn/view (style/community-cover-container 60)
[rn/image
{:source cover
:style {:flex 1
:border-top-right-radius 20
:border-top-left-radius 20}}]]
:style
{:flex 1
:border-top-right-radius 20
:border-top-left-radius 20}}]]
[rn/view (style/card-view-content-container 12)
[rn/view (style/card-view-chat-icon 48)
[icon/community-icon {:images images} 48]]
@@ -36,8 +38,7 @@
{:title name
:description description}]
[rn/view {:style (style/card-stats-position)}
[community-view/community-stats-column
{:type :card-view}]]
[community-view/community-stats-column :card-view]]
[rn/view {:style (style/community-tags-position)}
[community-view/community-tags tags]]]]]]])
@@ -64,8 +64,7 @@
colors/neutral-40
colors/neutral-60))}}
name]
[community-view/community-stats-column
{:type :list-view}]]
[community-view/community-stats-column :list-view]]
(if (= status :gated)
[community-view/permission-tag-container
{:locked? locked?
@@ -23,7 +23,7 @@
members-count]])
(defn community-stats-column
[{:keys [type]}]
[type]
(let [icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)]
[rn/view
(if (= type :card-view)
@@ -46,12 +46,11 @@
^{:key name}
[rn/view {:margin-right 8}
[tag/tag
{:size 24
:label name
:type :emoji
:labelled? true
:scrollable? true
:resource emoji}]])])
{:size 24
:label name
:type :emoji
:labelled? true
:resource emoji}]])])
(defn community-title
[{:keys [title description size] :or {size :small}}]
+1 -1
View File
@@ -62,7 +62,7 @@
:bottom 0
:left 0
:right 0
:border-radius 20
:height 20
:padding-horizontal padding-horizontal
:border-top-right-radius 16
:border-top-left-radius 16
+4 -4
View File
@@ -22,18 +22,18 @@
opts
{:type :default/:success/:error
:size :default/:tiny
:icon :i/info ;; info message icon
:icon :main-icons/info ;; info message icon
:text-color colors/white ;; text color override
:icon-color colors/white ;; icon color override
:no-icon-color? false ;; disable tint color for icon"
[{:keys [type size icon text-color icon-color no-icon-color? style]} message]
[{:keys [type size icon text-color icon-color no-icon-color?]} message]
(let [weight (if (= size :default) :regular :medium)
size (if (= size :default) :paragraph-2 :label)
text-color (or text-color (get-color type))
icon-color (or icon-color text-color)]
[rn/view
{:style (merge {:flex-direction :row}
style)}
{:style {:flex-direction :row
:flex 1}}
[quo2.icons/icon icon
{:color icon-color
:no-color no-icon-color?
@@ -1,70 +0,0 @@
(ns quo2.components.inputs.input.component-spec
(:require [quo2.components.inputs.input.view :as input]
[test-helpers.component :as h]))
(h/describe "Input"
(h/test "default render"
(h/render [input/input])
(h/is-truthy (h/query-by-label-text :input))
(h/is-null (h/query-by-label-text :password-input)))
(h/test "Password type"
(h/render [input/input {:type :password}])
(h/is-truthy (h/query-by-label-text :password-input))
(h/is-null (h/query-by-label-text :input)))
(h/describe "Icon"
(h/test "Doesn't exist in base input"
(h/render [input/input])
(h/is-null (h/query-by-label-text :input-icon)))
(h/test "Renders"
(h/render [input/input {:icon-name :i/placeholder}])
(h/is-truthy (h/get-by-label-text :input-icon))))
(h/describe "Right accessory"
(h/test "Doesn't exist in base input"
(h/render [input/input])
(h/is-null (h/query-by-label-text :input-right-icon)))
(h/test "Clear icon"
(h/render [input/input {:clearable? true}])
(h/is-truthy (h/query-by-label-text :input-right-icon)))
(h/test "Password icon"
(h/render [input/input {:type :password}])
(h/is-truthy (h/query-by-label-text :input-right-icon))))
(h/describe "Button"
(h/test "Doesn't exist in base input"
(h/render [input/input])
(h/is-null (h/query-by-label-text :input-button)))
(h/test "Renders with given text and it's pressable"
(let [button-text "This is a button"
button-callback (h/mock-fn)]
(h/render [input/input
{:button {:on-press button-callback
:text button-text}}])
(h/is-truthy (h/query-by-label-text :input-button))
(h/is-truthy (h/get-by-text button-text))
(h/fire-event :press (h/query-by-label-text :input-button))
(h/was-called button-callback))))
(h/describe "Label"
(h/test "Doesn't exist in base input"
(h/render [input/input])
(h/is-null (h/query-by-label-text :input-labels)))
(h/test "Renders with specified text"
(let [input-label "My label"]
(h/render [input/input {:label input-label}])
(h/is-truthy (h/query-by-label-text :input-labels))
(h/is-truthy (h/get-by-text input-label)))))
(h/test "Char limit counter"
(let [char-limit 100
char-limit-str (str "0/" char-limit)]
(h/render [input/input {:char-limit char-limit}])
(h/is-truthy (h/query-by-label-text :input-labels))
(h/is-truthy (h/get-by-text char-limit-str)))))
+12 -11
View File
@@ -66,7 +66,7 @@
:padding-horizontal 8
:border-width 1
:border-color (:border-color colors-by-status)
:border-radius (if small? 10 12)
:border-radius (if small? 10 14)
:opacity (if disabled? 0.3 1)})
(defn left-icon-container
@@ -83,15 +83,15 @@
(defn input
[colors-by-status small? multiple-lines?]
(let [base-props (assoc (text/text-style {:size :paragraph-1 :weight :regular})
:flex 1
:padding-right 0
:padding-left (if small? 4 8)
:padding-vertical (if small? 4 8)
:color (:text colors-by-status))]
(if multiple-lines?
(assoc base-props :text-align-vertical :top)
(assoc base-props :height (if small? 30 38) :line-height nil))))
(merge (text/text-style {:size :paragraph-1 :weight :regular})
{:flex 1
:text-align-vertical :top
:padding-right 0
:padding-left (if small? 4 8)
:padding-vertical (if small? 4 8)
:color (:text colors-by-status)}
(when-not multiple-lines?
{:height (if small? 30 38)})))
(defn right-icon-touchable-area
[small?]
@@ -110,7 +110,8 @@
:color (:clear-icon variant-colors)})
(def texts-container
{:flex-direction :row
{:flex 1
:flex-direction :row
:height 18
:margin-bottom 8})
+22 -34
View File
@@ -9,9 +9,7 @@
(defn- label-&-counter
[{:keys [label current-chars char-limit variant-colors]}]
(let [count-text (when char-limit (str current-chars "/" char-limit))]
[rn/view
{:accessibility-label :input-labels
:style style/texts-container}
[rn/view {:style style/texts-container}
[rn/view {:style style/label-container}
[text/text
{:style (style/label-color variant-colors)
@@ -27,40 +25,36 @@
(defn- left-accessory
[{:keys [variant-colors small? icon-name]}]
[rn/view
{:accessibility-label :input-icon
:style (style/left-icon-container small?)}
[rn/view {:style (style/left-icon-container small?)}
[icon/icon icon-name (style/icon variant-colors)]])
(defn- right-accessory
[{:keys [variant-colors small? disabled? on-press icon-style-fn icon-name]}]
[rn/touchable-opacity
{:accessibility-label :input-right-icon
:style (style/right-icon-touchable-area small?)
:disabled disabled?
:on-press on-press}
{:style (style/right-icon-touchable-area small?)
:disabled disabled?
:on-press on-press}
[icon/icon icon-name (icon-style-fn variant-colors)]])
(defn- right-button
[{:keys [variant-colors colors-by-status small? disabled? on-press text]}]
[rn/touchable-opacity
{:accessibility-label :input-button
:style (style/button variant-colors small?)
:disabled disabled?
:on-press on-press}
{:style (style/button variant-colors small?)
:disabled disabled?
:on-press on-press}
[rn/text {:style (style/button-text colors-by-status)}
text]])
(def ^:private custom-props
"Custom properties that must be removed from properties map passed to InputText."
[:type :blur? :override-theme :error? :right-icon :left-icon :disabled? :small? :button
:label :char-limit :on-char-limit-reach :icon-name :multiline? :on-focus :on-blur])
:label :char-limit :on-char-limit-reach :icon-name :multiline?])
(defn- base-input
[{:keys [on-change-text on-char-limit-reach]}]
(let [status (reagent/atom :default)
internal-on-focus #(reset! status :focus)
internal-on-blur #(reset! status :default)
on-focus #(reset! status :focus)
on-blur #(reset! status :default)
multiple-lines? (reagent/atom false)
set-multiple-lines! #(let [height (oops/oget % "nativeEvent.contentSize.height")]
(if (> height 57)
@@ -74,7 +68,7 @@
(when (>= amount-chars char-limit)
(on-char-limit-reach amount-chars))))]
(fn [{:keys [blur? override-theme error? right-icon left-icon disabled? small? button
label char-limit multiline? clearable? on-focus on-blur]
label char-limit multiline? clearable?]
:as props}]
(let [status-kw (cond
disabled? :disabled
@@ -83,7 +77,7 @@
colors-by-status (style/status-colors status-kw blur? override-theme)
variant-colors (style/variants-colors blur? override-theme)
clean-props (apply dissoc props custom-props)]
[:<>
[rn/view
(when (or label char-limit)
[label-&-counter
{:variant-colors variant-colors
@@ -98,16 +92,11 @@
:icon-name icon-name}])
[rn/text-input
(cond-> {:style (style/input colors-by-status small? @multiple-lines?)
:accessibility-label :input
:placeholder-text-color (:placeholder colors-by-status)
:cursor-color (:cursor variant-colors)
:editable (not disabled?)
:on-focus (fn []
(when on-focus (on-focus))
(internal-on-focus))
:on-blur (fn []
(when on-blur (on-blur))
(internal-on-blur))}
:on-focus on-focus
:on-blur on-blur}
:always (merge clean-props)
multiline? (assoc :multiline true
:on-content-size-change set-multiple-lines!)
@@ -137,13 +126,12 @@
(fn [props]
[base-input
(assoc props
:accessibility-label :password-input
:auto-capitalize :none
:auto-complete :new-password
:secure-text-entry (not @password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if @password-shown? :i/hide :i/reveal)
:on-press #(swap! password-shown? not)})])))
:auto-capitalize :none
:auto-complete :new-password
:secure-text-entry (not @password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if @password-shown? :i/hide :i/reveal)
:on-press #(swap! password-shown? not)})])))
(defn input
"This input supports the following properties:
@@ -158,7 +146,7 @@
- :clearable? - Booolean to specify if this input has a clear button at the end.
- :on-clear - Function executed when the clear button is pressed.
- :button - Map containing `:on-press` & `:text` keys, if provided renders a button
- :label - A string to set as label for this input.
- :label - A label for this input.
- :char-limit - A number to set a maximum char limit for this input.
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
and supports the usual React Native's TextInput properties to control its behaviour:
@@ -25,13 +25,13 @@
:height 24
:borderRadius 12}]}
[user-avatar/user-avatar
(assoc image-picker-props
:customization-color customization-color
:full-name (if (seq full-name)
full-name
placeholder)
:status-indicator? false
:size :medium)]]
(merge image-picker-props
{:customization-color customization-color
:full-name (if (seq full-name)
full-name
placeholder)
:status-indicator? false
:size :medium})]]
[buttons/button
{:accessibility-label :select-profile-picture-button
:type :grey
@@ -47,6 +47,5 @@
[rn/view {:style style/input-container}
[title-input/title-input
(merge title-input-props
{:override-theme :dark
:placeholder placeholder
{:placeholder placeholder
:customization-color customization-color})]]]))
@@ -34,11 +34,9 @@
(def text-input-container {:flex 1})
(defn title-text
[disabled? blur? override-theme]
[disabled? blur?]
{:text-align-vertical :bottom
:color (if disabled?
(get-disabled-color blur?)
(colors/theme-colors colors/neutral-100 colors/white override-theme))})
:color (when disabled? (get-disabled-color blur?))})
(defn char-count
[blur?]
@@ -16,8 +16,7 @@
on-change-text
placeholder
max-length
default-value
override-theme]
default-value]
:or {max-length 0
default-value ""}}]
(let [focused? (reagent/atom false)
@@ -35,7 +34,7 @@
(text/text-style
{:size :heading-2
:weight :semi-bold
:style (style/title-text disabled? blur? override-theme)})
:style (style/title-text disabled? blur?)})
:default-value default-value
:accessibility-label :profile-title-input
:on-focus #(swap! focused? (fn [] true))
+22 -27
View File
@@ -30,16 +30,16 @@
{:no-color true})))
(defn left-section-view
[{:keys [on-press icon accessibility-label type icon-background-color] :or {type :grey}}
[{:keys [on-press icon accessibility-label type icon-override-theme] :or {type :grey}}
put-middle-section-on-left?]
[rn/view {:style (when put-middle-section-on-left? {:margin-right 5})}
[button/button
{:on-press on-press
:icon true
:type type
:size 32
:accessibility-label accessibility-label
:override-background-color icon-background-color}
{:on-press on-press
:icon true
:type type
:size 32
:accessibility-label accessibility-label
:override-theme icon-override-theme}
icon]])
(defn- mid-section-comp
@@ -150,15 +150,13 @@
:justify-content :flex-end)}
(let [last-icon-index (-> right-section-buttons count dec)]
(map-indexed (fn [index
{:keys [icon on-press type style icon-override-theme accessibility-label]
{:keys [icon on-press type style icon-override-theme]
:or {type :grey}}]
^{:key index}
[rn/view
(cond-> {:style (assoc style
:margin-right
(if (= index last-icon-index) 0 8))}
accessibility-label (assoc :accessibility-label accessibility-label
:accessible true))
{:style (assoc style
:margin-right
(if (= index last-icon-index) 0 8))}
[button/button
{:on-press on-press
:icon true
@@ -237,18 +235,15 @@
:align-items :center}}
(when left-section
[left-section-view left-section put-middle-section-on-left?])
(when mid-section
(cond
put-middle-section-on-left?
[mid-section-view
(assoc mid-section-props
:left-align? true
:description (:description mid-section)
:description-color (:description-color mid-section)
:description-icon (:description-icon mid-section)
:align-mid? align-mid?
:description-user-icon (:description-user-icon mid-section))]
(not put-middle-section-on-left?)
[mid-section-view mid-section-props]))]
(when put-middle-section-on-left?
[mid-section-view
(assoc mid-section-props
:left-align? true
:description (:description mid-section)
:description-color (:description-color mid-section)
:description-icon (:description-icon mid-section)
:align-mid? align-mid?
:description-user-icon (:description-user-icon mid-section))])]
(when-not put-middle-section-on-left?
[mid-section-view mid-section-props])
[right-section-view right-section-buttons]]))
+1 -2
View File
@@ -16,8 +16,7 @@
[text/text
{:style (style/tip-text completed?)
:weight :regular
:size :paragraph-2}
text]
:size :paragraph-2} text]
(when completed?
[rn/view
{:style style/strike-through
@@ -2,16 +2,14 @@
(:require [quo2.foundations.colors :as colors]))
(defn card-container
[{:keys [customization-color padding-bottom border-bottom-radius]}]
{:padding-horizontal 12
:padding-top 12
:padding-bottom padding-bottom
:flex 1
:border-top-left-radius 16
:border-top-right-radius 16
:border-bottom-left-radius border-bottom-radius
:border-bottom-right-radius border-bottom-radius
:background-color (colors/custom-color customization-color 50 40)})
[customization-color padding-bottom]
{:flex-direction :column
:padding-horizontal 12
:padding-top 12
:padding-bottom padding-bottom
:flex 1
:border-radius 16
:background-color (colors/custom-color customization-color 50 40)})
(def card-header
{:flex-direction :row
@@ -4,104 +4,77 @@
[quo2.components.icon :as icon]
[quo2.components.tags.tag :as tag]
[quo2.foundations.colors :as colors]
[react-native.hole-view :as hole-view]
[quo2.components.markdown.text :as text]
[quo2.components.buttons.button :as button]
[quo2.components.profile.profile-card.style :as style]
[quo2.components.avatars.user-avatar.view :as user-avatar]))
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.profile.profile-card.style :as style]))
(defn- profile-card-component
[{:keys [keycard-account? profile-picture name hash
customization-color emoji-hash on-options-press
show-emoji-hash? show-options-button? show-user-hash?
show-logged-in? on-card-press login-card? last-item? card-style]
(defn profile-card
[{:keys [key-card? profile-picture name hash customization-color
emoji-hash on-options-press show-emoji-hash? padding-bottom
show-options-button? show-user-hash? show-logged-in? on-card-press]
:or {show-emoji-hash? false
show-user-hash? false
customization-color :turquoise
show-options-button? false
show-logged-in? false
keycard-account? false
login-card? false
last-item? false
card-style {:padding-horizontal 20
:flex 1}}}]
(let [{:keys [width]} (rn/use-window-dimensions)
padding-bottom (cond
login-card? 38
show-emoji-hash? 12
:else 10)
border-bottom-radius (if (or (not login-card?) last-item?) 16 0)]
[rn/touchable-without-feedback
{:on-press on-card-press
:accessibility-label :profile-card}
[hole-view/hole-view
{:key (str name last-item?) ;; Key is required to force removal of holes
:style (merge {:flex-direction :row} card-style)
:holes (if (or (not login-card?) last-item?)
[]
[{:x 20
:y 108
:width (- width 40)
:height 50
:borderRadius 16}])}
[rn/view
{:style (style/card-container
{:customization-color customization-color
:padding-bottom padding-bottom
:border-bottom-radius border-bottom-radius})}
[rn/view
{:style style/card-header}
[user-avatar/user-avatar
{:full-name name
:profile-picture profile-picture
key-card? false}}]
[rn/touchable-without-feedback
{:on-press on-card-press
:flex 1
:accessibility-label :profile-card}
[rn/view
(style/card-container
customization-color
(or padding-bottom (if show-emoji-hash? 12 10)))
[rn/view
{:style style/card-header}
[user-avatar/user-avatar
{:full-name name
:profile-picture profile-picture
:override-theme :dark
:size :medium
:status-indicator? false}]
[rn/view {:flex-direction :row}
(when show-logged-in?
[tag/tag
{:type :icon
:size 32
:blurred? true
:labelled? true
:resource :main-icons2/check
:accessibility-label :logged-in-tag
:icon-color colors/success-50
:override-theme :dark
:size :medium
:status-indicator? false
:customization-color customization-color}]
[rn/view {:flex-direction :row}
(when show-logged-in?
[tag/tag
{:type :icon
:size 32
:blurred? true
:labelled? true
:resource :main-icons2/check
:accessibility-label :logged-in-tag
:icon-color colors/success-50
:override-theme :dark
:label (i18n/label :t/logged-in)}])
(when show-options-button?
[button/button
{:size 32
:type :blur-bg
:icon true
:override-theme :dark
:style style/option-button
:on-press on-options-press
:accessibility-label :profile-card-options}
:i/options])]]
[rn/view
{:style style/name-container}
[text/text
{:size :heading-2
:weight :semi-bold
:number-of-lines 1
:style style/user-name} name]
(when keycard-account?
(icon/icon
:i/keycard
style/keycard-icon))]
(when show-user-hash?
[text/text
{:weight :monospace
:number-of-lines 1
:style style/user-hash} hash])
(when (and show-emoji-hash? emoji-hash)
[text/text
{:weight :monospace
:number-of-lines 1
:style style/emoji-hash} emoji-hash])]]]))
(defn profile-card
[props]
[:f> profile-card-component props])
:label (i18n/label :t/logged-in)}])
(when show-options-button?
[button/button
{:size 32
:type :blur-bg
:icon true
:override-theme :dark
:style style/option-button
:on-press on-options-press
:accessibility-label :profile-card-options}
:i/options])]]
[rn/view
{:style style/name-container}
[text/text
{:size :heading-2
:weight :semi-bold
:number-of-lines 1
:style style/user-name} name]
(when key-card?
(icon/icon
:i/keycard
style/keycard-icon))]
(when show-user-hash?
[text/text
{:weight :monospace
:number-of-lines 1
:style style/user-hash} hash])
(when (and show-emoji-hash? emoji-hash)
[text/text
{:weight :monospace
:number-of-lines 1
:style style/emoji-hash} emoji-hash])]])
@@ -1,29 +0,0 @@
(ns quo2.components.selectors.disclaimer.component-spec
(:require [quo2.components.selectors.disclaimer.view :as disclaimer]
[test-helpers.component :as h]))
(h/describe "Disclaimer tests"
(h/test "Default render of toggle component"
(h/render [disclaimer/view {:on-change (h/mock-fn)} "test"])
(h/is-truthy (h/get-by-label-text :checkbox-off)))
(h/test "Renders its text"
(let [text "I accept this disclaimer"]
(h/render [disclaimer/view {} text])
(h/is-truthy (h/get-by-text text))))
(h/test "On change event gets fire after press"
(let [mock-fn (h/mock-fn)]
(h/render [disclaimer/view {:on-change mock-fn} "test"])
(h/fire-event :press (h/get-by-label-text :checkbox-off))
(h/was-called mock-fn)))
(h/describe "It's rendered according to its `checked?` property"
(h/test "checked? true"
(h/render [disclaimer/view {:checked? true} "test"])
(h/is-null (h/query-by-label-text :checkbox-off))
(h/is-truthy (h/query-by-label-text :checkbox-on)))
(h/test "checked? false"
(h/render [disclaimer/view {:checked? false} "test"])
(h/is-null (h/query-by-label-text :checkbox-on))
(h/is-truthy (h/query-by-label-text :checkbox-off)))))
@@ -2,16 +2,14 @@
(:require [quo2.foundations.colors :as colors]))
(defn container
[blur?]
(let [dark-background (if blur? colors/white-opa-5 colors/neutral-80-opa-40)
dark-border (if blur? colors/white-opa-10 colors/neutral-70)]
{:flex-direction :row
:background-color (colors/theme-colors colors/neutral-5 dark-background)
:padding 11
:align-self :stretch
:border-radius 12
:border-width 1
:border-color (colors/theme-colors colors/neutral-20 dark-border)}))
[]
{:flex-direction :row
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40)
:padding 11
:align-self :stretch
:border-radius 12
:border-width 1
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-70)})
(def text
{:margin-left 8})
@@ -5,13 +5,12 @@
[react-native.core :as rn]))
(defn view
[{:keys [checked? blur? on-change accessibility-label container-style]} label]
[{:keys [on-change accessibility-label container-style]} label]
[rn/view
{:style (merge container-style (style/container blur?))}
{:style (merge container-style (style/container))}
[selectors/checkbox
{:accessibility-label accessibility-label
:on-change on-change
:checked? checked?}]
:on-change on-change}]
[text/text
{:size :paragraph-2
:style style/text}
+10 -17
View File
@@ -5,10 +5,6 @@
[react-native.core :as rn]
[reagent.core :as reagent]))
(def themes-for-blur
{:light {:background-color colors/neutral-80-opa-5}
:dark {:background-color colors/white-opa-5}})
(def themes
{:light {:background-color colors/neutral-20}
:dark {:background-color colors/neutral-80}})
@@ -16,12 +12,11 @@
(defn segmented-control
[{:keys [default-active on-change]}]
(let [active-tab-id (reagent/atom default-active)]
(fn [{:keys [data size override-theme blur?]}]
(fn [{:keys [data size]}]
(let [active-id @active-tab-id]
[rn/view
{:flex-direction :row
:background-color (get-in (if blur? themes-for-blur themes)
[(or override-theme (theme/get-theme)) :background-color])
:background-color (get-in themes [(theme/get-theme) :background-color])
:border-radius (case size
32 10
28 8
@@ -34,14 +29,12 @@
{:margin-left (if (= 0 indx) 0 2)
:flex 1}
[tab/view
{:id id
:segmented? true
:size size
:override-theme override-theme
:blur? blur?
:active (= id active-id)
:on-press (fn [tab-id]
(reset! active-tab-id tab-id)
(when on-change
(on-change tab-id)))}
{:id id
:segmented? true
:size size
:active (= id active-id)
:on-press (fn [tab-id]
(reset! active-tab-id tab-id)
(when on-change
(on-change tab-id)))}
label]])]))))
+5 -6
View File
@@ -79,12 +79,11 @@
[notification-dot/notification-dot
{:style style/notification-dot}])
[rn/view
{:style (style/tab
{:size size
:disabled disabled
:segmented? segmented?
:background-color (if (and segmented? (not active)) :transparent background-color)
:show-notification-dot? show-notification-dot?})}
{:style (style/tab {:size size
:disabled disabled
:segmented? segmented?
:background-color background-color
:show-notification-dot? show-notification-dot?})}
(when before
[rn/view
[icons/icon before {:color icon-color}]])
-2
View File
@@ -60,7 +60,6 @@
quo2.components.settings.accounts.view
quo2.components.settings.privacy-option
quo2.components.onboarding.small-option-card.view
quo2.components.tabs.segmented-tab
quo2.components.tabs.account-selector
quo2.components.tabs.tabs
quo2.components.tags.context-tags
@@ -92,7 +91,6 @@
(def audio-tag quo2.components.tags.context-tags/audio-tag)
(def community-tag quo2.components.tags.context-tags/community-tag)
(def tabs quo2.components.tabs.tabs/tabs)
(def segmented-control quo2.components.tabs.segmented-tab/segmented-control)
(def account-selector quo2.components.tabs.account-selector/account-selector)
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
(def page-nav quo2.components.navigation.page-nav/page-nav)
+2 -4
View File
@@ -2,23 +2,21 @@
(:require [quo2.components.avatars.user-avatar.component-spec]
[quo2.components.banners.banner.component-spec]
[quo2.components.buttons.--tests--.buttons-component-spec]
[quo2.components.colors.color-picker.component-spec]
[quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.dividers.strength-divider.component-spec]
[quo2.components.drawers.action-drawers.component-spec]
[quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.permission-context.component-spec]
[quo2.components.inputs.input.component-spec]
[quo2.components.colors.color-picker.component-spec]
[quo2.components.inputs.profile-input.component-spec]
[quo2.components.inputs.title-input.component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
[quo2.components.password.tips.component-spec]
[quo2.components.profile.select-profile.component-spec]
[quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec]
[quo2.components.record-audio.soundtrack.--tests--.soundtrack-component-spec]
[quo2.components.profile.select-profile.component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.disclaimer.component-spec]
[quo2.components.selectors.filter.component-spec]
[quo2.components.tags.--tests--.status-tags-component-spec]))
+1 -6
View File
@@ -85,7 +85,6 @@
;;100 with transparency
(def neutral-100-opa-0 (alpha neutral-100 0))
(def neutral-100-opa-10 (alpha neutral-100 0.1))
(def neutral-100-opa-30 (alpha neutral-100 0.3))
(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))
@@ -237,11 +236,7 @@
([color suffix]
(custom-color color suffix nil))
([color suffix opacity]
(let [color-keyword (keyword color)
base-color (get-in colors-map
[(if (= color-keyword :yinyang)
(if (theme/dark?) :yang :yin)
(keyword color)) suffix])]
(let [base-color (get-in colors-map [(keyword color) suffix])]
(if opacity (alpha base-color (/ opacity 100)) base-color))))))
(defn custom-color-by-theme
-5
View File
@@ -1,5 +0,0 @@
(ns react-native.camera-kit
(:require ["react-native-camera-kit" :refer (CameraKitCamera)]
[reagent.core :as reagent]))
(def camera (reagent/adapt-react-class CameraKitCamera))
-4
View File
@@ -6,7 +6,3 @@
(let [kb (.useKeyboard hooks)]
{:keyboard-shown (.-keyboardShown ^js kb)
:keyboard-height (.-keyboardHeight ^js kb)}))
(defn use-back-handler
[handler]
(.useBackHandler hooks handler))
+7 -12
View File
@@ -21,8 +21,6 @@
[utils.collection]
[utils.worklets.core :as worklets.core]))
(def ^:const default-duration 300)
;; Animations
(def slide-in-up-animation SlideInUp)
(def slide-out-up-animation SlideOutUp)
@@ -67,7 +65,6 @@
(def in-out
(.-inOut ^js Easing))
;; trying to put default-easing inside easings map causes test to fail
(defn default-easing [] (in-out (.-quad ^js Easing)))
(def easings
@@ -118,15 +115,13 @@
(js-obj "duration" duration
"easing" (get easings easing))))))
(defn animate-delay
([animation val delay]
(animate-delay animation val delay default-duration))
([animation val delay duration]
(set-shared-value animation
(with-delay delay
(with-timing val
(clj->js {:duration duration
:easing (default-easing)}))))))
(defn animate-shared-value-with-delay-default-easing
[anim val duration delay]
(set-shared-value anim
(with-delay delay
(with-timing val
(js-obj "duration" duration
"easing" (in-out (.-quad ^js Easing)))))))
(defn animate-shared-value-with-repeat
[anim val duration easing number-of-repetitions reverse?]
+3 -5
View File
@@ -147,9 +147,8 @@
(defn build-image-messages
[{db :db} chat-id input-text]
(let [images (get-in db [:chat/inputs chat-id :metadata :sending-image])
{:keys [message-id]} (get-in db [:chat/inputs chat-id :metadata :responding-to-message])
album-id (str (random-uuid))]
(let [images (get-in db [:chat/inputs chat-id :metadata :sending-image])
album-id (str (random-uuid))]
(mapv (fn [[_ {:keys [resized-uri width height]}]]
{:chat-id chat-id
:album-id album-id
@@ -160,8 +159,7 @@
;; TODO: message not received if text field is
;; nil or empty, issue:
;; https://github.com/status-im/status-mobile/issues/14754
:text (or input-text "placeholder")
:response-to message-id})
:text (or input-text "placeholder")})
images)))
(rf/defn clean-input
+2 -2
View File
@@ -276,7 +276,7 @@
(vals (get-in db [:communities community-id :chats])))]
(when (and id
(not= (:current-chat-id db) (str community-id id)))
(chat.events/navigate-to-chat cofx (str community-id id)))))
(chat.events/navigate-to-chat cofx (str community-id id) nil))))
(rf/defn fetch
[_]
@@ -817,7 +817,7 @@
[cofx community-id]
(rf/merge cofx
(navigation/pop-to-root :shell-stack)
(navigation/navigate-to-cofx :community-overview community-id)))
(navigation/navigate-to-nav2 :community community-id true)))
(rf/defn member-role-updated
{:events [:community.member/role-updated]}
+1 -1
View File
@@ -202,7 +202,7 @@
(defn words-count
[s]
(if (empty? s)
0
nil
(-> s
passphrase->words
count)))
+1 -2
View File
@@ -57,7 +57,6 @@
status-im2.contexts.activity-center.events
status-im2.contexts.activity-center.notification.contact-requests.events
status-im2.contexts.shell.events
status-im2.contexts.onboarding.events
status-im.chat.models.gaps
[status-im2.navigation.events :as navigation]))
@@ -117,7 +116,7 @@
(let [current-theme-type (get-in cofx [:db :multiaccount :appearance])]
(when (and (multiaccounts.model/logged-in? cofx)
(= current-theme-type status-im2.constants/theme-type-system))
{:multiaccounts.ui/switch-theme-fx
{:multiaccounts.ui/switch-theme
[(get-in db [:multiaccount :appearance])
(:view-id db) true]})))
+1 -1
View File
@@ -15,7 +15,7 @@
{:events [:navigate-chat-updated]}
[cofx chat-id]
(when (get-in cofx [:db :chats chat-id])
(chat.events/navigate-to-chat cofx chat-id)))
(chat.events/navigate-to-chat cofx chat-id nil)))
(rf/defn handle-chat-removed
{:events [:chat-removed]}
+1 -1
View File
@@ -17,7 +17,7 @@
[{:keys [db] :as cofx}]
(rf/merge cofx
{:db db}
(navigation/pop-to-root :profiles)))
(navigation/pop-to-root :multiaccounts-stack)))
(rf/defn login-pin-more-icon-pressed
{:events [:keycard.login.pin.ui/more-icon-pressed]}
+1 -3
View File
@@ -1,6 +1,5 @@
(ns status-im.mobile-sync-settings.core
(:require [status-im2.common.bottom-sheet.events :as bottom-sheet]
[status-im2.contexts.add-new-contact.events :as add-new-contact]
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.multiaccounts.update.core :as multiaccounts.update]
@@ -43,8 +42,7 @@
(and logged-in? initialized?)
[(mailserver/process-next-messages-request)
(bottom-sheet/hide-bottom-sheet)
(wallet/restart-wallet-service nil)
(add-new-contact/set-new-identity-reconnected)]
(wallet/restart-wallet-service nil)]
logged-in?
[(mailserver/process-next-messages-request)
+6 -13
View File
@@ -5,13 +5,14 @@
[status-im2.common.bottom-sheet.events :as bottom-sheet]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.native-module.core :as native-module]
[status-im.theme.core :as theme]
[utils.re-frame :as rf]
[quo2.foundations.colors :as colors]
[status-im2.constants :as constants]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]
[status-im2.setup.hot-reload :as hot-reload]
[status-im2.common.theme.core :as theme]
[status-im2.common.theme.core :as utils.theme]
[taoensso.timbre :as log]
[status-im2.contexts.shell.animation :as shell.animation]
[status-im.contact.db :as contact.db]))
@@ -136,16 +137,16 @@
{::blank-preview-flag-changed private?}))
(re-frame/reg-fx
:multiaccounts.ui/switch-theme-fx
:multiaccounts.ui/switch-theme
(fn [[theme-type view-id reload-ui?]]
(let [[theme status-bar-theme nav-bar-color]
;; Status bar theme represents status bar icons colors, so opposite to app theme
(if (or (= theme-type constants/theme-type-dark)
(and (= theme-type constants/theme-type-system)
(theme/device-theme-dark?)))
(utils.theme/dark-mode?)))
[:dark :light colors/neutral-100]
[:light :dark colors/white])]
(theme/set-theme theme)
(theme/change-theme theme)
(re-frame/dispatch [:change-root-status-bar-style
(if (shell.animation/home-stack-open?) status-bar-theme :light)])
(when reload-ui?
@@ -157,17 +158,9 @@
{:events [:multiaccounts.ui/appearance-switched]}
[cofx theme]
(rf/merge cofx
{:multiaccounts.ui/switch-theme-fx [theme :appearance true]}
{:multiaccounts.ui/switch-theme [theme :appearance true]}
(multiaccounts.update/multiaccount-update :appearance theme {})))
(rf/defn switch-theme
{:events [:multiaccounts.ui/switch-theme]}
[cofx theme view-id]
(let [theme (or theme
(get-in cofx [:db :multiaccount :appearance])
constants/theme-type-dark)]
{:multiaccounts.ui/switch-theme-fx [theme view-id false]}))
(rf/defn switch-profile-picture-show-to
{:events [:multiaccounts.ui/profile-picture-show-to-switched]}
[cofx id]
+11 -18
View File
@@ -44,7 +44,6 @@
[status-im2.navigation.events :as navigation]
[status-im2.common.log :as logging]
[taoensso.timbre :as log]
[status-im2.contexts.shell.animation :as shell.animation]
[utils.security.core :as security]))
(re-frame/reg-fx
@@ -339,6 +338,10 @@
{:method "permissions_getDappPermissions"
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
(rf/defn initialize-appearance
[cofx]
{:multiaccounts.ui/switch-theme [(get-in cofx [:db :multiaccount :appearance]) nil false]})
(rf/defn get-group-chat-invitations
[_]
{:json-rpc/call
@@ -390,6 +393,7 @@
#(do (re-frame/dispatch [:chats-list/load-success %])
(rf/dispatch [:communities/get-user-requests-to-join])
(re-frame/dispatch [::get-chats-callback]))})
(initialize-appearance)
(initialize-wallet-connect)
(get-node-config)
(communities/fetch)
@@ -475,17 +479,8 @@
(defn redirect-to-root
"Decides which root should be initialised depending on user and app state"
[db]
(cond
(get db :local-pairing/completed-pairing?)
(re-frame/dispatch [:syncing/pairing-completed])
(get db :onboarding-2/new-account?)
(re-frame/dispatch [:navigate-to :enable-notifications])
(get db :tos/accepted?)
(if (get db :tos/accepted?)
(re-frame/dispatch [:init-root :shell-stack])
:else
(re-frame/dispatch [:init-root :tos])))
(rf/defn login-only-events
@@ -519,11 +514,10 @@
tos-accepted? (get db :tos/accepted?)
{:networks/keys [current-network networks]} db
network-id (str (get-in networks [current-network :config :NetworkId]))]
(shell.animation/change-selected-stack-id :communities-stack true)
(rf/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)
(assoc :tos/next-root :enable-notifications :chats/loading? false)
(assoc :tos/next-root :onboarding-notification :chats/loading? false)
(assoc-in [:multiaccount :multiaccounts/first-account] first-account?))
::get-tokens [network-id accounts recovered-account?]}
(finish-keycard-setup)
@@ -534,7 +528,7 @@
(multiaccounts/switch-preview-privacy-mode-flag)
(link-preview/request-link-preview-whitelist)
(logging/set-log-level (:log-level multiaccount))
(navigation/init-root :enable-notifications))))
(navigation/init-root :shell-stack))))
(defn- keycard-setup?
[cofx]
@@ -637,7 +631,7 @@
(assoc-in [:keycard :pin :login] []))})
#(if keycard-account?
{:init-root-fx :multiaccounts-keycard}
{:init-root-fx :profiles})
{:init-root-fx :multiaccounts})
#(when goto-key-storage?
(navigation/navigate-to-cofx % :actions-not-logged-in nil))))))
@@ -736,9 +730,8 @@
keycard-multiaccount? (boolean (:keycard-pairing multiaccount))]
(rf/merge
cofx
(merge
{:db (update db :keycard dissoc :application-info)}
(when keycard-multiaccount? {:navigate-to-fx :keycard-login-pin}))
{:db (update db :keycard dissoc :application-info)
:navigate-to-fx (if keycard-multiaccount? :keycard-login-pin :login)}
(open-login (select-keys multiaccount [:key-uid :name :public-key :identicon :images])))))
(rf/defn hide-keycard-banner
-20
View File
@@ -91,14 +91,6 @@
key-uid
#(.loginWithConfig ^js (status) account-data hashed-password config))))
(defn create-account-and-login
[request]
(.createAccountAndLogin ^js (status) (types/clj->json request)))
(defn restore-account-and-login
[request]
(.restoreAccountAndLogin ^js (status) (types/clj->json request)))
(defn export-db
"NOTE: beware, the password has to be sha3 hashed"
[key-uid account-data hashed-password callback]
@@ -619,15 +611,3 @@
current-password#
new-password
callback))
(defn backup-disabled-data-dir
[]
(.backupDisabledDataDir ^js (status)))
(defn keystore-dir
[]
(.keystoreDir ^js (status)))
(defn log-file-path
[]
(.logFilePath ^js (status)))
+6 -40
View File
@@ -9,10 +9,7 @@
[status-im.visibility-status-updates.core :as visibility-status-updates]
[utils.re-frame :as rf]
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
[taoensso.timbre :as log]
[status-im2.constants :as constants]
[quo2.foundations.colors :as colors]
[status-im.multiaccounts.model :as multiaccounts.model]))
[taoensso.timbre :as log]))
(rf/defn status-node-started
[{db :db :as cofx} {:keys [error]}]
@@ -56,40 +53,10 @@
:peer-stats peer-stats
:peers-count (count (:peers peer-stats)))}))
(rf/defn handle-local-pairing-signals
[{:keys [db] :as cofx} event]
(log/info "local pairing signal received"
{:event event})
(let [connection-success? (= (:type event)
constants/local-pairing-event-connection-success)
error-on-pairing? (contains? constants/local-pairing-event-errors (:type event))
completed-pairing? (and (= (:type event)
constants/local-pairing-event-process-success)
(= (:action event)
constants/local-pairing-action-pairing-account))
logged-in? (multiaccounts.model/logged-in? cofx)
;; since `connection-success` event is received on both sender and receiver devices
;; we check the `logged-in?` status to identify the receiver and take the user to next screen
navigate-to-syncing-devices? (and connection-success? (not logged-in?))
user-in-syncing-devices-screen? (= (:view-id db) :syncing-devices)]
(merge {:db (cond-> db
connection-success?
(assoc :local-pairing/completed-pairing? false)
error-on-pairing?
(dissoc :local-pairing/completed-pairing?)
completed-pairing?
(assoc :local-pairing/completed-pairing? true))}
(when navigate-to-syncing-devices?
{:dispatch [:navigate-to :syncing-devices]})
(when (and error-on-pairing? user-in-syncing-devices-screen?)
{:dispatch-n [[:toasts/upsert
{:icon :i/info
:icon-color colors/danger-50
:override-theme :light
:text (i18n/label :t/error-syncing-connection-failed)}]
[:navigate-back]]}))))
(defn handle-local-pairing-signals
[event]
(log/debug "local pairing signal received"
{:event event}))
(rf/defn process
{:events [:signals/signal-received]}
@@ -143,6 +110,5 @@
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
cofx
(js->clj event-js :keywordize-keys true))
"localPairing" (handle-local-pairing-signals cofx
(js->clj event-js :keywordize-keys true))
"localPairing" (handle-local-pairing-signals (js->clj event-js :keywordize-keys true))
(log/debug "Event " type " not handled"))))
+8
View File
@@ -0,0 +1,8 @@
(ns status-im.theme.core
(:require [quo.theme :as quo.theme]
[quo2.theme :as quo2.theme]))
(defn change-theme
[theme]
(quo.theme/set-theme theme)
(quo2.theme/set-theme theme))
@@ -48,7 +48,7 @@
:on-press (fn []
(rf/dispatch [:communities/load-category-states id])
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community-overview id]))
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[community/community-actions community])}])}
@@ -111,7 +111,7 @@
(i18n/label :t/open-membership))]]
:on-press #(do
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community-overview id]))}]))
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))}]))
(defn communities-actions
[]
@@ -12,7 +12,7 @@
[]
[quo/list-item
{:theme :accent
:on-press #(hide-sheet-and-dispatch [:navigate-to :intro])
:on-press #(hide-sheet-and-dispatch [:generate-and-derive-addresses])
:icon :main-icons/add
:accessibility-label :generate-a-new-key
:title (i18n/label :t/generate-a-new-key)}])
@@ -377,14 +377,14 @@
:height 40}}]
[communities.icon/community-icon community])]
[rn/view {:padding-right 14 :flex 1}
[rn/text {:style {:font-weight "700" :font-size 17 :color quo.colors/black}}
[rn/text {:style {:font-weight "700" :font-size 17}}
name]
[rn/text {:style {:color quo.colors/black}} description]]]
[rn/text description]]]
[rn/view (style/community-view-button)
[rn/touchable-opacity
{:on-press #(re-frame/dispatch
[:communities/navigate-to-community
(:id community)])}
{:community-id (:id community)}])}
[rn/text
{:style {:text-align :center
:color quo.colors/blue}} (i18n/label :t/view)]]]])))
+4 -8
View File
@@ -225,12 +225,8 @@
(defn format-members
[count]
(cond
(> count 1000000)
(if (> count 1000000)
(str (with-precision (/ count 1000000) 1) (i18n/label :t/M))
(< 999 count 1000000)
(str (with-precision (/ count 1000) 1) (i18n/label :t/K))
:else
count))
(if (and (> count 999) (< count 1000000))
(str (with-precision (/ count 1000) 1) (i18n/label :t/K))
count)))
@@ -1,42 +0,0 @@
(ns status-im2.common.bottom-sheet-screen.style
(:require
[quo2.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
(defn background
[opacity]
(reanimated/apply-animations-to-style
{:opacity opacity}
{:background-color colors/neutral-100-opa-70
:position :absolute
:top 0
:bottom 0
:left 0
:right 0}))
(defn main-view
[translate-y]
(reanimated/apply-animations-to-style
{:transform [{:translate-y translate-y}]}
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:border-top-left-radius 20
:border-top-right-radius 20
:flex 1
:overflow :hidden}))
(def handle-container
{:left 0
:right 0
:top 0
:height 20
:z-index 1
:position :absolute
:justify-content :center
:align-items :center})
(defn handle
[]
{:width 32
:height 4
:border-radius 100
:background-color (colors/theme-colors colors/neutral-100-opa-30 colors/white-opa-30)})
@@ -1,81 +0,0 @@
(ns status-im2.common.bottom-sheet-screen.view
(:require
[react-native.gesture :as gesture]
[react-native.hooks :as hooks]
[react-native.navigation :as navigation]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[oops.core :as oops]
[react-native.safe-area :as safe-area]
[status-im2.common.bottom-sheet-screen.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.re-frame :as rf]))
(def ^:const drag-threshold 100)
(defn drag-gesture
[translate-y opacity scroll-enabled curr-scroll]
(->
(gesture/gesture-pan)
(gesture/on-start (fn [e]
(when (< (oops/oget e "velocityY") 0)
(reset! scroll-enabled true))))
(gesture/on-update (fn [e]
(let [translation (oops/oget e "translationY")
progress (Math/abs (/ translation drag-threshold))]
(when (pos? translation)
(reanimated/set-shared-value translate-y translation)
(reanimated/set-shared-value opacity (- 1 (/ progress 5)))))))
(gesture/on-end (fn [e]
(if (> (oops/oget e "translationY") drag-threshold)
(do
(reanimated/set-shared-value opacity (reanimated/with-timing-duration 0 100))
(rf/dispatch [:navigate-back]))
(do
(reanimated/set-shared-value opacity (reanimated/with-timing 1))
(reanimated/set-shared-value translate-y (reanimated/with-timing 0))
(reset! scroll-enabled true)))))
(gesture/on-finalize (fn [e]
(when (and (>= (oops/oget e "velocityY") 0)
(<= @curr-scroll (if platform/ios? -1 0)))
(reset! scroll-enabled false))))))
(defn on-scroll
[e curr-scroll]
(let [y (oops/oget e "nativeEvent.contentOffset.y")]
(reset! curr-scroll y)))
(defn view
[content skip-background?]
[:f>
(let [scroll-enabled (reagent/atom true)
curr-scroll (atom 0)]
(fn []
(let [sb-height (navigation/status-bar-height)
insets (safe-area/use-safe-area)
padding-top (Math/max sb-height (:top insets))
padding-top (if platform/ios? padding-top (+ padding-top 10))
opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value 0)
close (fn []
(reanimated/set-shared-value opacity (reanimated/with-timing-duration 0 100))
(rf/dispatch [:navigate-back]))]
(rn/use-effect
(fn []
(reanimated/animate-delay opacity 1 (if platform/ios? 300 100))))
(hooks/use-back-handler close)
[rn/view
{:style {:flex 1
:padding-top padding-top}}
(when-not skip-background?
[reanimated/view {:style (style/background opacity)}])
[gesture/gesture-detector
{:gesture (drag-gesture translate-y opacity scroll-enabled curr-scroll)}
[reanimated/view {:style (style/main-view translate-y)}
[rn/view {:style style/handle-container}
[rn/view {:style (style/handle)}]]
[content
{:close close
:scroll-enabled @scroll-enabled
:on-scroll #(on-scroll % curr-scroll)}]]]])))])
@@ -26,23 +26,18 @@
[quo/text {:style {:margin-left 10}} extra-text]]))
(defn confirmation-drawer
[{:keys [title description context button-text on-press extra-action extra-text accessibility-label
close-button-text]}]
[{:keys [title description context button-text on-press extra-action extra-text accessibility-label]}]
(let [extra-action-selected? (reagent/atom false)]
(fn []
(let [{:keys [group-chat chat-id public-key color profile-picture
name]} context
id (or chat-id public-key)
display-name (or
name
(when-not group-chat
(rf/sub [:contacts/contact-name-by-identity id])))
contact (when-not group-chat
(rf/sub [:contacts/contact-by-address
id]))
photo-path (or profile-picture
(when-not (empty? (:images contact))
(rf/sub [:chats/photo-path id])))]
(let [{:keys [group-chat chat-id public-key color name]} context
id (or chat-id public-key)
display-name
(if-not group-chat (first (rf/sub [:contacts/contact-two-names-by-identity id])) name)
contact (when-not group-chat
(rf/sub [:contacts/contact-by-address
id]))
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path id]))]
[rn/view
{:style {:margin-horizontal 20}
:accessibility-label accessibility-label}
@@ -62,7 +57,7 @@
{:type :grey
:style {:flex 0.48} ;;WUT? 0.48 , whats that ?
:on-press #(rf/dispatch [:bottom-sheet/hide])}
(or close-button-text (i18n/label :t/close))]
(i18n/label :t/close)]
[quo/button
{:type :danger
:style {:flex 0.48}
+21 -25
View File
@@ -89,7 +89,7 @@
(defn display-picture
[scroll-height logo]
[scroll-height cover]
(let [input-range (if platform/ios? [-67 10] [0 150])
y (reanimated/use-shared-value scroll-height)
animation (reanimated/interpolate y
@@ -104,7 +104,7 @@
[reanimated/view
{:style (style/display-picture-container animation)}
[rn/image
{:source logo
{:source cover
:style style/display-picture}]]))
(defn scroll-page
@@ -117,7 +117,7 @@
[:<>
[:f> scroll-page-header @scroll-height height name page-nav-right-section-buttons
logo sticky-header top-nav title-colum navigate-back?]
[rn/flat-list
[rn/scroll-view
{:content-container-style (style/scroll-view-container
(diff-with-max-min @scroll-height 16 0))
:shows-vertical-scroll-indicator false
@@ -128,25 +128,21 @@
event
"nativeEvent.contentOffset.y")))
(when on-scroll
(on-scroll @scroll-height)))
:header [rn/view
(when cover-image
[rn/view {:style {:height 151}}
[rn/image
{:source cover-image
;; Using negative margin-bottom as a workaround because
;; on Android,
;; ScrollView clips its children despite setting
;; overflow: 'visible'.
;; Related issue:
;; https://github.com/facebook/react-native/issues/31218
:style {:margin-bottom -16
:flex 1}}]])
(when children
[rn/view
{:flex 1
:border-radius (diff-with-max-min @scroll-height 16 0)
:background-color background-color}
(when cover-image
[:f> display-picture @scroll-height logo])
children])]}]])))
(on-scroll @scroll-height)))}
(when cover-image
[rn/view {:style {:height 151}}
[rn/image
{:source cover-image
;; Using negative margin-bottom as a workaround because on Android,
;; ScrollView clips its children despite setting overflow: 'visible'.
;; Related issue: https://github.com/facebook/react-native/issues/31218
:style {:margin-bottom -16
:flex 1}}]])
(when children
[rn/view
{:flex 1
:border-radius (diff-with-max-min @scroll-height 16 0)
:background-color background-color}
(when cover-image
[:f> display-picture @scroll-height logo])
children])]])))
+9 -16
View File
@@ -1,24 +1,17 @@
(ns status-im2.common.theme.core
(:require [quo.theme :as quo]
[quo2.theme :as quo2]
[react-native.core :as rn]))
(:require [react-native.core :as rn]))
(def device-theme (atom (rn/get-color-scheme)))
(def initial-mode (atom (rn/get-color-scheme)))
;; Note - don't use value returned by change listener
;; https://github.com/facebook/react-native/issues/28525
(defn add-device-theme-change-listener
(defn add-mode-change-listener
[callback]
(rn/appearance-add-change-listener #(let [theme (rn/get-color-scheme)]
(when-not (= theme @device-theme)
(reset! device-theme theme)
(callback (keyword theme))))))
(rn/appearance-add-change-listener #(let [mode (rn/get-color-scheme)]
(when-not (= mode @initial-mode)
(reset! initial-mode mode)
(callback (keyword mode))))))
(defn device-theme-dark?
(defn dark-mode?
[]
(= @device-theme "dark"))
(defn set-theme
[value]
(quo/set-theme value)
(quo2/set-theme value))
(= @initial-mode "dark"))
-31
View File
@@ -90,9 +90,6 @@
(def ^:const command-state-transaction-pending 6)
(def ^:const command-state-transaction-sent 7)
(def ^:const profile-default-color :blue)
(def ^:const profile-name-max-length 24)
(def ^:const profile-pictures-show-to-contacts-only 1)
(def ^:const profile-pictures-show-to-everyone 2)
(def ^:const profile-pictures-show-to-none 3)
@@ -263,27 +260,6 @@
An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 "
"cs")
;; sender and receiver events
(def ^:const local-pairing-event-connection-success "connection-success")
(def ^:const local-pairing-event-connection-error "connection-error")
(def ^:const local-pairing-event-transfer-success "transfer-success")
(def ^:const local-pairing-event-transfer-error "transfer-error")
;; receiver events
(def ^:const local-pairing-event-received-amount "received-account")
(def ^:const local-pairing-event-process-success "process-success")
(def ^:const local-pairing-event-process-error "process-error")
(def ^:const local-pairing-event-errors
#{local-pairing-event-connection-error
local-pairing-event-transfer-error
local-pairing-event-process-error})
(def ^:const local-pairing-action-connect 1)
(def ^:const local-pairing-action-pairing-account 2)
(def ^:const local-pairing-action-sync-device 3)
(def ^:const local-pairing-action-pairing-installation 4)
(def ^:const serialization-key
"We pass this serialization key as a parameter to MultiformatSerializePublicKey
function at status-go, This key determines the output base of the serialization.
@@ -316,10 +292,3 @@
(def ^:const everyone-mention-id "0x00001")
(def ^:const empty-category-id :communities/not-categorized)
(def ^:const seed-phrase-valid-length #{12 18 24})
(def ^:const auth-method-password "password")
(def ^:const auth-method-biometric "biometric")
(def ^:const auth-method-biometric-prepare "biometric-prepare")
(def ^:const auth-method-none "none")
@@ -1,5 +1,6 @@
(ns status-im2.contexts.activity-center.notification.contact-requests.events
(:require [taoensso.timbre :as log]
(:require [status-im2.contexts.activity-center.events :as ac-events]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/defn accept-contact-request
@@ -18,7 +19,8 @@
(log/error "Failed to accept contact-request"
{:error error
:event :activity-center.contact-requests/accept
:contact-id contact-id}))
:contact-id contact-id})
nil)
(rf/defn decline-contact-request
{:events [:activity-center.contact-requests/decline]}
@@ -36,4 +38,32 @@
(log/error "Failed to decline contact-request"
{:error error
:event :activity-center.contact-requests/decline
:contact-id contact-id}))
:contact-id contact-id})
nil)
(rf/defn cancel-outgoing-contact-request
{:events [:activity-center.contact-requests/cancel-outgoing]}
[{:keys [db]} {:keys [contact-id notification-id]}]
(when-let [notification (ac-events/get-notification db notification-id)]
{:json-rpc/call
[{:method "wakuext_cancelOutgoingContactRequest"
:params [{:id contact-id}]
:on-success #(rf/dispatch [:activity-center.contact-requests/cancel-outgoing-success
notification])
:on-error #(rf/dispatch [:activity-center.contact-requests/cancel-outgoing-error contact-id
%])}]}))
(rf/defn cancel-outgoing-contact-request-success
{:events [:activity-center.contact-requests/cancel-outgoing-success]}
[_ notification]
{:dispatch [:activity-center.notifications/reconcile
[(assoc notification :deleted true)]]})
(rf/defn cancel-outgoing-contact-request-error
{:events [:activity-center.contact-requests/cancel-outgoing-error]}
[_ contact-id error]
(log/error "Failed to cancel outgoing contact-request"
{:error error
:event :activity-center.contact-requests/cancel-outgoing
:contact-id contact-id})
nil)
@@ -1,13 +1,12 @@
(ns status-im2.contexts.activity-center.notification.contact-requests.view
(:require
[quo2.core :as quo]
[react-native.gesture :as gesture]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.notification.common.style :as common-style]
[status-im2.contexts.activity-center.notification.common.view :as common]
[utils.datetime :as datetime]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(:require [quo2.core :as quo]
[react-native.gesture :as gesture]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.notification.common.style :as common-style]
[status-im2.contexts.activity-center.notification.common.view :as common]
[utils.datetime :as datetime]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- swipe-button-accept
[{:keys [style]} _]
@@ -23,17 +22,24 @@
:icon :i/placeholder
:text (i18n/label :t/decline)}])
(defn- swipe-button-cancel-pending
[{:keys [style]} _]
[common/swipe-button-container
{:style (common-style/swipe-danger-container style)
:icon :i/placeholder
:text (i18n/label :t/cancel)}])
(defn- swipeable
[{:keys [active-swipeable extra-fn notification]} child]
(let [{:keys [id author message]} notification
{:keys [contact-request-state]} message
{:keys [public-key]} (rf/sub [:multiaccount/contact])
outgoing? (= public-key author)]
(let [{:keys [id author message last-message]} notification
{:keys [contact-request-state]} (or (:message notification)
(:last-message notification))
{:keys [public-key]} (rf/sub [:multiaccount/contact])
message (or message last-message)]
(cond
(or (#{constants/contact-request-message-state-accepted
constants/contact-request-message-state-declined}
contact-request-state)
(and outgoing? (= contact-request-state constants/contact-request-message-state-pending)))
(#{constants/contact-request-message-state-accepted
constants/contact-request-message-state-declined}
contact-request-state)
[common/swipeable
{:left-button common/swipe-button-read-or-unread
:left-on-press common/swipe-on-press-toggle-read
@@ -43,23 +49,33 @@
:extra-fn extra-fn}
child]
(and (= contact-request-state constants/contact-request-message-state-pending)
(not outgoing?))
[common/swipeable
{:left-button swipe-button-accept
:left-on-press #(rf/dispatch [:activity-center.contact-requests/accept id])
:right-button swipe-button-decline
:right-on-press #(rf/dispatch [:activity-center.contact-requests/decline id])
:active-swipeable active-swipeable
:extra-fn extra-fn}
child]
(= contact-request-state constants/contact-request-message-state-pending)
(if (= public-key author)
[common/swipeable
{:right-button swipe-button-cancel-pending
:right-on-press (fn []
(rf/dispatch
[:activity-center.contact-requests/cancel-outgoing
{:contact-id (:from message)
:notification-id id}]))
:active-swipeable active-swipeable
:extra-fn extra-fn}
child]
[common/swipeable
{:left-button swipe-button-accept
:left-on-press #(rf/dispatch [:activity-center.contact-requests/accept id])
:right-button swipe-button-decline
:right-on-press #(rf/dispatch [:activity-center.contact-requests/decline id])
:active-swipeable active-swipeable
:extra-fn extra-fn}
child])
:else
child)))
(defn- outgoing-contact-request-view
[{:keys [notification set-swipeable-height]}]
(let [{:keys [chat-id message last-message]} notification
(let [{:keys [id chat-id message last-message]} notification
{:keys [contact-request-state] :as message} (or message last-message)]
(if (= contact-request-state constants/contact-request-message-state-accepted)
[quo/activity-log
@@ -83,7 +99,17 @@
:message {:body (get-in message [:content :text])}
:items (case contact-request-state
constants/contact-request-message-state-pending
[{:type :status
[{:type :button
:subtype :danger
:key :button-cancel
:label (i18n/label :t/cancel)
:accessibility-label :cancel-contact-request
:on-press (fn []
(rf/dispatch
[:activity-center.contact-requests/cancel-outgoing
{:contact-id (:from message)
:notification-id id}]))}
{:type :status
:subtype :pending
:key :status-pending
:blur? true
@@ -1,6 +1,5 @@
(ns status-im2.contexts.add-new-contact.events
(:require [clojure.string :as string]
[utils.re-frame :as rf]
(:require [utils.re-frame :as rf]
[status-im.utils.types :as types]
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
@@ -12,120 +11,11 @@
[status-im2.contexts.contacts.events :as data-store.contacts]
[status-im.utils.utils :as utils]))
(defn init-contact
"Create a new contact (persisted to app-db as [:contacts/new-identity]).
The following options are available:
| key | description |
| -------------------|-------------|
| `:user-public-key` | user's public key (not the contact)
| `:input` | raw user input (untrimmed)
| `:scanned` | scanned user input (untrimmed)
| `:id` | public-key|compressed-key|ens
| `:type` | :empty|:public-key|:compressed-key|:ens
| `:ens` | id.eth|id.ens-stateofus
| `:public-key` | public-key (from decompression or ens resolution)
| `:state` | :empty|:invalid|:decompress-key|:resolve-ens|:valid
| `:msg` | keyword i18n msg"
([]
(-> [:user-public-key :input :scanned :id :type :ens :public-key :state :msg]
(zipmap (repeat nil))))
([kv] (-> (init-contact) (merge kv))))
(def url-regex #"^https?://join.status.im/u/(.+)")
(defn ->id
[{:keys [input] :as contact}]
(let [trimmed-input (utils/safe-trim input)]
(->> {:id (if (empty? trimmed-input)
nil
(if-some [[_ id] (re-matches url-regex trimmed-input)]
id
trimmed-input))}
(merge contact))))
(defn ->type
[{:keys [id] :as contact}]
(->> (cond
(empty? id)
{:type :empty}
(validators/valid-public-key? id)
{:type :public-key
:public-key id}
(validators/valid-compressed-key? id)
{:type :compressed-key}
:else
{:type :ens
:ens (stateofus/ens-name-parse id)})
(merge contact)))
(defn ->state
[{:keys [id type public-key user-public-key] :as contact}]
(->> (cond
(empty? id)
{:state :empty}
(= type :public-key)
{:state :invalid
:msg :t/not-a-chatkey}
(= public-key user-public-key)
{:state :invalid
:msg :t/can-not-add-yourself}
(and (= type :compressed-key) (empty? public-key))
{:state :decompress-key}
(and (= type :ens) (empty? public-key))
{:state :resolve-ens}
(and (or (= type :compressed-key) (= type :ens))
(validators/valid-public-key? public-key))
{:state :valid})
(merge contact)))
(def validate-contact (comp ->state ->type ->id))
(defn dispatcher [event input] (fn [arg] (rf/dispatch [event input arg])))
(rf/defn set-new-identity
{:events [:contacts/set-new-identity]}
[{:keys [db]} input scanned]
(let [user-public-key (get-in db [:multiaccount :public-key])
{:keys [input id ens state]
:as contact} (-> {:user-public-key user-public-key
:input input
:scanned scanned}
init-contact
validate-contact)]
(case state
:empty {:db (dissoc db :contacts/new-identity)}
(:valid :invalid) {:db (assoc db :contacts/new-identity contact)}
:decompress-key {:db (assoc db :contacts/new-identity contact)
:contacts/decompress-public-key
{:compressed-key id
:on-success
(dispatcher :contacts/set-new-identity-success input)
:on-error
(dispatcher :contacts/set-new-identity-error input)}}
:resolve-ens {:db (assoc db :contacts/new-identity contact)
:contacts/resolve-public-key-from-ens
{:chain-id (ethereum/chain-id db)
:ens ens
:on-success
(dispatcher :contacts/set-new-identity-success input)
:on-error
(dispatcher :contacts/set-new-identity-error input)}})))
(re-frame/reg-fx
:contacts/decompress-public-key
(fn [{:keys [compressed-key on-success on-error]}]
(fn [{:keys [public-key on-success on-error]}]
(status/compressed-key->public-key
compressed-key
public-key
(fn [resp]
(let [{:keys [error]} (types/json->clj resp)]
(if error
@@ -133,16 +23,74 @@
(on-success (str "0x" (subs resp 5)))))))))
(re-frame/reg-fx
:contacts/resolve-public-key-from-ens
(fn [{:keys [chain-id ens on-success on-error]}]
(ens/pubkey chain-id ens on-success on-error)))
:contacts/resolve-public-key-from-ens-name
(fn [{:keys [chain-id ens-name on-success on-error]}]
(ens/pubkey chain-id ens-name on-success on-error)))
(defn fx-callbacks
[input ens-name]
{:on-success (fn [pubkey]
(rf/dispatch [:contacts/set-new-identity-success input ens-name pubkey]))
:on-error (fn [err]
(rf/dispatch [:contacts/set-new-identity-error err input]))})
(defn identify-type
[input]
(let [regex #"^https?://join.status.im/u/(.+)"
id (as-> (utils/safe-trim input) $
(if-some [[_ match] (re-matches regex $)]
match
$)
(if (empty? $) nil $))
public-key? (validators/valid-public-key? id)
compressed-key? (validators/valid-compressed-key? id)
type (cond (empty? id) :empty
public-key? :public-key
compressed-key? :compressed-key
:else :ens-name)
ens-name (when (= type :ens-name)
(stateofus/ens-name-parse id))]
{:input input
:id id
:type type
:ens-name ens-name}))
(rf/defn set-new-identity
{:events [:contacts/set-new-identity]}
[{:keys [db]} input]
(let [{:keys [input id type ens-name]} (identify-type input)]
(case type
:empty {:db (dissoc db :contacts/new-identity)}
:public-key {:db (assoc db
:contacts/new-identity
{:input input
:public-key id
:state :error
:error :uncompressed-key})}
:compressed-key {:db
(assoc db
:contacts/new-identity
{:input input
:state :searching})
:contacts/decompress-public-key
(merge {:public-key id}
(fx-callbacks id ens-name))}
:ens-name {:db
(assoc db
:contacts/new-identity
{:input input
:state :searching})
:contacts/resolve-public-key-from-ens-name
(merge {:chain-id (ethereum/chain-id db)
:ens-name ens-name}
(fx-callbacks id ens-name))})))
(rf/defn build-contact
{:events [:contacts/build-contact]}
[_ pubkey ens open-profile-modal?]
[_ pubkey ens-name open-profile-modal?]
{:json-rpc/call [{:method "wakuext_buildContact"
:params [{:publicKey pubkey
:ENSName ens}]
:ENSName ens-name}]
:js-response true
:on-success #(rf/dispatch [:contacts/contact-built
pubkey
@@ -158,25 +106,24 @@
(rf/defn set-new-identity-success
{:events [:contacts/set-new-identity-success]}
[{:keys [db]} input pubkey]
(let [contact (get-in db [:contacts/new-identity])]
(when (= (:input contact) input)
(rf/merge {:db (assoc db
:contacts/new-identity
(->state (assoc contact :public-key pubkey)))}
(build-contact pubkey (:ens contact) false)))))
[{:keys [db] :as cofx} input ens-name pubkey]
(rf/merge cofx
{:db (assoc db
:contacts/new-identity
{:input input
:public-key pubkey
:ens-name ens-name
:state :valid})}
(build-contact pubkey ens-name false)))
(rf/defn set-new-identity-error
{:events [:contacts/set-new-identity-error]}
[{:keys [db]} input err]
(let [contact (get-in db [:contacts/new-identity])]
(when (= (:input contact) input)
(let [state (cond
(or (string/includes? (:message err) "fallback failed")
(string/includes? (:message err) "no such host"))
{:state :invalid :msg :t/lost-connection}
:else {:state :invalid})]
{:db (assoc db :contacts/new-identity (merge contact state))}))))
[{:keys [db]} error input]
{:db (assoc db
:contacts/new-identity
{:input input
:state :error
:error :invalid})})
(rf/defn clear-new-identity
{:events [:contacts/clear-new-identity :contacts/new-chat-focus]}
@@ -185,13 +132,7 @@
(rf/defn qr-code-scanned
{:events [:contacts/qr-code-scanned]}
[{:keys [db] :as cofx} scanned]
[{:keys [db] :as cofx} input]
(rf/merge cofx
(set-new-identity scanned scanned)
(set-new-identity input)
(navigation/navigate-back)))
(rf/defn set-new-identity-reconnected
[{:keys [db]}]
(let [input (get-in db [:contacts/new-identity :input])
resubmit? (and input (= :new-contact (get-in db [:view-id])))]
(rf/dispatch [:contacts/set-new-identity input])))
@@ -1,10 +1,7 @@
(ns status-im2.contexts.add-new-contact.events-test
(:require [cljs.test :refer-macros [deftest are]]
[status-im2.contexts.add-new-contact.events :as events]))
(:require [cljs.test :refer-macros [deftest is are]]
[status-im2.contexts.add-new-contact.events :as core]))
(def user-ukey
"0x04ca27ed9c7c4099d230c6d8853ad0cfaf084a019c543e9e433d3c04fac6de9147cf572b10e247cfe52f396b5aa10456b56dd1cf1d8a681e2b93993d44594b2e85")
(def user-ckey "zQ3shtFEo4PxpQiYGcNZZ8xhJmhD6WBXwnHPBueu5SRnvPXjk")
(def ukey
"0x045596a7ff87da36860a84b0908191ce60a504afc94aac93c1abd774f182967ce694f1bf2d8773cd59f4dd0863e951f9b7f7351c5516291a0fceb73f8c392a0e88")
(def ckey "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA")
@@ -13,118 +10,47 @@
(def link-ckey (str "https://join.status.im/u/" ckey))
(def link-ens (str "https://join.status.im/u/" ens))
;;; unit tests (no app-db involved)
(deftest identify-type-test
(are [input expected] (= (core/identify-type input) expected)
"" {:input ""
:id nil
:type :empty
:ens-name nil}
(deftest validate-contact-test
(are [i e] (= (events/validate-contact (events/init-contact
{:user-public-key user-ukey
:input i}))
(events/init-contact e))
ukey {:input ukey
:id ukey
:type :public-key
:ens-name nil}
"" {:user-public-key user-ukey
:input ""
:type :empty
:state :empty}
ens {:input ens
:id ens
:type :ens-name
:ens-name ens-stateofus-eth}
" " {:user-public-key user-ukey
:input " "
:type :empty
:state :empty}
ckey {:input ckey
:id ckey
:type :compressed-key
:ens-name nil}
ukey {:user-public-key user-ukey
:input ukey
:id ukey
:type :public-key
:public-key ukey
:state :invalid
:msg :t/not-a-chatkey}
link-ckey {:input link-ckey
:id ckey
:type :compressed-key
:ens-name nil}
ens {:user-public-key user-ukey
:input ens
:id ens
:type :ens
:ens ens-stateofus-eth
:state :resolve-ens}
link-ens {:input link-ens
:id ens
:type :ens-name
:ens-name ens-stateofus-eth}))
(str " " ens) {:user-public-key user-ukey
:input (str " " ens)
:id ens
:type :ens
:ens ens-stateofus-eth
:state :resolve-ens}
(deftest search-empty-string-test
(is (= (core/set-new-identity {:db {:contacts/new-identity :foo}} "")
{:db {}})))
ckey {:user-public-key user-ukey
:input ckey
:id ckey
:type :compressed-key
:state :decompress-key}
(deftest search-uncompressed-key-test
(is (= (core/set-new-identity {:db {}} ukey)
{:db {:contacts/new-identity
{:input ukey
:public-key ukey
:state :error
:error :uncompressed-key}}})))
link-ckey {:user-public-key user-ukey
:input link-ckey
:id ckey
:type :compressed-key
:state :decompress-key}
link-ens {:user-public-key user-ukey
:input link-ens
:id ens
:type :ens
:ens ens-stateofus-eth
:state :resolve-ens}))
;;; event handler tests (no callbacks)
(def db
{:multiaccount {:public-key user-ukey}
:networks/current-network "mainnet_rpc"
:networks/networks {"mainnet_rpc"
{:id "mainnet_rpc"
:config {:NetworkId 1}}}})
(deftest set-new-identity-test
(with-redefs [events/dispatcher (fn [& args] args)]
(are [i edb] (= (events/set-new-identity {:db db} i nil) edb)
"" {:db db}
ukey {:db (assoc db
:contacts/new-identity
(events/init-contact
{:user-public-key user-ukey
:input ukey
:id ukey
:type :public-key
:public-key ukey
:state :invalid
:msg :t/not-a-chatkey}))}
ens {:db (assoc db
:contacts/new-identity
(events/init-contact
{:user-public-key user-ukey
:input ens
:id ens
:type :ens
:ens ens-stateofus-eth
:public-key nil ; not yet...
:state :resolve-ens}))
:contacts/resolve-public-key-from-ens
{:chain-id 1
:ens ens-stateofus-eth
:on-success [:contacts/set-new-identity-success ens]
:on-error [:contacts/set-new-identity-error ens]}}
;; compressed-key & add-self-as-contact
user-ckey {:db (assoc db
:contacts/new-identity
(events/init-contact
{:user-public-key user-ukey
:input user-ckey
:id user-ckey
:type :compressed-key
:public-key nil ; not yet...
:state :decompress-key}))
:contacts/decompress-public-key
{:compressed-key user-ckey
:on-success [:contacts/set-new-identity-success user-ckey]
:on-error [:contacts/set-new-identity-error user-ckey]}})))
@@ -32,7 +32,7 @@
{:style {:flex-direction :row
:justify-content :space-between}})
(def container-invalid
(def container-error
{:style {:flex-direction :row
:align-items :center
:margin-top 8}})
@@ -64,18 +64,18 @@
colors/neutral-50
colors/neutral-40)}})
(def icon-invalid
(def icon-error
{:size 16
:color colors/danger-50})
(def text-invalid
(def text-error
{:size :paragraph-2
:align :left
:style {:margin-left 4
:color colors/danger-50}})
(defn text-input-container
[invalid?]
[error?]
{:style {:padding-top 1
:padding-left 12
:padding-right 7
@@ -88,7 +88,7 @@
colors/neutral-95)
:border-width 1
:border-radius 12
:border-color (if invalid?
:border-color (if error?
colors/danger-50-opa-40
(colors/theme-colors
colors/neutral-20
@@ -4,7 +4,6 @@
[quo2.core :as quo]
[react-native.core :as rn]
[react-native.clipboard :as clipboard]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.utils.utils :as utils]
@@ -45,78 +44,60 @@
(defn new-contact
[]
(let [clipboard (reagent/atom nil)
default-value (reagent/atom nil)]
(fn []
(clipboard/get-string #(reset! clipboard %))
(let [{:keys [input scanned public-key ens state msg]}
(rf/sub [:contacts/new-identity])
invalid? (= state :invalid)
show-paste-button? (and (not (string/blank? @clipboard))
(string/blank? @default-value)
(string/blank? input))]
[rn/keyboard-avoiding-view (style/container-kbd)
[rn/view style/container-image
[rn/image
{:source (resources/get-image :add-new-contact)
:style style/image}]
[quo/button
(merge (style/button-close)
{:on-press
(fn []
(reset! clipboard nil)
(reset! default-value nil)
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back]))}) :i/close]]
[rn/view (style/container-outer)
[rn/view style/container-inner
[quo/text (style/text-title)
(i18n/label :t/add-a-contact)]
[quo/text (style/text-subtitle)
(i18n/label :t/find-your-friends)]
[quo/text (style/text-description)
(i18n/label :t/ens-or-chat-key)]
[rn/view style/container-text-input
[rn/view (style/text-input-container invalid?)
[rn/text-input
(merge (style/text-input)
{:default-value (or scanned @default-value input)
:placeholder (i18n/label :t/type-some-chat-key)
:on-change-text (fn [v]
(reset! default-value v)
(debounce/debounce-and-dispatch
[:contacts/set-new-identity v nil]
600))})]
(when show-paste-button?
[quo/button
(merge style/button-paste
{:on-press
(fn []
(reset! default-value @clipboard)
(rf/dispatch
[:contacts/set-new-identity @clipboard nil]))})
(i18n/label :t/paste)])]
[quo/button
(merge style/button-qr
{:on-press #(rf/dispatch
[::qr-scanner/scan-code
{:handler :contacts/qr-code-scanned}])})
:i/scan]]
(when invalid?
[rn/view style/container-invalid
[quo/icon :i/alert style/icon-invalid]
[quo/text style/text-invalid
(i18n/label (or msg :t/invalid-ens-or-key))]])
(when (= state :valid)
[found-contact public-key])]
[rn/view
(let [{:keys [input public-key state error ens-name]} (rf/sub [:contacts/new-identity])
error? (and (= state :error)
(= error :uncompressed-key))]
[rn/keyboard-avoiding-view (style/container-kbd)
[rn/view style/container-image
[rn/image
{:source (resources/get-image :add-new-contact)
:style style/image}]
[quo/button
(merge (style/button-close)
{:on-press
(fn []
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back]))}) :i/close]]
[rn/view (style/container-outer)
[rn/view style/container-inner
[quo/text (style/text-title)
(i18n/label :t/add-a-contact)]
[quo/text (style/text-subtitle)
(i18n/label :t/find-your-friends)]
[quo/text (style/text-description)
(i18n/label :t/ens-or-chat-key)]
[rn/view style/container-text-input
[rn/view (style/text-input-container error?)
[rn/text-input
(merge (style/text-input)
{:default-value input
:placeholder (i18n/label :t/type-some-chat-key)
:on-change-text #(debounce/debounce-and-dispatch
[:contacts/set-new-identity %]
600)})]
(when (string/blank? input)
[quo/button
(merge (style/button-view-profile state)
{:on-press
(fn []
(reset! clipboard nil)
(reset! default-value nil)
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back])
(rf/dispatch [:chat.ui/show-profile public-key ens]))})
(i18n/label :t/view-profile)]]]]))))
(merge style/button-paste
{:on-press (fn []
(clipboard/get-string #(rf/dispatch [:contacts/set-new-identity %])))})
(i18n/label :t/paste)])]
[quo/button
(merge style/button-qr
{:on-press #(rf/dispatch [::qr-scanner/scan-code
{:handler :contacts/qr-code-scanned}])})
:i/scan]]
(when error?
[rn/view style/container-error
[quo/icon :i/alert style/icon-error]
[quo/text style/text-error (i18n/label :t/not-a-chatkey)]])
(when (= state :valid)
[found-contact public-key])]
[rn/view
[quo/button
(merge (style/button-view-profile state)
{:on-press
(fn []
(rf/dispatch [:contacts/clear-new-identity])
(rf/dispatch [:navigate-back])
(rf/dispatch [:chat.ui/show-profile public-key ens-name]))})
(i18n/label :t/view-profile)]]]]))
+4 -10
View File
@@ -13,8 +13,7 @@
[status-im2.contexts.contacts.events :as contacts-store]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.utils.clocks :as utils.clocks]
[status-im.utils.types :as types]
[reagent.core :as reagent]))
[status-im.utils.types :as types]))
(defn- get-chat
[cofx chat-id]
@@ -202,9 +201,9 @@
(rf/defn navigate-to-chat
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
{:events [:chat/navigate-to-chat]}
[{db :db :as cofx} chat-id]
[{db :db :as cofx} chat-id from-shell?]
(rf/merge cofx
{:dispatch [:navigate-to :chat chat-id]}
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
(when-not (or (= (:view-id db) :community) (= (:view-id db) :community-overview))
(navigation/pop-to-root :shell-stack))
(close-chat false)
@@ -339,12 +338,6 @@
[{:keys [db]} shared-element-id]
{:db (assoc db :shared-element-id shared-element-id)})
(rf/defn navigate-to-lightbox
{:events [:chat.ui/navigate-to-lightbox]}
[{:keys [db]} shared-element-id screen-params]
(reagent/next-tick #(rf/dispatch [:navigate-to :lightbox screen-params]))
{:db (assoc db :shared-element-id shared-element-id)})
(rf/defn exit-lightbox-signal
{:events [:chat.ui/exit-lightbox-signal]}
[{:keys [db]} value]
@@ -364,3 +357,4 @@
{:events [:chat.ui/lightbox-scale]}
[{:keys [db]} value]
{:db (assoc db :lightbox/scale value)})
@@ -88,7 +88,7 @@
(let [chat-id "test_chat"
db {:pagination-info {chat-id {:all-loaded? true}}}]
(testing "Pagination info should be reset on navigation"
(let [res (chat/navigate-to-chat {:db db} chat-id)]
(let [res (chat/navigate-to-chat {:db db} chat-id false)]
(is (nil? (get-in res [:db :pagination-info chat-id :all-loaded?])))))))
(deftest camera-roll-loading-more-test
@@ -41,13 +41,13 @@
:size 32} :i/reaction]])
(defn image-button
[insets]
[chat-id]
[quo/button
{:on-press (fn []
(permissions/request-permissions
{:permissions [:read-external-storage :write-external-storage]
:on-allowed #(rf/dispatch
[:open-modal :photo-selector {:insets insets}])
[:open-modal :photo-selector {:chat-id chat-id}])
:on-denied (fn []
(background-timer/set-timeout
#(utils-old/show-popup (i18n/label :t/error)
@@ -122,7 +122,7 @@
(when (and (not @input/recording-audio?)
(nil? (get @input/reviewing-audio-filepath chat-id)))
[:<>
[image-button insets]
[image-button chat-id]
[rn/view {:width 12}]
[reactions-button]
[rn/view {:flex 1}]
@@ -231,7 +231,7 @@
:sending-image (seq images)
:refs refs}]]]]
(if suggestions?
[mentions/mentions (select-keys params [:refs :suggestions :max-y]) insets]
[mentions/mentions params insets]
[controls/view send-ref record-ref params insets chat-id images
edit #(clean-and-minimize params)])
;;;;black background
@@ -52,11 +52,13 @@
{:key (:message-id item)
:active-opacity 1
:on-long-press #(on-long-press message context)
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
(:message-id item)
{:messages (:album message)
:index index
:insets insets}])}
:on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox
{:messages (:album message)
:index index
:insets insets}])
100))}
[fast-image/fast-image
{:style (style/image dimensions index portrait? images-count)
:source {:uri (:image (:content item))}
@@ -27,11 +27,13 @@
:key message-id
:style {:margin-top (when (pos? index) 10)}
:on-long-press on-long-press
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
message-id
{:messages [message]
:index 0
:insets insets}])}
:on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id message-id])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox
{:messages [message]
:index 0
:insets insets}])
100))}
(when (and (not= text "placeholder") (= index 0))
[rn/view {:style {:margin-bottom 10}} [text/text-content message context]])
[fast-image/fast-image
@@ -27,10 +27,6 @@
(concat
(when (and outgoing
(not (or deleted? deleted-for-me?))
;; temporarily disable edit image message until
;; https://github.com/status-im/status-mobile/issues/15298
;; is implemented
(not= content-type constants/content-type-image)
(not= content-type constants/content-type-audio))
[{:type :main
:on-press #(rf/dispatch [:chat.ui/edit-message message-data])
@@ -15,7 +15,8 @@
:flex-direction :row
:left 0
:right 0
:top 20
:margin-top 20
:margin-bottom 12
:justify-content :center
:z-index 1})
@@ -65,8 +66,8 @@
:height (/ window-width 3)
:margin-left (when (not= (mod index 3) 0) 1)
:margin-bottom 1
:border-top-left-radius (when (= index 0) 20)
:border-top-right-radius (when (= index 2) 20)})
:border-top-left-radius (when (= index 0) 10)
:border-top-right-radius (when (= index 2) 10)})
(defn overlay
[window-width]
@@ -1,9 +1,9 @@
(ns status-im2.contexts.chat.photo-selector.view
(:require
[react-native.gesture :as gesture]
[react-native.platform :as platform]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[react-native.safe-area :as safe-area]
[quo2.components.notifications.info-count :as info-count]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
@@ -13,7 +13,6 @@
[status-im2.contexts.chat.photo-selector.style :as style]
[status-im.utils.core :as utils]
[quo.react]
[status-im2.common.bottom-sheet-screen.view :as bottom-sheet-screen]
[utils.re-frame :as rf]))
(defn on-press-confirm-selection
@@ -81,38 +80,31 @@
(inc (utils/first-index #(= (:uri item) (:uri %)) @selected))])])
(defn album-title
[photos? selected-album]
(fn []
[rn/touchable-opacity
{:style (style/title-container)
:active-opacity 1
:accessibility-label :album-title
:on-press (fn []
;; TODO: album-selector issue:
;; https://github.com/status-im/status-mobile/issues/15398
(js/alert "currently disabled")
;(if photos?
; (do
; (reset! temporary-selected @selected)
; (rf/dispatch [:open-modal :album-selector {:insets insets}]))
; (rf/dispatch [:navigate-back]))
)}
[quo/text
{:weight :medium
:ellipsize-mode :tail
:number-of-lines 1
:style {:max-width 150}}
selected-album]
[rn/view {:style (style/chevron-container)}
[quo/icon (if photos? :i/chevron-down :i/chevron-up)
{:color (colors/theme-colors colors/neutral-100 colors/white)}]]]))
[photos? selected-album selected temporary-selected]
[rn/touchable-opacity
{:style (style/title-container)
:active-opacity 1
:accessibility-label :album-title
:on-press (fn []
(if photos?
(do
(reset! temporary-selected @selected)
(rf/dispatch [:open-modal :album-selector]))
(rf/dispatch [:navigate-back])))}
[quo/text
{:weight :medium
:ellipsize-mode :tail
:number-of-lines 1
:style {:max-width 150}}
selected-album]
[rn/view {:style (style/chevron-container)}
[quo/icon (if photos? :i/chevron-down :i/chevron-up)
{:color (colors/theme-colors colors/neutral-100 colors/white)}]]])
(defn photo-selector
[]
[:f>
(let [{:keys [insets]} (rf/sub [:get-screen-params])
temporary-selected (reagent/atom [])] ; used when switching albums
(let [temporary-selected (reagent/atom [])] ; used when switching albums
(fn []
(let [selected (reagent/atom []) ; currently selected
selected-images (rf/sub [:chats/sending-image]) ; already selected and dispatched
@@ -124,19 +116,26 @@
(reset! selected (vec (vals selected-images)))
(reset! selected @temporary-selected)))
[selected-album])
[bottom-sheet-screen/view
(fn [{:keys [scroll-enabled on-scroll]}]
[safe-area/consumer
(fn [insets]
(let [window-width (:width (rn/get-window))
camera-roll-photos (rf/sub [:camera-roll/photos])
end-cursor (rf/sub [:camera-roll/end-cursor])
loading? (rf/sub [:camera-roll/loading-more])
has-next-page? (rf/sub [:camera-roll/has-next-page])]
[:<>
[rn/view {:style {:flex 1}}
[rn/view
{:style style/buttons-container}
[album-title true selected-album selected temporary-selected insets]
(when platform/android?
[rn/touchable-opacity
{:active-opacity 1
:on-press #(rf/dispatch [:navigate-back])
:style (style/close-button-container)}
[quo/icon :i/close
{:size 20 :color (colors/theme-colors colors/black colors/white)}]])
[album-title true selected-album selected temporary-selected]
[clear-button selected]]
[gesture/flat-list
[rn/flat-list
{:key-fn identity
:render-fn image
:render-data {:window-width window-width :selected selected}
@@ -144,9 +143,7 @@
:num-columns 3
:content-container-style {:width "100%"
:padding-bottom (+ (:bottom insets) 100)
:padding-top 64}
:on-scroll on-scroll
:scroll-enabled scroll-enabled
:padding-top 80}
:on-end-reached #(rf/dispatch [:camera-roll/on-end-reached end-cursor
selected-album loading?
has-next-page?])}]
@@ -22,11 +22,10 @@
(def featured-list-container
{:flex-direction :row
:overflow :hidden})
(def flat-list-container
{:padding-bottom 24
:padding-horizontal 20})
:overflow :hidden
:margin-bottom 24
:margin-left 20
:padding-right 20})
(def other-communities-container
{:flex 1
@@ -7,6 +7,7 @@
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im.ui.screens.communities.community :as community]
[status-im.ui.components.react :as react]
[react-native.platform :as platform]
[status-im2.common.scroll-page.view :as scroll-page]
@@ -21,28 +22,23 @@
:group [{:id 1
:token-icon (resources/get-mock-image :status-logo)}]}]}})
(defn community-list-item
[{:keys [id] :as community} _ _ {:keys [width view-type]}]
(let [community-item (merge
community
(get mock-community-item-data :data))
cover {:uri (get-in (:images community) [:banner :uri])}]
(defn render-fn
[community-item _ _ {:keys [width view-type]}]
(let [item (merge community-item
(get mock-community-item-data :data))
cover {:uri (get-in (:images item) [:banner :uri])}]
(if (= view-type :card-view)
[quo/community-card-view-item (assoc community-item :width width :cover cover)
#(rf/dispatch [:navigate-to :community-overview (:id community)])]
[quo/community-card-view-item (assoc item :width width :cover cover)
#(rf/dispatch [:navigate-to :community-overview (:id item)])]
[quo/communities-list-view-item
{:on-press (fn []
(rf/dispatch [:communities/load-category-states id])
(rf/dispatch [:communities/load-category-states (:id item)])
(rf/dispatch [:dismiss-keyboard])
<<<<<<< HEAD
(rf/dispatch [:navigate-to :community-overview (:id item)]))
=======
(rf/dispatch [:navigate-to :community {:community-id id}]))
>>>>>>> 1675fef63 (Fix: community data not displayed)
(rf/dispatch [:navigate-to :community {:community-id (:id item)}]))
:on-long-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn []
[options/community-options-bottom-sheet id])}])}])))
[options/community-options-bottom-sheet (:id item)])}])}])))
(defn screen-title
[]
@@ -93,6 +89,7 @@
:label (i18n/label :t/gated)
:accessibility-label :gated-communities-tab}]}]])
(defn featured-list
[communities view-type]
(let [view-size (reagent/atom 0)]
@@ -101,7 +98,7 @@
{:style style/featured-list-container
:on-layout #(swap! view-size
(fn []
(- (oops/oget % "nativeEvent.layout.width") 40)))}
(- (oops/oget % "nativeEvent.layout.width") 20)))}
(when-not (= @view-size 0)
[rn/flat-list
{:key-fn :id
@@ -110,22 +107,9 @@
:shows-horizontal-scroll-indicator false
:separator [rn/view {:width 12}]
:data communities
:render-fn community-list-item
:render-fn render-fn
:render-data {:width @view-size
:view-type view-type}
:contentContainerStyle style/flat-list-container}])])))
(defn other-communities-list
[{:keys [communities view-type]}]
[rn/view style/other-communities-container
[rn/flat-list
{:key-fn :id
:keyboard-should-persist-taps :always
:separator [rn/view {:height 16}]
:data communities
:render-fn community-list-item
:contentContainerStyle style/flat-list-container
:render-data {:view-type view-type}}]])
:view-type view-type}}])])))
(defn discover-communities-header
[{:keys [featured-communities-count
@@ -136,10 +120,39 @@
[screen-title]
[featured-communities-header featured-communities-count]
[featured-list featured-communities view-type]
[rn/view {:style {:margin-horizontal 20}}
[quo/separator]]
[quo/separator]
[discover-communities-segments selected-tab false]])
(defn other-communities-list
[{:keys [communities communities-ids view-type]}]
[rn/view {:style style/other-communities-container}
(map-indexed
(fn [inner-index item]
(let [community-id (when communities-ids item)
community (if communities
item
[rf/sub [:communities/home-item community-id]])]
[rn/view
{:key (str inner-index (:id community))
:margin-bottom 16}
(if (= view-type :card-view)
[quo/community-card-view-item
(merge community
(get mock-community-item-data :data))
#(rf/dispatch [:navigate-to :community-overview (:id community)])]
[quo/communities-list-view-item
{:on-press (fn []
(rf/dispatch [:communities/load-category-states (:id community)])
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community (:id community)]))
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn []
;; TODO implement with quo2
[community/community-actions community])}])}
(merge community
(get mock-community-item-data :data))])]))
(if communities communities communities-ids))])
(defn communities-lists
[selected-tab view-type]
[rn/view {:style {:flex 1}}
@@ -18,7 +18,7 @@
item (merge item unviewed-counts)]
[quo/communities-membership-list-item
{:style {:padding-horizontal 18}
:on-press #(rf/dispatch [:navigate-to :community-overview id])
:on-press #(rf/dispatch [:navigate-to-nav2 :community-overview id])
:on-long-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn []
@@ -295,14 +295,14 @@
(defn page-nav-right-section-buttons
[id]
[{:icon :i/options
:background-color (scroll-page/icon-color)
:accessibility-label :community-options-for-community
:on-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn []
[options/community-options-bottom-sheet
id])}])}])
[{:icon :i/options
:background-color (scroll-page/icon-color)
:on-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content
(fn []
[options/community-options-bottom-sheet
id])}])}])
(defn pick-first-category-by-height
[scroll-height first-channel-height categories-heights]
@@ -3,12 +3,7 @@
(def background-container
{:background-color colors/neutral-95
:flex-direction :row
:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
:flex-direction :row})
(defn background-gradient-overlay
[dark-overlay?]
@@ -11,8 +11,7 @@
{:style style/background-container}
[rn/image
{:blur-radius (if dark-overlay? 13 0)
:style {:height "100%"
:width "100%"}
:style {:flex 1}
;; Todo - get background image from sub using carousel index on landing page
:source (resources/get-image :onboarding-bg-1)}]
[linear-gradient/linear-gradient
@@ -23,4 +22,4 @@
:style (style/background-gradient-overlay dark-overlay?)}]
(when dark-overlay?
[rn/view
{:style style/background-blur-overlay}])])
{:style style/background-blur-overlay}])])
@@ -61,7 +61,7 @@
:source (get-in carousels [@carousel-index :image])}]
[quo/drawer-buttons
{:top-card {:on-press (fn []
(rf/dispatch [:navigate-to :sign-in])
(rf/dispatch [:navigate-to :new-to-status])
(rf/dispatch [:hide-terms-of-services-opt-in-screen]))
:heading (i18n/label :t/sign-in)
:accessibility-label :already-use-status-button}
@@ -1,19 +0,0 @@
(ns status-im2.contexts.onboarding.common.navigation-bar.view
(:require [quo2.core :as quo]
[react-native.core :as rn]
[utils.re-frame :as rf]))
(defn navigation-bar
[{:keys [on-press-info]}]
[rn/view {:style {:height 56}}
[quo/page-nav
{:align-mid? true
:mid-section {:type :text-only}
:left-section {:type :blur-bg
:icon :i/arrow-left
:icon-override-theme :dark
:on-press #(rf/dispatch [:navigate-back])}
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press on-press-info}]}]])
@@ -1,69 +1,14 @@
(ns status-im2.contexts.onboarding.create-password.style
(:require [quo2.foundations.colors :as colors]))
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]))
(def image-background
{:height "100%"
:width "100%"})
(def navigation-bar {:height 56})
(def overlay
{:position :absolute
(def page-container
{:padding-top (if platform/ios? 44 0)
:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:background-color colors/neutral-80-opa-80-blur})
(def content-style {:flex-grow 1})
(def heading {:margin-bottom 20})
(def heading-subtitle {:color colors/white})
(def heading-title (assoc heading-subtitle :margin-bottom 8))
(def label-container
{:margin-top 8
:flex-direction :row
:align-items :center
:height 16})
(def label-icon
{:width 16
:height 18
:margin-right 4})
(defn label-icon-color
[status]
(get {:neutral colors/neutral-40
:success colors/success-60
:danger colors/danger-60}
status))
(defn label-color
[status]
(let [colors {:neutral colors/white-opa-70
:success colors/success-60
:danger colors/danger-60}]
{:color (get colors status)}))
(def space-between-inputs {:height 16})
(def password-tips
{:flex-direction :row
:justify-content :space-between
:margin-horizontal 20})
(def top-part
{:margin-horizontal 20
:margin-top 12})
(def bottom-part
{:flex 1
:margin-top 12
:justify-content :flex-end})
(def disclaimer-container
{:margin-horizontal 20
:margin-vertical 4})
(def button-container
{:margin-horizontal 20
:margin-vertical 12})
@@ -1,198 +1,42 @@
(ns status-im2.contexts.onboarding.create-password.view
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.common.navigation-bar.view :as navigation-bar]
[status-im2.contexts.onboarding.create-password.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]
[utils.string :as utils.string]))
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im2.contexts.onboarding.create-password.style :as style]
[utils.i18n :as i18n]
[status-im2.contexts.onboarding.common.background.view :as background]
[utils.re-frame :as rf]))
(defn header
(defn navigation-bar
[]
[rn/view {:style style/heading}
[quo/text
{:style style/heading-title
:weight :semi-bold
:size :heading-1}
(i18n/label :t/password-creation-title)]
[quo/text
{:style style/heading-subtitle
:weight :regular
:size :paragraph-1}
(i18n/label :t/password-creation-subtitle)]])
[rn/view {:style style/navigation-bar}
[quo/page-nav
{:align-mid? true
:mid-section {:type :text-only :main-text ""}
:left-section {:type :blur-bg
:icon :i/arrow-left
:icon-override-theme :dark
:on-press #(rf/dispatch [:navigate-back])}
:right-section-buttons [{:type :blur-bg
:icon :i/info
:icon-override-theme :dark
:on-press #(js/alert "Pending")}]}]])
(defn password-with-hint
[{{:keys [text status shown]} :hint :as input-props}]
[rn/view
[quo/input
(-> input-props
(dissoc :hint)
(assoc :type :password
:blur? true))]
[rn/view {:style style/label-container}
(when shown
[:<>
[quo/icon (if (= status :success) :i/check-circle :i/info)
{:container-style style/label-icon
:color (style/label-icon-color status)
:size 16}]
[quo/text
{:style (style/label-color status)
:size :paragraph-2}
text]])]])
(defn password-inputs
[{:keys [passwords-match? on-change-password on-change-repeat-password on-input-focus
password-long-enough? empty-password? show-password-validation?
on-blur-repeat-password]}]
(let [hint-1-status (if password-long-enough? :success :neutral)
hint-2-status (if passwords-match? :success :danger)
hint-2-text (if passwords-match?
(i18n/label :t/password-creation-match)
(i18n/label :t/password-creation-dont-match))
error? (and show-password-validation?
(not passwords-match?)
(not empty-password?))]
[:<>
[password-with-hint
{:hint {:text (i18n/label :t/password-creation-hint)
:status hint-1-status
:shown true}
:placeholder (i18n/label :t/password-creation-placeholder-1)
:on-change-text on-change-password
:on-focus #(on-input-focus :password)}]
[rn/view {:style style/space-between-inputs}]
[password-with-hint
{:hint {:text hint-2-text
:status hint-2-status
:shown (and (not empty-password?)
show-password-validation?)}
:error? error?
:placeholder (i18n/label :t/password-creation-placeholder-2)
:on-change-text on-change-repeat-password
:on-focus #(on-input-focus :repeat-password)
:on-blur on-blur-repeat-password}]]))
(def strength-status
{1 :very-weak
2 :weak
3 :okay
4 :strong
5 :very-strong})
(defn help
[{{:keys [lower-case? upper-case? numbers? symbols?]} :validations
password-strength :password-strength}]
[rn/view
[quo/strength-divider {:type (strength-status password-strength :info)}
(i18n/label :t/password-creation-tips-title)]
[rn/view {:style style/password-tips}
[quo/tips {:completed? lower-case?}
(i18n/label :t/password-creation-tips-1)]
[quo/tips {:completed? upper-case?}
(i18n/label :t/password-creation-tips-2)]
[quo/tips {:completed? numbers?}
(i18n/label :t/password-creation-tips-3)]
[quo/tips {:completed? symbols?}
(i18n/label :t/password-creation-tips-4)]]])
(defn password-validations
[password]
(let [validations (juxt utils.string/has-lower-case?
utils.string/has-upper-case?
utils.string/has-numbers?
utils.string/has-symbols?
#(utils.string/at-least-n-chars? % 10))]
(->> password
(validations)
(zipmap [:lower-case? :upper-case? :numbers? :symbols? :long-enough?]))))
(defn calc-password-strength
[validations]
(->> (vals validations)
(filter true?)
(count)))
(defn password-form
[{:keys [scroll-to-end-fn]}]
(let [password (reagent/atom "")
repeat-password (reagent/atom "")
accepts-disclaimer? (reagent/atom false)
focused-input (reagent/atom nil)
show-password-validation? (reagent/atom false)
same-password-length? #(and (seq @password)
(= (count @password) (count @repeat-password)))]
(fn []
(let [{user-color :color} (rf/sub [:onboarding-2/profile])
{:keys [long-enough?]
:as validations} (password-validations @password)
password-strength (calc-password-strength validations)
empty-password? (empty? @password)
same-passwords? (= @password @repeat-password)
meet-requirements? (and (not empty-password?)
(utils.string/at-least-n-chars? @password 10)
same-passwords?
@accepts-disclaimer?)]
[:<>
[rn/view {:style style/top-part}
[header]
[password-inputs
{:password-long-enough? long-enough?
:passwords-match? same-passwords?
:empty-password? empty-password?
:show-password-validation? @show-password-validation?
:on-input-focus (fn [input-id]
(scroll-to-end-fn)
(reset! focused-input input-id))
:on-change-password (fn [new-value]
(reset! password new-value)
(when (same-password-length?)
(reset! show-password-validation? true)))
:on-change-repeat-password (fn [new-value]
(reset! repeat-password new-value)
(when (same-password-length?)
(reset! show-password-validation? true)))
:on-blur-repeat-password #(if empty-password?
(reset! show-password-validation? false)
(reset! show-password-validation? true))}]]
[rn/view {:style style/bottom-part}
(when (= @focused-input :password)
[help
{:validations validations
:password-strength password-strength}])
(when (= @focused-input :repeat-password)
[rn/view {:style style/disclaimer-container}
[quo/disclaimer
{:on-change #(reset! accepts-disclaimer? %)
:checked? @accepts-disclaimer?}
(i18n/label :t/password-creation-disclaimer)]])
[rn/view {:style style/button-container}
[quo/button
{:disabled (not meet-requirements?)
:override-background-color (colors/custom-color user-color 60)
:on-press #(rf/dispatch
[:onboarding-2/password-set
(security/mask-data @password)])}
(i18n/label :t/password-creation-confirm)]]]]))))
(defn page
[]
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view {:style {:padding-horizontal 20}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}} "Create profile password"]
[quo/button
{:on-press #(rf/dispatch [:navigate-to :enable-biometrics])
:style {}} (i18n/label :t/continue)]]])
(defn create-password
[]
(let [scroll-view-ref (atom nil)
scroll-to-end-fn #(js/setTimeout ^js/Function (.-scrollToEnd @scroll-view-ref) 250)]
(fn []
[:<>
[background/view true]
[rn/scroll-view
{:ref #(reset! scroll-view-ref %)
:style style/overlay
:content-container-style style/content-style}
[navigation-bar/navigation-bar {:on-press-info #(js/alert "Info pressed")}]
[password-form {:scroll-to-end-fn scroll-to-end-fn}]]])))
[rn/view {:style {:flex 1}}
[background/view true]
[page]])
@@ -2,14 +2,6 @@
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]))
(def continue-button
{:width "100%"
:margin-top :auto
:margin-bottom 72
:margin-left :auto
:margin-right :auto
:align-self :flex-end})
(def page-container
{:padding-top (if platform/ios? 44 0)
:position :absolute
@@ -21,5 +13,3 @@
(def navigation-bar {:height 56})
(def info-message
{:margin-top 8})
@@ -1,15 +1,11 @@
(ns status-im2.contexts.onboarding.create-profile.view
(:require [quo2.core :as quo]
[clojure.string :as string]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im2.contexts.onboarding.create-profile.style :as style]
[utils.i18n :as i18n]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.select-photo.method-menu.view :as method-menu]
[utils.re-frame :as rf]
[status-im2.constants :as c]))
[utils.re-frame :as rf]))
(defn navigation-bar
[]
@@ -22,104 +18,21 @@
:icon-override-theme :dark
:on-press #(rf/dispatch [:navigate-back])}}]])
(def emoji-regex
(new
js/RegExp
#"(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])"
"i"))
(defn has-emojis [s] (re-find emoji-regex s))
(def common-names ["Ethereum" "Bitcoin"])
(defn has-common-names [s] (pos? (count (filter #(string/includes? s %) common-names))))
(def special-characters-regex (new js/RegExp #"[^a-zA-Z\d\s-]" "i"))
(defn has-special-characters [s] (re-find special-characters-regex s))
(defn validation-message
[s]
(cond
(or (= s nil) (= s "")) nil
(has-emojis s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/emojis)})
(has-special-characters s) (i18n/label :t/are-not-allowed
{:check (i18n/label :t/special-characters)})
(string/ends-with? s "-eth") (i18n/label :t/ending-not-allowed {:ending "-eth"})
(has-common-names s) (i18n/label :t/are-not-allowed {:check (i18n/label :t/common-names)})
:else nil))
(defn page
[{:keys [image-path display-name color]}]
(let [full-name (reagent/atom display-name)
validation-msg (reagent/atom (validation-message @full-name))
on-change-text (fn [s]
(reset! validation-msg (validation-message s))
(reset! full-name s))
custom-color (reagent/atom (or color c/profile-default-color))
profile-pic (reagent/atom image-path)
on-change-profile-pic #(reset! profile-pic %)
on-change #(reset! custom-color %)]
(fn []
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view
{:style {:flex 1
:padding-horizontal 20}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white
:margin-top 12
:margin-bottom 20}} (i18n/label :t/create-profile)]
[rn/view
{:flex 1
:align-items :flex-start}
[rn/view
{:flex-direction :row
:justify-content :center}
[quo/profile-input
{:customization-color @custom-color
:placeholder (i18n/label :t/your-name)
:on-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:override-theme :dark
:content
(fn []
[method-menu/view on-change-profile-pic])}])
:image-picker-props {:profile-picture @profile-pic
:full-name @full-name}
:title-input-props {:max-length c/profile-name-max-length
:on-change-text on-change-text}}]]
(when @validation-msg
[quo/info-message
{:type :error
:size :default
:icon :i/info
:style style/info-message}
@validation-msg])
[quo/text
{:size :paragraph-2
:style {:color colors/white-70-blur
:margin-top 20
:margin-bottom 16}} (i18n/label :t/accent-colour)]
[quo/color-picker
{:blur? true
:default-selected? :blue
:selected @custom-color
:on-change on-change}]]
[quo/button
{:accessibility-label :submit-create-profile-button
:type :primary
:override-background-color (colors/custom-color @custom-color 60)
:on-press #(rf/dispatch [:onboarding-2/profile-data-set
{:image-path @profile-pic
:display-name @full-name
:color @custom-color}])
:style style/continue-button
:disabled (and (not (seq @full-name)) (not @validation-msg))}
(i18n/label :t/continue)]]])))
[]
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view {:style {:padding-horizontal 20}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}} "Create Profile"]
[quo/button
{:on-press #(rf/dispatch [:navigate-to :create-profile-password])
:style {}} (i18n/label :t/continue)]]])
(defn create-profile
[]
[rn/view {:style {:flex 1}}
(let [onboarding-profile-data (rf/sub [:onboarding-2/profile])]
[background/view true]
[page onboarding-profile-data])])
[background/view true]
[page]])
@@ -12,12 +12,3 @@
:background-color colors/neutral-80-opa-80-blur})
(def navigation-bar {:height 56})
(def image-container
{:margin-top 20
:margin-bottom 24
:background-color colors/danger-50
:border-radius 20
:flex 1
:align-items :center
:justify-content :center})
@@ -5,8 +5,7 @@
[status-im2.contexts.onboarding.enable-biometrics.style :as style]
[utils.i18n :as i18n]
[status-im2.contexts.onboarding.common.background.view :as background]
[utils.re-frame :as rf]
[status-im.multiaccounts.biometric.core :as biometric]))
[utils.re-frame :as rf]))
(defn navigation-bar
[]
@@ -18,39 +17,18 @@
(defn page
[]
(let [supported-biometric (rf/sub [:supported-biometric-auth])
bio-type-label (biometric/get-label supported-biometric)
profile-color (:color (rf/sub [:onboarding-2/profile]))]
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view
{:style {:padding-horizontal 20
:flex 1}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}} (i18n/label :t/enable-biometrics)]
[quo/text
{:size :paragraph-1
:style {:color colors/white
:margin-top 8}}
(i18n/label :t/use-biometrics)]
;; TODO(@briansztamfater): Replace view with image view with the real illustration,
;; https://github.com/status-im/status-mobile/issues/15445
[rn/view {:style style/image-container}
[quo/text {:size :paragraph-1}
"Illustration here"]]
[rn/view {:style {:margin-bottom 55}}
[quo/button
{:on-press #(rf/dispatch [:onboarding-2/enable-biometrics])
:before :i/face-id
:override-background-color (colors/custom-color profile-color 50)}
(i18n/label :t/biometric-enable-button {:bio-type-label bio-type-label})]
[quo/button
{:on-press #(rf/dispatch [:onboarding-2/create-account-and-login])
:override-background-color colors/white-opa-5
:style {:margin-top 12}}
(i18n/label :t/maybe-later)]]]]))
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view {:style {:padding-horizontal 20}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}} "Enable-biometrics"]
[quo/button
{:on-press #(rf/dispatch [:navigate-to :enable-notifications])
:type :grey
:override-theme :dark
:style {}} (i18n/label :t/continue)]]])
(defn enable-biometrics
[]
@@ -1,26 +1,14 @@
(ns status-im2.contexts.onboarding.enable-notifications.style
(:require
[react-native.platform :as platform]
[quo2.foundations.colors :as colors]))
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]))
(def title-container
{:justify-content :center
:margin-top 12
:padding-horizontal 20})
(def enable-notifications-buttons
{:margin 20})
(def enable-notifications
{:flex 1
:padding-top (if platform/ios? 44 0)
(def page-container
{:padding-top (if platform/ios? 44 0)
:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:background-color colors/neutral-80-opa-80-blur})
(def page-illustration
{:flex 1
:background-color colors/danger-50
:align-items :center
:margin-horizontal 20
:border-radius 20
:margin-top 20
:justify-content :center})
(def navigation-bar {:height 56})
@@ -1,71 +1,37 @@
(ns status-im2.contexts.onboarding.enable-notifications.view
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[react-native.core :as rn]
[react-native.platform :as platform]
[status-im.notifications.core :as notifications]
[status-im2.contexts.onboarding.common.background.view :as background]
[status-im2.contexts.onboarding.enable-notifications.style :as style]))
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im2.contexts.onboarding.enable-notifications.style :as style]
[utils.i18n :as i18n]
[status-im2.contexts.onboarding.common.background.view :as background]
[utils.re-frame :as rf]))
(defn navigation-bar
[]
[quo/page-nav
(merge {:horizontal-description? false
:one-icon-align-left? true
:align-mid? false
:page-nav-color :transparent
:left-section {:icon :i/arrow-left
:icon-background-color colors/white-opa-5
:icon-override-theme :dark
:type :shell
:on-press #()}})])
[rn/view {:style style/navigation-bar}
[quo/page-nav
{:align-mid? true
:mid-section {:type :text-only :main-text ""}
}]])
(defn page-title
(defn page
[]
[rn/view {:style style/title-container}
[quo/text
{:accessibility-label :notifications-screen-title
:weight :semi-bold
:size :heading-1
:style {:color colors/white}}
(i18n/label :t/intro-wizard-title6)]
[quo/text
{:accessibility-label :notifications-screen-sub-title
:weight :regular
:size :paragraph-1
:style {:color colors/white}}
(i18n/label :t/enable-notifications-sub-title)]])
(defn enable-notification-buttons
[]
[rn/view {:style style/enable-notifications-buttons}
[quo/button
{:on-press (fn []
(rf/dispatch [::notifications/switch true platform/ios?])
(rf/dispatch [:init-root :welcome]))
:type :primary
:before :i/notifications
:accessibility-label :enable-notifications-button
:override-background-color (colors/custom-color :magenta 60)}
(i18n/label :t/intro-wizard-title6)]
[quo/button
{:on-press #(rf/dispatch [:init-root :welcome])
:accessibility-label :enable-notifications-later-button
:override-background-color colors/white-opa-5
:style {:margin-top 12}}
(i18n/label :t/maybe-later)]])
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view {:style {:padding-horizontal 20}}
[quo/text
{:size :heading-1
:weight :semi-bold
:style {:color colors/white}} "Enable-notifications"]
[quo/button
{:on-press #(rf/dispatch [:navigate-to :shell-stack])
:type :grey
:override-theme :dark
:style {}} (i18n/label :t/continue)]]])
(defn enable-notifications
[]
[rn/view {:style style/enable-notifications}
[rn/view {:style {:flex 1}}
[background/view true]
[navigation-bar]
[page-title]
[rn/view {:style style/page-illustration}
[quo/text
"[Illustration here]"]]
[enable-notification-buttons]])
[page]])
@@ -1,14 +0,0 @@
(ns status-im2.contexts.onboarding.enter-seed-phrase.style
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]))
(def page-container
{:padding-top (if platform/ios? 44 0)
:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:background-color colors/neutral-80-opa-80-blur})
(def navigation-bar {:height 56})
@@ -1,79 +0,0 @@
(ns status-im2.contexts.onboarding.enter-seed-phrase.view
(:require [quo2.core :as quo]
[quo.core :as quo1]
[clojure.string :as string]
[status-im.ethereum.mnemonic :as mnemonic]
[status-im2.constants :as constants]
[utils.security.core :as security]
[utils.re-frame :as rf]
[reagent.core :as reagent]
[react-native.core :as rn]
[status-im2.contexts.onboarding.enter-seed-phrase.style :as style]
[status-im2.contexts.onboarding.common.background.view :as background]
[utils.i18n :as i18n]))
(defn navigation-bar
[]
[rn/view {:style style/navigation-bar}
[quo/page-nav
{:align-mid? true
:left-section {:type :blur-bg
:icon :i/arrow-left
:icon-override-theme :dark
:on-press #(rf/dispatch [:navigate-back])}
:mid-section {:type :text-only :main-text ""}}]])
(def button-disabled?
(comp not constants/seed-phrase-valid-length mnemonic/words-count))
(defn clean-seed-phrase
[s]
(as-> s $
(string/lower-case $)
(string/split $ #"\s")
(filter #(not (string/blank? %)) $)
(string/join " " $)))
(defn page
[]
(let [seed-phrase (reagent/atom "")
error-message (reagent/atom "")
on-invalid-seed-phrase #(reset! error-message (i18n/label :t/custom-seed-phrase))]
(fn []
[rn/view {:style style/page-container}
[navigation-bar]
[rn/view {:style {:padding-horizontal 20}}
[quo/text
{:weight :bold
:align :center}
(i18n/label :t/use-recovery-phrase)]
[quo/text
(i18n/label-pluralize (mnemonic/words-count @seed-phrase) :t/words-n)]
[:<>
[quo1/text-input
{:on-change-text (fn [t]
(reset! seed-phrase (clean-seed-phrase t))
(reset! error-message ""))
:auto-focus true
:accessibility-label :passphrase-input
:placeholder (i18n/label :t/seed-phrase-placeholder)
:show-cancel false
:bottom-value 40
:multiline true
:auto-correct false
:keyboard-type :visible-password
:monospace true}]]
[quo/button
{:disabled (button-disabled? @seed-phrase)
:on-press #(rf/dispatch [:onboarding-2/seed-phrase-entered
(security/mask-data @seed-phrase)
on-invalid-seed-phrase])}
(i18n/label :t/continue)]
(when (seq @error-message)
[quo/text @error-message])]])))
(defn enter-seed-phrase
[]
[rn/view {:style {:flex 1}}
[background/view true]
[page]])
@@ -1,139 +0,0 @@
(ns status-im2.contexts.onboarding.events
(:require
[utils.re-frame :as rf]
[re-frame.core :as re-frame]
[status-im.utils.types :as types]
[status-im2.config :as config]
[clojure.string :as string]
[utils.security.core :as security]
[status-im.native-module.core :as status]
[status-im.ethereum.core :as ethereum]
[status-im2.constants :as constants]
[utils.i18n :as i18n]))
(re-frame/reg-fx
:multiaccount/create-account-and-login
(fn [request]
(status/create-account-and-login request)))
(re-frame/reg-fx
:multiaccount/validate-mnemonic
(fn [[mnemonic on-success on-error]]
(status/validate-mnemonic
(security/safe-unmask-data mnemonic)
(fn [result]
(let [{:keys [error]} (types/json->clj result)]
(if (seq error)
(when on-error (on-error error))
(on-success mnemonic)))))))
(re-frame/reg-fx
:multiaccount/restore-account-and-login
(fn [request]
(status/restore-account-and-login request)))
(rf/defn profile-data-set
{:events [:onboarding-2/profile-data-set]}
[{:keys [db]} onboarding-data]
{:db (update db :onboarding-2/profile merge onboarding-data)
:dispatch [:navigate-to :create-profile-password]})
(rf/defn enable-biometrics
{:events [:onboarding-2/enable-biometrics]}
[_]
{:biometric-auth/authenticate [#(rf/dispatch [:onboarding-2/biometrics-done %]) {}]})
(rf/defn show-biometrics-message
[cofx bioauth-message bioauth-code]
(let [content (or (when (get #{"NOT_AVAILABLE" "NOT_ENROLLED"} bioauth-code)
(i18n/label :t/grant-face-id-permissions))
bioauth-message)]
(when content
{:utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title)
:content content}})))
(rf/defn biometrics-done
{:events [:onboarding-2/biometrics-done]}
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
(if bioauth-success
{:db (assoc-in db [:onboarding-2/profile :auth-method] constants/auth-method-biometric)
:dispatch [:onboarding-2/create-account-and-login]}
(show-biometrics-message cofx bioauth-message bioauth-code)))
(defn strip-file-prefix
[path]
(when path
(string/replace-first path "file://" "")))
(rf/defn create-account-and-login
{:events [:onboarding-2/create-account-and-login]}
[{:keys [db]}]
(let [{:keys [display-name
seed-phrase
password
image-path
color]} (:onboarding-2/profile db)
log-enabled? (boolean (not-empty config/log-level))
effect (if seed-phrase
:multiaccount/restore-account-and-login
:multiaccount/create-account-and-login)
request {:displayName display-name
:password (ethereum/sha3 (security/safe-unmask-data password))
:mnemonic (when seed-phrase
(security/safe-unmask-data seed-phrase))
:imagePath (strip-file-prefix image-path)
:customizationColor color
:backupDisabledDataDir (status/backup-disabled-data-dir)
:rootKeystoreDir (status/keystore-dir)
;; Temporary fix until https://github.com/status-im/status-go/issues/3024 is
;; resolved
:wakuV2Nameserver "1.1.1.1"
:logLevel (when log-enabled? config/log-level)
:logEnabled log-enabled?
:logFilePath (status/log-file-path)
:openseaAPIKey config/opensea-api-key
:verifyTransactionURL config/verify-transaction-url
:verifyENSURL config/verify-ens-url
:verifyENSContractAddress config/verify-ens-contract-address
:verifyTransactionChainID config/verify-transaction-chain-id
:previewPrivacy config/blank-preview?}]
{effect request
:dispatch [:navigate-to :generating-keys]
:db (-> db
(dissoc :onboarding-2/profile)
(assoc :onboarding-2/new-account? true))}))
(rf/defn on-delete-profile-success
{:events [:onboarding-2/on-delete-profile-success]}
[{:keys [db]} key-uid]
{:db (update-in db [:multiaccounts/multiaccounts] dissoc key-uid)})
(rf/defn password-set
{:events [:onboarding-2/password-set]}
[{:keys [db]} password]
{:db (-> db
(assoc-in [:onboarding-2/profile :password] password)
(assoc-in [:onboarding-2/profile :auth-method] constants/auth-method-password))
:dispatch [:navigate-to :enable-biometrics]})
(rf/defn seed-phrase-entered
{:events [:onboarding-2/seed-phrase-entered]}
[_ seed-phrase on-error]
{:multiaccount/validate-mnemonic [seed-phrase
#(re-frame/dispatch [:onboarding-2/seed-phrase-validated
seed-phrase])
on-error]})
(rf/defn seed-phrase-validated
{:events [:onboarding-2/seed-phrase-validated]}
[{:keys [db]} seed-phrase]
{:db (assoc-in db [:onboarding-2/profile :seed-phrase] seed-phrase)
:dispatch [:navigate-to :create-profile]})
(rf/defn navigate-to-create-profile
{:events [:onboarding-2/navigate-to-create-profile]}
[{:keys [db]}]
;; Restart the flow
{:db (dissoc db :onboarding-2/profile)
:dispatch [:navigate-to :create-profile]})
@@ -1,14 +0,0 @@
(ns status-im2.contexts.onboarding.generating-keys.style
(:require [quo2.foundations.colors :as colors]
[react-native.platform :as platform]))
(def page-container
{:padding-top (if platform/ios? 44 0)
:position :absolute
:top 0
:bottom 0
:left 0
:right 0
:background-color colors/neutral-80-opa-80-blur})
(def navigation-bar {:height 56})

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