Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff2510720 | ||
|
|
30f3ed5b3d | ||
|
|
3da2118e15 | ||
|
|
e046feb124 | ||
|
|
1e6c4e1932 | ||
|
|
2ade8fc7ee | ||
|
|
ee0df8633e |
@@ -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
@@ -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
|
||||
|
||||
|
||||
+4
-49
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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]}]
|
||||
|
||||
@@ -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}}]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))))
|
||||
@@ -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})
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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]]))
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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]])]))))
|
||||
|
||||
@@ -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}]])
|
||||
|
||||
@@ -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,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]))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
@@ -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))
|
||||
|
||||
@@ -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?]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]}
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
(defn words-count
|
||||
[s]
|
||||
(if (empty? s)
|
||||
0
|
||||
nil
|
||||
(-> s
|
||||
passphrase->words
|
||||
count)))
|
||||
|
||||
@@ -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]})))
|
||||
|
||||
|
||||
@@ -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]}
|
||||
|
||||
@@ -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,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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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"))))
|
||||
|
||||
@@ -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)]]]])))
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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])]])))
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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)]]]]))
|
||||
|
||||
@@ -202,9 +202,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
(anim/animate background-color :transparent)
|
||||
(anim/animate opacity 0)
|
||||
(rf/dispatch (if platform/ios?
|
||||
[:chat.ui/exit-lightbox-signal @index]
|
||||
[:navigate-back]
|
||||
[:navigate-back])))
|
||||
:style style/close-container}
|
||||
[quo/icon :close {:size 20 :color colors/white}]]
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
(defn toggle-opacity
|
||||
[index {:keys [opacity-value border-value transparent? atoms]} portrait?]
|
||||
(let [{:keys [small-list-ref]} atoms
|
||||
opacity (reanimated/get-shared-value opacity-value)]
|
||||
opacity (reanimated/get-shared-value opacity-value)]
|
||||
(if (= opacity 1)
|
||||
(do
|
||||
(when platform/ios?
|
||||
@@ -63,8 +63,8 @@
|
||||
(orientation/lock-to-portrait "lightbox"))
|
||||
(js/setTimeout #(when @flat-list-ref
|
||||
(.scrollToOffset
|
||||
^js @flat-list-ref
|
||||
#js {:animated false :offset (* (+ item-width seperator-width) @index)}))
|
||||
^js @flat-list-ref
|
||||
#js {:animated false :offset (* (+ item-width seperator-width) @index)}))
|
||||
timeout)
|
||||
(when platform/ios?
|
||||
(top-view/animate-rotation result screen-width screen-height insets animations))))
|
||||
@@ -124,57 +124,58 @@
|
||||
;; we get `insets` from `screen-params` because trying to consume it from
|
||||
;; lightbox screen causes lots of problems
|
||||
(let [{:keys [messages index insets]} (rf/sub [:get-screen-params])
|
||||
atoms {:flat-list-ref (atom nil)
|
||||
:small-list-ref (atom nil)
|
||||
:scroll-index-lock? (atom true)}
|
||||
render-list (reagent/atom false)
|
||||
atoms {:flat-list-ref (atom nil)
|
||||
:small-list-ref (atom nil)
|
||||
:scroll-index-lock? (atom true)}
|
||||
;; The initial value of data is the image that was pressed (and not the whole album) in order
|
||||
;; for the transition animation to execute properly, otherwise it would animate towards
|
||||
;; outside the screen (even if we have `initialScrollIndex` set).
|
||||
data (reagent/atom [(nth messages index)])
|
||||
scroll-index (reagent/atom index)
|
||||
transparent? (reagent/atom false)
|
||||
set-full-height? (reagent/atom false)
|
||||
window (rf/sub [:dimensions/window])
|
||||
window-width (:width window)
|
||||
window-height (:height window)
|
||||
window-height (if platform/android?
|
||||
(+ window-height (:top insets))
|
||||
window-height)
|
||||
animations {:background-color (anim/use-val "rgba(0,0,0,0)")
|
||||
:border (anim/use-val (if platform/ios? 0 12))
|
||||
:opacity (anim/use-val 0)
|
||||
:rotate (anim/use-val "0deg")
|
||||
:layout (anim/use-val -10)
|
||||
:top-view-y (anim/use-val 0)
|
||||
:top-view-x (anim/use-val 0)
|
||||
:top-view-width (anim/use-val window-width)
|
||||
:top-view-bg (anim/use-val colors/neutral-100-opa-0)
|
||||
:pan-y (anim/use-val 0)
|
||||
:pan-x (anim/use-val 0)}
|
||||
derived {:top-layout (worklet/info-layout (:layout animations)
|
||||
true)
|
||||
:bottom-layout (worklet/info-layout (:layout animations)
|
||||
false)}
|
||||
callback (fn [e]
|
||||
(on-viewable-items-changed e scroll-index atoms))]
|
||||
data (reagent/atom [(nth messages index)])
|
||||
scroll-index (reagent/atom index)
|
||||
transparent? (reagent/atom false)
|
||||
set-full-height? (reagent/atom false)
|
||||
window (rf/sub [:dimensions/window])
|
||||
window-width (:width window)
|
||||
window-height (:height window)
|
||||
window-height (if platform/android?
|
||||
(+ window-height (:top insets))
|
||||
window-height)
|
||||
animations {:background-color (anim/use-val "rgba(0,0,0,0)")
|
||||
:border (anim/use-val (if platform/ios? 0 12))
|
||||
:opacity (anim/use-val 0)
|
||||
:rotate (anim/use-val "0deg")
|
||||
:layout (anim/use-val -10)
|
||||
:top-view-y (anim/use-val 0)
|
||||
:top-view-x (anim/use-val 0)
|
||||
:top-view-width (anim/use-val window-width)
|
||||
:top-view-bg (anim/use-val colors/neutral-100-opa-0)
|
||||
:pan-y (anim/use-val 0)
|
||||
:pan-x (anim/use-val 0)}
|
||||
derived {:top-layout (worklet/info-layout (:layout animations)
|
||||
true)
|
||||
:bottom-layout (worklet/info-layout (:layout animations)
|
||||
false)}
|
||||
callback (fn [e]
|
||||
(on-viewable-items-changed e scroll-index atoms))]
|
||||
(anim/animate (:background-color animations) "rgba(0,0,0,1)")
|
||||
(reset! data messages)
|
||||
(orientation/use-device-orientation-change
|
||||
(fn [result]
|
||||
(if platform/ios?
|
||||
(handle-orientation result scroll-index window-width window-height animations insets atoms)
|
||||
;; `use-device-orientation-change` will always be called on Android, so need to check
|
||||
(orientation/get-auto-rotate-state
|
||||
(fn [enabled?]
|
||||
;; RNN does not support landscape-right
|
||||
(when (and enabled? (not= result orientation/landscape-right))
|
||||
(handle-orientation result
|
||||
scroll-index
|
||||
window-width
|
||||
window-height
|
||||
animations
|
||||
insets
|
||||
atoms)))))))
|
||||
(fn [result]
|
||||
(if platform/ios?
|
||||
(handle-orientation result scroll-index window-width window-height animations insets atoms)
|
||||
;; `use-device-orientation-change` will always be called on Android, so need to check
|
||||
(orientation/get-auto-rotate-state
|
||||
(fn [enabled?]
|
||||
;; RNN does not support landscape-right
|
||||
(when (and enabled? (not= result orientation/landscape-right))
|
||||
(handle-orientation result
|
||||
scroll-index
|
||||
window-width
|
||||
window-height
|
||||
animations
|
||||
insets
|
||||
atoms)))))))
|
||||
(rn/use-effect (fn []
|
||||
(when @(:flat-list-ref atoms)
|
||||
(.scrollToIndex ^js @(:flat-list-ref atoms)
|
||||
@@ -185,6 +186,7 @@
|
||||
(anim/animate (:border animations) 12))
|
||||
(if platform/ios? 250 100))
|
||||
(js/setTimeout #(reset! (:scroll-index-lock? atoms) false) 300)
|
||||
(js/setTimeout #(reset! render-list true) 500)
|
||||
(fn []
|
||||
(rf/dispatch [:chat.ui/zoom-out-signal nil])
|
||||
(when platform/android?
|
||||
@@ -202,44 +204,73 @@
|
||||
window-height
|
||||
window-width)
|
||||
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
|
||||
;[rn/view {:style (merge (style/image (+ screen-width seperator-width) screen-height) {:background-color :black})}
|
||||
;[reanimated/fast-image
|
||||
; {:source {:uri (:image (:content (nth messages index)))}
|
||||
; :native-ID :shared-element
|
||||
; :style {:width window-width
|
||||
; :height (* (:image-height (nth messages index)) (/ window-width (:image-width (nth messages index))))}
|
||||
; ;:style (style/image dimensions animations (:border-value args))
|
||||
; }]]
|
||||
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style {:background-color (:background-color
|
||||
animations)}
|
||||
animations)}
|
||||
{:height screen-height})}
|
||||
(when-not @transparent?
|
||||
[top-view/top-view (first messages) insets scroll-index animations derived landscape?
|
||||
screen-width])
|
||||
;(when-not @transparent?
|
||||
; [top-view/top-view (first messages) insets scroll-index animations derived landscape?
|
||||
; screen-width])
|
||||
[gesture/gesture-detector
|
||||
{:gesture (drag-gesture animations (and landscape? platform/ios?) set-full-height?)}
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:transform [{:translateY (:pan-y animations)}
|
||||
{:translateX (:pan-x animations)}]}
|
||||
{})}
|
||||
[gesture/flat-list
|
||||
{:ref #(reset! (:flat-list-ref atoms) %)
|
||||
:key-fn :message-id
|
||||
:style {:width (+ screen-width seperator-width)}
|
||||
:data @data
|
||||
:render-fn image
|
||||
:render-data {:opacity-value (:opacity animations)
|
||||
:border-value (:border animations)
|
||||
:transparent? transparent?
|
||||
:set-full-height? set-full-height?
|
||||
:screen-height screen-height
|
||||
:screen-width screen-width
|
||||
:window-height window-height
|
||||
:window-width window-width
|
||||
:atoms atoms}
|
||||
:horizontal horizontal?
|
||||
:inverted inverted?
|
||||
:paging-enabled true
|
||||
:get-item-layout (fn [_ index] (get-item-layout _ index item-width))
|
||||
:viewability-config {:view-area-coverage-percent-threshold 50
|
||||
:wait-for-interaction true}
|
||||
:shows-vertical-scroll-indicator false
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:on-viewable-items-changed callback}]]]
|
||||
(when (and (not @transparent?) (not landscape?))
|
||||
[bottom-view/bottom-view messages index scroll-index insets animations derived
|
||||
item-width atoms])]))]))])
|
||||
{:transform [{:translateY (:pan-y animations)}
|
||||
{:translateX (:pan-x animations)}]}
|
||||
{})}
|
||||
(if @render-list
|
||||
[gesture/flat-list
|
||||
{:ref #(reset! (:flat-list-ref atoms) %)
|
||||
:key-fn :message-id
|
||||
:style {:width (+ screen-width seperator-width)}
|
||||
:data @data
|
||||
:render-fn image
|
||||
:render-data {:opacity-value (:opacity animations)
|
||||
:border-value (:border animations)
|
||||
:transparent? transparent?
|
||||
:set-full-height? set-full-height?
|
||||
:screen-height screen-height
|
||||
:screen-width screen-width
|
||||
:window-height window-height
|
||||
:window-width window-width
|
||||
:atoms atoms}
|
||||
:initial-scroll-index index
|
||||
:horizontal horizontal?
|
||||
:inverted inverted?
|
||||
:paging-enabled true
|
||||
:get-item-layout (fn [_ index] (get-item-layout _ index item-width))
|
||||
:viewability-config {:view-area-coverage-percent-threshold 50
|
||||
:wait-for-interaction true}
|
||||
:shows-vertical-scroll-indicator false
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:on-viewable-items-changed callback}]
|
||||
[rn/view
|
||||
{:style (style/image (+ screen-width seperator-width) screen-height)}
|
||||
[rn/view {:style {:width window-width
|
||||
:height (* (:image-height (nth messages index)) (/ window-width (:image-width (nth messages index))))}}
|
||||
[reanimated/fast-image
|
||||
{:source {:uri (:image (:content (nth messages index)))}
|
||||
:native-ID :shared-element
|
||||
:style {:border-radius 12
|
||||
:width window-width
|
||||
:height (* (:image-height (nth messages index)) (/ window-width (:image-width (nth messages index))))}
|
||||
;:style (style/image dimensions animations (:border-value args))
|
||||
}]
|
||||
]
|
||||
[rn/view {:style {:width seperator-width}}]]
|
||||
)
|
||||
]]
|
||||
;(when (and (not @transparent?) (not landscape?))
|
||||
; [bottom-view/bottom-view messages index scroll-index insets animations derived
|
||||
; item-width atoms])
|
||||
]
|
||||
))]))])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}])])
|
||||
|
||||
@@ -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})
|
||||
@@ -1,30 +0,0 @@
|
||||
(ns status-im2.contexts.onboarding.generating-keys.view
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.onboarding.generating-keys.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
|
||||
:mid-section {:type :text-only :main-text ""}}]])
|
||||
|
||||
(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}} (i18n/label :t/generating-keys)]]])
|
||||
|
||||
(defn generating-keys
|
||||
[]
|
||||
[rn/view {:style {:flex 1}}
|
||||
[background/view true]
|
||||
[page]])
|
||||
@@ -1,14 +1,12 @@
|
||||
(ns status-im2.contexts.onboarding.new-to-status.view
|
||||
(:require
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.keycard.recovery :as keycard]
|
||||
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im2.contexts.onboarding.new-to-status.style :as style]
|
||||
[status-im2.contexts.onboarding.common.navigation-bar.view :as navigation-bar]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.keycard.recovery :as keycard]
|
||||
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
||||
[status-im2.common.resources :as resources]
|
||||
[status-im2.contexts.onboarding.new-to-status.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn background-image
|
||||
[]
|
||||
@@ -17,6 +15,21 @@
|
||||
:blur-radius 13
|
||||
:source (resources/get-image :onboarding-blur-bg)}])
|
||||
|
||||
(defn navigation-bar
|
||||
[]
|
||||
[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 sign-in-options
|
||||
[]
|
||||
(let [window (rf/sub [:dimensions/window])]
|
||||
@@ -36,7 +49,7 @@
|
||||
(* 2 56) ;; two other list items
|
||||
(* 2 16) ;; spacing between items
|
||||
220) ;; extra spacing (top bar)
|
||||
:on-press #(rf/dispatch [:onboarding-2/navigate-to-create-profile])}]
|
||||
:on-press #(rf/dispatch [:navigate-to :create-profile])}]
|
||||
|
||||
[rn/view {:style style/subtitle-container}
|
||||
[quo/text
|
||||
@@ -54,19 +67,12 @@
|
||||
:accessibility-label :generate-old-key
|
||||
:on-press #(rf/dispatch [:generate-and-derive-addresses])}]
|
||||
[rn/view {:style style/space-between-suboptions}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title "Temporary (old) recover phrase flow"
|
||||
:subtitle (i18n/label :t/use-recovery-phrase-subtitle)
|
||||
:image (resources/get-image :ethereum-address)
|
||||
:on-press #(rf/dispatch [::multiaccounts.recover/enter-phrase-pressed])}]
|
||||
[rn/view {:style style/space-between-suboptions}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-recovery-phrase)
|
||||
:subtitle (i18n/label :t/use-recovery-phrase-subtitle)
|
||||
:image (resources/get-image :ethereum-address)
|
||||
:on-press #(rf/dispatch [:navigate-to :enter-seed-phrase])}]
|
||||
:on-press #(rf/dispatch [::multiaccounts.recover/enter-phrase-pressed])}]
|
||||
[rn/view {:style style/space-between-suboptions}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
@@ -80,5 +86,5 @@
|
||||
[rn/view {:style style/full-screen}
|
||||
[background-image]
|
||||
[rn/view {:style style/layer-background}
|
||||
[navigation-bar/navigation-bar {:on-press-info #(js/alert "Info pressed")}]
|
||||
[navigation-bar]
|
||||
[sign-in-options]]])
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user