Compare commits

..
Author SHA1 Message Date
Mohamed Javid 5062b07934 feature(ios): Add screenshot and screen capture block
Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-06-29 21:29:34 +05:30
241 changed files with 2549 additions and 4415 deletions
+1
View File
@@ -26,6 +26,7 @@ APN_TOPIC=im.status.ethereum.pr
COMMUNITIES_ENABLED=1
DATABASE_MANAGEMENT_ENABLED=1
DELETE_MESSAGE_ENABLED=1
COLLECTIBLES_ENABLED=1
COMMANDS_ENABLED=1
TWO_MINUTES_SYNCING=1
SWAP_ENABLED=1
+1
View File
@@ -18,5 +18,6 @@ PARTITIONED_TOPIC=0
ENABLE_ROOT_ALERT=1
MAX_IMAGES_BATCH=1
DELETE_MESSAGE_ENABLED=1
COLLECTIBLES_ENABLED=1
FAST_CREATE_COMMUNITY_ENABLED=0
TEST_NETWORKS_ENABLED=0
-6
View File
@@ -457,12 +457,6 @@ android-tail-geth: export VERSION ?= debug
android-tail-geth:
adb shell 'while true; do cat; sleep 1; done < /storage/emulated/0/Android/data/im.status.ethereum$$( [ "$(VERSION)" = "release" ] || echo ".$(VERSION)" )/files/Download/geth.log'
android-clean-geth: export TARGET := android-sdk
android-clean-geth: export VERSION ?= debug
android-clean-geth:
adb shell 'rm /storage/emulated/0/Android/data/im.status.ethereum$$( [ "$(VERSION)" = "release" ] || echo ".$(VERSION)" )/files/Download/geth.log'
android-logcat: export TARGET := android-sdk
android-logcat: ##@other Read status-mobile logs from Android phone using adb
adb logcat | grep -e RNBootstrap -e ReactNativeJS -e ReactNative -e StatusModule -e StatusNativeLogs -e 'F DEBUG :' -e 'Go :' -e 'GoLog :' -e 'libc :'
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -71,7 +71,7 @@ pipeline {
}
stage('Upload') {
steps { script {
def urls = apks.collect { s5cmd.upload(it) }
def urls = apks.collect { s3.uploadArtifact(it) }
if (urls.size() > 1) { /* Return only the universal APK. */
env.PKG_URL = urls.find { it.contains('universal') }
} else { /* If no universal is available pick first. */
+3 -24
View File
@@ -1,7 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
import groovy.json.JsonBuilder
library 'status-jenkins-lib@v1.8.12'
pipeline {
agent { label 'linux' }
@@ -74,7 +72,7 @@ pipeline {
iOS: utils.pkgUrl(ios),
Diawi: utils.getEnv(ios, 'DIAWI_URL'),
/* upload the sha256 checksums file too */
SHA: s5cmd.upload(sha),
SHA: s3.uploadArtifact(sha),
]
/* add URLs to the build description */
jenkins.setBuildDesc(urls)
@@ -85,7 +83,7 @@ pipeline {
steps { script {
switch (utils.getBuildType()) {
case 'nightly': /* Create JSON file with newest build URLs */
updateBucketJSON(urls, 'latest.json');
s3.updateBucketJSON(urls, 'latest.json');
break;
case 'release':
github.publishReleaseFiles(repo: 'status-mobile');
@@ -116,22 +114,3 @@ def Boolean getPublishDefault(Boolean previousValue) {
if (previousValue != null) { return previousValue }
return false
}
/* Helper for updating JSON with newest builds. */
def updateBucketJSON(urls, fileName) {
/* latest.json has slightly different key names */
def content = [
DIAWI: urls.Diawi,
APK: urls.Apk, IOS: urls.iOS,
APP: urls.App, MAC: urls.Mac,
WIN: urls.Win, SHA: urls.SHA
]
def filePath = "${pwd()}/pkg/${fileName}"
/* it might not exist */
sh "mkdir -p ${pwd()}/pkg"
def contentJson = new JsonBuilder(content).toPrettyString()
println "${filePath}:\n${contentJson}"
writeFile(file: filePath, text: contentJson)
return s5cmd.upload(filePath)
}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -75,7 +75,7 @@ pipeline {
stage('Upload') {
steps {
script {
env.PKG_URL = s5cmd.upload(LOG_FILE)
env.PKG_URL = s3.uploadArtifact(LOG_FILE)
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
agent { label params.AGENT_LABEL }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.1'
library 'status-jenkins-lib@v1.8.12'
pipeline {
agent {
+3 -5
View File
@@ -32,16 +32,14 @@ status-mobile code that makes it to the `develop` branch, should always point to
In practice, this means that sometimes they need to be merged in lockstep.
1) Create a PR in status-go and status-mobile. Update the status-go version to the PR revision `scripts/update-status-go.sh $git_revision`.
2) Get both PRs reviewed and approved. Once status-mobile PR has been approved, go through manual QA testing if necessary. Don't merge status-mobile PR just yet.
3) Now that you know the integration between client & server is working, merge the status-go PR first.
4) Once merged, tag the merged commit with the new version and push the tag:
3) Now that you know the integration between client & server is working, bump the `VERSION` in status-go and merge it.
4) Once merged, tag the version with the new version and push the tag:
```
git checkout develop
git pull develop
make tag-version
git tag vx.y.z
git push origin vx.y.z
```
:warning: If a specific commit need to tagged in status-go, use `make tag-version TARGET_COMMIT={hash}`. More info about tagging in [status-go](https://github.com/status-im/status-go/blob/develop/RELEASING.md#tagging-versions).
5) Update status-mobile with the new status-go version, using the new tag `scripts/update-status-go.sh "vx.y.z"`
6) If you had to rebase status-go to include new changes, e2e test MUST be re-run. If there's any issue you will
have to fix in status-go with another PR and follow the same process.
+2 -2
View File
@@ -31,7 +31,7 @@ NOW:
(defn view
[{:keys [on-press on-long-press icon]}]
(let [[pressed? set-pressed] (rn/use-state false)
theme (theme/use-theme)
theme (theme/use-theme-value)
on-press-in (rn/use-callback #(set-pressed true))
on-press-out (rn/use-callback #(set-pressed nil))]
[rn/pressable
@@ -47,7 +47,7 @@ NOW:
- We no longer need to create an anonymous function for rendering. This removes unnecessary confusion and the need for specific knowledge on how it works and why it was needed.
- `rn/use-state` is used instead of `reagent/atom`
- State values no longer need to be dereferenced; they are accessible as regular symbols. This eliminates a common bug where the "@" symbol was inadvertently omitted.
- `theme/with-theme` wrapper is not needed anymore, `(theme/use-theme)` hook can be used directly in the components
- `theme/with-theme` wrapper is not needed anymore, `(theme/use-theme-value)` hook can be used directly in the components
- `:f>` not needed anymore, all components are functional by default
- `rn/use-callback` hook should be used for anon callback functions
@@ -246,14 +246,6 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
utils.executeRunnableStatusGoMethod({ Statusgo.openAccounts(rootDir) }, callback)
}
@ReactMethod
private fun initializeApplication(request: String, callback: Callback) {
Log.d(TAG, "initializeApplication")
Log.d(TAG, "[Initializing application $request")
utils.executeRunnableStatusGoMethod({ Statusgo.initializeApplication(request) }, callback)
}
@ReactMethod
fun logout() {
Log.d(TAG, "logout")
@@ -76,16 +76,6 @@ class StatusModule(private val reactContext: ReactApplicationContext, private va
utils.executeRunnableStatusGoMethod({ Statusgo.getNodeConfig() }, callback)
}
@ReactMethod
fun addCentralizedMetric(request: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.addCentralizedMetric(request) }, callback)
}
@ReactMethod
fun toggleCentralizedMetrics(request: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.toggleCentralizedMetrics(request) }, callback)
}
@ReactMethod
fun deleteImportedKey(keyUID: String, address: String, password: String, callback: Callback) {
val keyStoreDir = utils.getKeyStorePath(keyUID)
@@ -153,9 +153,4 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
return strArray
}
@ReactMethod(isBlockingSynchronousMethod = true)
fun validateConnectionString(connectionString: String): String {
return Statusgo.validateConnectionString(connectionString)
}
}
@@ -195,15 +195,6 @@ RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID
callback(@[result]);
}
RCT_EXPORT_METHOD(initializeApplication:(NSString *)request
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"initializeApplication() method called");
#endif
NSString *result = StatusgoInitializeApplication(request);
callback(@[result]);
}
RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"OpenAccounts() method called");
@@ -3,6 +3,7 @@
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "Utils.h"
#import "UIHelper.h"
@implementation EncryptionUtils
@@ -101,6 +102,13 @@ RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue)
[userDefaults setBool:newValue forKey:@"BLANK_PREVIEW"];
[userDefaults synchronize];
if (newValue) {
[UIHelper addScreenshotBlock];
} else {
[UIHelper removeScreenshotBlock];
}
}
RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON
@@ -176,24 +176,6 @@ RCT_EXPORT_METHOD(appStateChange:(NSString *)type) {
StatusgoAppStateChange(type);
}
RCT_EXPORT_METHOD(addCentralizedMetric:(NSString *)request
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"addCentralizedMetric() method called");
#endif
NSString *result = StatusgoAddCentralizedMetric(request);
callback(@[result]);
}
RCT_EXPORT_METHOD(toggleCentralizedMetrics:(NSString *)request
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"toggleCentralizedMetrics() method called");
#endif
NSString *result = StatusgoToggleCentralizedMetrics(request);
callback(@[result]);
}
RCT_EXPORT_METHOD(startLocalNotifications) {
#if DEBUG
NSLog(@"StartLocalNotifications() method called");
@@ -5,4 +5,7 @@
@interface UIHelper : NSObject <RCTBridgeModule>
+ (void)addScreenshotBlock;
+ (void)removeScreenshotBlock;
@end
@@ -8,6 +8,9 @@ RCT_EXPORT_MODULE();
#pragma mark - only android methods
UITextField *textField;
UIView *guardView;
RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) {
#if DEBUG
NSLog(@"setSoftInputMode() works only on Android");
@@ -35,5 +38,75 @@ RCT_EXPORT_METHOD(clearStorageAPIs) {
}
}
+ (void) addScreenshotBlock {
// create new secure text field and append to the window layer to prevent screenshot
if (textField == nil) {
UIWindow *window = [UIApplication sharedApplication].keyWindow;
textField = [[UITextField alloc] initWithFrame:window.frame];
textField.translatesAutoresizingMaskIntoConstraints = NO;
[textField setTextAlignment:NSTextAlignmentCenter];
[textField setUserInteractionEnabled: NO];
[window makeKeyAndVisible];
[window.layer.superlayer addSublayer:textField.layer];
if (textField.layer.sublayers.firstObject) {
[textField.layer.sublayers.firstObject addSublayer: window.layer];
}
}
[textField setSecureTextEntry: TRUE];
[textField setBackgroundColor: [UIColor blackColor]];
// create event listener for screen captures and add a view to prevent the app content from exposed if recorded
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[center removeObserver:self
name:UIScreenCapturedDidChangeNotification
object:nil];
[center addObserverForName:UIScreenCapturedDidChangeNotification
object:nil
queue:mainQueue
usingBlock:^(NSNotification *notification) {
if (UIScreen.mainScreen.captured){
UIWindow *window = [UIApplication sharedApplication].keyWindow;
if (guardView == nil) {
guardView = [[UIView alloc]initWithFrame:window.frame];
guardView.backgroundColor = [UIColor blackColor];
guardView.alpha = 0;
}
[window addSubview:guardView];
[window bringSubviewToFront:guardView];
[UIView animateWithDuration:0.5 animations:^{
guardView.alpha = 1;
}];
} else {
[UIView animateWithDuration:0.5 animations:^{
guardView.alpha = 0;
} completion:^(BOOL finished) {
[guardView removeFromSuperview];
}];
}
}];
}
+ (void) removeScreenshotBlock {
UIWindow *window = [UIApplication sharedApplication].keyWindow;
if (textField != nil) {
[textField setSecureTextEntry: FALSE];
[textField setBackgroundColor: [UIColor clearColor]];
CALayer *textFieldLayer = textField.layer.sublayers.firstObject;
if ([window.layer.superlayer.sublayers containsObject:textFieldLayer]) {
[textFieldLayer removeFromSuperlayer];
}
}
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self
name:UIScreenCapturedDidChangeNotification
object:nil];
}
@end
@@ -128,8 +128,4 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(toChecksumAddress:(NSString *)address) {
return StatusgoToChecksumAddress(address);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(validateConnectionString:(NSString *)cs) {
return StatusgoValidateConnectionString(cs);
}
@end
+1 -32
View File
@@ -302,36 +302,6 @@ void _MultiAccountStoreAccount(const FunctionCallbackInfo<Value>& args) {
delete c;
}
void _InitializeApplication(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.Length() != 1) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8Literal(isolate, "Wrong number of arguments for InitializeApplication")));
return;
}
// Check the argument types
if (!args[0]->IsString()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8Literal(isolate, "Wrong argument type for request")));
return;
}
String::Utf8Value arg0Obj(isolate, args[0]->ToString(context).ToLocalChecked());
char *arg0 = *arg0Obj;
// Call exported Go function, which returns a C string
char *c = InitializeApplication(arg0);
Local<String> ret = String::NewFromUtf8(isolate, c).ToLocalChecked();
args.GetReturnValue().Set(ret);
delete c;
}
void _InitKeystore(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
@@ -1965,7 +1935,6 @@ void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "multiAccountStoreDerivedAccounts", _MultiAccountStoreDerivedAccounts);
NODE_SET_METHOD(exports, "multiAccountStoreAccount", _MultiAccountStoreAccount);
NODE_SET_METHOD(exports, "initKeystore", _InitKeystore);
NODE_SET_METHOD(exports, "initializeApplication", _InitializeApplication);
NODE_SET_METHOD(exports, "fleets", _Fleets);
NODE_SET_METHOD(exports, "stopCPUProfiling", _StopCPUProfiling);
NODE_SET_METHOD(exports, "encodeTransfer", _EncodeTransfer);
@@ -2003,7 +1972,7 @@ void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "signTypedData", _SignTypedData);
NODE_SET_METHOD(exports, "sendTransaction", _SendTransaction);
NODE_SET_METHOD(exports, "appStateChange", _AppStateChange);
NODE_SET_METHOD(exports, "setSignalEventCallback", _SetSignalEventCallback);
NODE_SET_METHOD(exports, "setSignalEventCallback", _SetSignalEventCallback);
NODE_SET_METHOD(exports, "validateNodeConfig", _ValidateNodeConfig);
NODE_SET_METHOD(exports, "hashTypedData", _HashTypedData);
NODE_SET_METHOD(exports, "recover", _Recover);
+1 -1
View File
@@ -57,7 +57,7 @@ in {
yarn = super.yarn.override { nodejs = super.nodejs-18_x; };
openjdk = super.openjdk11_headless;
xcodeWrapper = callPackage ./pkgs/xcodeenv/compose-xcodewrapper.nix { } {
versions = ["15.1" "15.2" "15.3" "15.4"];
versions = ["15.1" "15.2" "15.3"];
};
go = super.go_1_21;
clang = super.clang_15;
+2 -3
View File
@@ -20,10 +20,9 @@
"@react-native-community/netinfo": "^4.4.0",
"@react-native-community/push-notification-ios": "^1.4.1",
"@react-native-community/slider": "^3.0.0",
"@walletconnect/react-native-compat": "2.11.2",
"@walletconnect/web3wallet": "1.10.2",
"@walletconnect/react-native-compat": "^2.12.2",
"@walletconnect/web3wallet": "^1.11.2",
"base-64": "^1.0.0",
"big-integer": "1.6.51",
"bignumber.js": "git+https://github.com/status-im/bignumber.js.git#refs/tags/v4.0.2-status",
"chance": "^1.1.0",
"emojilib": "^2.4.0",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

-2
View File
@@ -45,8 +45,6 @@ SECRETS_ENV_VARS=(
'INFURA_TOKEN'
'INFURA_TOKEN_SECRET'
'OPENSEA_API_KEY'
'MIXPANEL_APP_ID'
'MIXPANEL_TOKEN'
'POKT_TOKEN'
)
-6
View File
@@ -67,8 +67,6 @@
:closure-defines
{status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID"
status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN"
status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
@@ -104,8 +102,6 @@
{status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID"
status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN"
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
status-im.config/ALCHEMY_ETHEREUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ETHEREUM_MAINNET_TOKEN"
@@ -147,8 +143,6 @@
status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID"
status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN"
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
status-im.config/ALCHEMY_ETHEREUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ETHEREUM_MAINNET_TOKEN"
+4 -3
View File
@@ -26,6 +26,7 @@
legacy.status-im.ui.components.invite.events
[legacy.status-im.ui.components.react :as react]
legacy.status-im.ui.screens.notifications-settings.events
legacy.status-im.ui.screens.privacy-and-security-settings.events
[legacy.status-im.utils.dimensions :as dimensions]
legacy.status-im.utils.logging.core
[legacy.status-im.utils.utils :as utils]
@@ -107,7 +108,8 @@
(when (and (multiaccounts.model/logged-in? db)
(= current-theme-type status-im.constants/theme-type-system))
{:profile.settings/switch-theme-fx
[(get-in db [:profile/profile :appearance]) (:view-id db)]})))
[(get-in db [:profile/profile :appearance])
(:view-id db) true]})))
(defn- on-biometric-auth-fail
[{:keys [code]}]
@@ -133,8 +135,7 @@
(>= (- now app-in-background-since)
constants/ms-in-bg-for-require-bioauth))]
(rf/merge cofx
{:db (dissoc db :app-in-background-since)
:effects.biometric/get-supported-type nil}
{:db (dissoc db :app-in-background-since)}
(mailserver/process-next-messages-request)
(when-not new-account?
(universal-links/process-stored-event))
@@ -120,3 +120,12 @@
{:events [:multiaccounts.ui/switch-backup-enabled]}
[cofx enabled?]
(multiaccount-update cofx :backup-enabled? enabled? {}))
(rf/defn toggle-opensea-nfts-visibility
{:events [::toggle-opensea-nfts-visiblity]}
[cofx visible?]
(rf/merge cofx
{:db (assoc-in (:db cofx) [:profile/profile :opensea-enabled?] visible?)
;; need to add fully qualified namespace to counter circular deps
:dispatch [:legacy.status-im.wallet.core/fetch-collectibles-collection]}
(multiaccount-update :opensea-enabled? visible? {})))
+1 -1
View File
@@ -17,7 +17,7 @@
(reg-root-key-sub :ui/search :ui/search)
(reg-root-key-sub :network/type :network/type)
(reg-root-key-sub :network-status :network-status)
(reg-root-key-sub :peer-stats/count :peer-stats/count)
(reg-root-key-sub :peers-count :peers-count)
(reg-root-key-sub :peers-summary :peers-summary)
(reg-root-key-sub :web3-node-version :web3-node-version)
@@ -1,9 +1,14 @@
(ns legacy.status-im.ui.components.connectivity.view
(:require
[clojure.string :as string]
[legacy.status-im.ui.components.animation :as animation]
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.react :as react])
(:require-macros [legacy.status-im.utils.views :as views]))
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.react :as react]
[re-frame.core :as re-frame]
[utils.i18n :as i18n])
(:require-macros [legacy.status-im.utils.views :as views :refer [defview letsubs]]))
(defn easing
[direction n]
@@ -67,3 +72,112 @@
colors/white)
:left
(* 0.15 parent-width))}]]]))
(defview loading-indicator
[]
(letsubs [fetching? [:mailserver/fetching?]
window-width [:dimensions/window-width]]
(when fetching?
[loading-indicator-anim window-width])))
(defn hide-sheet-and-dispatch
[event]
(re-frame/dispatch [:bottom-sheet/hide-old])
(re-frame/dispatch event))
(defview connectivity-sheet
[]
(letsubs [{:keys [peers node mobile sync]} [:connectivity/state]
current-mailserver-name [:mailserver/current-name]
peers-count [:peers-count]
{:keys [syncing-on-mobile-network?]} [:profile/profile]]
[:<>
[quo/header {:title (i18n/label :t/connection-status) :border-bottom false}]
[quo/list-header (i18n/label :t/peer-to-peer)]
(if (= peers :offline)
[list.item/list-item
{:title (i18n/label :t/not-connected-to-peers)
:accessibility-label "not-connected-to-peers"
:subtitle (i18n/label :t/unable-to-send-messages)
:subtitle-max-lines 2
:theme :negative
:icon :main-icons/network}]
[list.item/list-item
{:title (str (i18n/label :t/connected-to)
" " peers-count
" " (string/lower-case (i18n/label :t/peers)))
:accessibility-label "connected-to-n-peers"
:subtitle (i18n/label :t/can-send-messages)
:subtitle-max-lines 2
:theme :positive
:icon :main-icons/network}])
[quo/list-header (i18n/label :t/history-nodes)]
(cond
(#{:error :offline} node)
[list.item/list-item
{:title (i18n/label :t/not-connected-nodes)
:accessibility-label "not-connected-nodes"
:subtitle (i18n/label :t/unable-to-fetch)
:theme :negative
:icon :main-icons/mailserver}]
(= node :disabled)
[list.item/list-item
{:title (i18n/label :t/nodes-disabled)
:accessibility-label "nodes-disabled"
:subtitle (i18n/label :t/unable-to-fetch)
:disabled true
:icon :main-icons/mailserver}]
(and mobile (not sync))
[list.item/list-item
{:title (i18n/label :t/waiting-wi-fi)
:accessibility-label "waiting-wi-fi"
:subtitle (i18n/label :t/unable-to-fetch)
:disabled true
:icon :main-icons/mailserver}]
(= node :connecting)
[list.item/list-item
{:title (i18n/label :t/connecting)
:accessibility-label "connecting"
:subtitle (i18n/label :t/unable-to-fetch)
:icon :main-icons/mailserver}]
(= node :online)
[list.item/list-item
{:title (str (i18n/label :t/connected-to) " " current-mailserver-name)
:accessibility-label "connected-to-mailserver"
:subtitle (i18n/label :t/you-can-fetch)
:theme :positive
:icon :main-icons/mailserver}])
[list.item/list-item
{:title (i18n/label :t/settings)
:accessibility-label "settings"
:theme :accent
:on-press #(hide-sheet-and-dispatch [:navigate-to :legacy-sync-settings])
:icon :main-icons/settings}]
(when mobile
[:<>
[react/view
{:margin-vertical 8
:background-color colors/gray-lighter
:height 36
:align-items :center
:justify-content :center}
[react/text {:style {:color colors/gray}} (i18n/label :t/youre-on-mobile-network)]]
[list.item/list-item
{:title (i18n/label :t/mobile-network-use-mobile)
:accessibility-label "mobile-network-use-mobile"
:accessory :switch
:on-press #(re-frame/dispatch [:mobile-network/set-syncing
(not syncing-on-mobile-network?)])
:active syncing-on-mobile-network?}]
[react/text {:style {:margin-horizontal 16 :margin-bottom 12 :color colors/gray}}
(i18n/label :t/status-mobile-descr)]])]))
(defn get-icon
[{:keys [peers node mobile sync]}]
(if (or (= peers :offline)
(= node :offline)
(= node :connecting))
:main-icons/offline
(if mobile
(if sync :main-icons/mobile-sync :main-icons/mobile-sync-off)
(when (#{:error :disabled} node) :main-icons/node-offline))))
@@ -0,0 +1,11 @@
(ns legacy.status-im.ui.screens.dapps-permissions.styles
(:require
[legacy.status-im.ui.components.colors :as colors]))
(def icon-container
{:width 40
:height 40
:border-radius 20
:background-color colors/gray-lighter
:align-items :center
:justify-content :center})
@@ -0,0 +1,64 @@
(ns legacy.status-im.ui.screens.dapps-permissions.views
(:require-macros [legacy.status-im.utils.views :as views])
(:require
[legacy.status-im.ui.components.colors :as colors]
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.icons.icons :as icons]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.list.views :as list]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.components.topbar :as topbar]
[legacy.status-im.ui.screens.dapps-permissions.styles :as styles]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[utils.i18n :as i18n]))
(defn d-icon
[]
[react/view styles/icon-container
[icons/icon :main-icons/dapp {:color colors/gray}]])
(defn prepare-items
[{:keys [dapp permissions]}]
{:title dapp
:chevron true
:on-press #(re-frame/dispatch [:navigate-to :manage-dapps-permissions
{:dapp dapp :permissions permissions}])
:icon [d-icon]})
(defn prepare-items-manage
[name]
(fn [permission]
{:title (cond
(= permission constants/dapp-permission-web3)
name
(= permission constants/dapp-permission-contact-code)
(i18n/label :t/contact-code))
:size :small
:accessory [icons/icon :main-icons/check {}]}))
(views/defview dapps-permissions
[]
(views/letsubs [permissions [:dapps/permissions]]
[list/flat-list
{:data (vec (map prepare-items (vals permissions)))
:key-fn (fn [_ i] (str i))
:render-fn list.item/list-item}]))
(views/defview manage
[]
(views/letsubs [{:keys [dapp permissions]} [:get-screen-params]
{:keys [name]} [:dapps-account]]
[:<>
[topbar/topbar {:title dapp}]
[list/flat-list
{:data (vec (map (prepare-items-manage name) permissions))
:key-fn (fn [_ i] (str i))
:render-fn list.item/list-item}]
[react/view
{:padding-vertical 16
:padding-horizontal 16}
[quo/button
{:theme :negative
:on-press #(re-frame/dispatch [:dapps/revoke-access dapp])}
(i18n/label :t/revoke-access)]]]))
@@ -0,0 +1,13 @@
(ns legacy.status-im.ui.screens.link-previews-settings.styles)
(def link-preview-settings-image
{:height 100
:align-self :center
:margin-top 16})
(def whitelist-container
{:flex-direction :row
:justify-content :space-between})
(def enable-all
{:align-self :flex-end})
@@ -0,0 +1,67 @@
(ns legacy.status-im.ui.screens.link-previews-settings.views
(:require-macros [legacy.status-im.utils.views :as views])
(:require
[legacy.status-im.react-native.resources :as resources]
[legacy.status-im.ui.components.core :as components]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.list.views :as list]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.screens.link-previews-settings.styles :as styles]
[quo.core :as quo]
[re-frame.core :as re-frame]
[status-im.contexts.chat.messenger.messages.link-preview.events]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn prepare-urls-items-data
[link-previews-enabled-sites]
(fn [{:keys [title address]}]
(let [enabled? (contains? link-previews-enabled-sites title)]
{:title title
:subtitle address
:size :small
:accessory :switch
:active (contains? link-previews-enabled-sites title)
:on-press #(re-frame/dispatch
[:chat.ui/enable-link-previews title ((complement boolean) enabled?)])})))
(views/defview link-previews-settings
[]
(views/letsubs [link-previews-whitelist [:link-previews-whitelist]
link-previews-enabled-sites [:link-preview/enabled-sites]]
(let [all-enabled (= (count link-previews-whitelist) (count link-previews-enabled-sites))]
[:<>
[quo/page-nav
{:type :title
:title (i18n/label :t/chat-link-previews)
:background :blur
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
[react/image
{:source (resources/get-theme-image :unfurl)
:style styles/link-preview-settings-image}]
[components/text {:style {:margin 16}}
(i18n/label :t/you-can-choose-preview-websites)]
[components/separator {:style {:margin-vertical 8}}]
[react/view styles/whitelist-container
[components/list-header (i18n/label :t/websites)]
(when (> (count link-previews-whitelist) 1)
[components/button
{:on-press #(re-frame/dispatch [:chat.ui/enable-all-link-previews
link-previews-whitelist
(not all-enabled)])
:type :secondary
:style styles/enable-all}
(if all-enabled
(i18n/label :t/disable-all)
(i18n/label :t/enable-all))])]
[list/flat-list
{:data (vec (map (prepare-urls-items-data link-previews-enabled-sites)
link-previews-whitelist))
:key-fn (fn [_ i] (str i))
:render-fn list.item/list-item
:footer [quo/text
{:color :secondary
:style {:margin 16}} (i18n/label :t/previewing-may-share-metadata)]}]])))
@@ -1,21 +1,17 @@
(ns legacy.status-im.ui.screens.peers-stats
(:require
[react-native.core :as rn]
[react-native.core :as react-native.core]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as re-frame]))
(defn peers-stats
[]
(let [peers-count (rf/sub [:peer-stats/count])]
(rn/use-mount
(fn []
(rf/dispatch [:peer-stats/get-count])))
[rn/view
{:style {:flex 1
:margin-horizontal 8}}
[rn/view
(let [peers-count (re-frame/sub [:peers-count])]
[react-native.core/view
{:flex 1
:margin-horizontal 8}
[react-native.core/view
{:style {:flex-direction :row
:margin-vertical 8
:justify-content :space-between}}
[rn/text (str (i18n/label :t/peers-count) ": " peers-count)]]]))
[react-native.core/text (str (i18n/label :t/peers-count) ": " peers-count)]]]))
@@ -0,0 +1,81 @@
(ns legacy.status-im.ui.screens.privacy-and-security-settings.delete-profile
(:require
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[legacy.status-im.ui.components.core :as quo]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.react :as react]
[legacy.status-im.ui.screens.privacy-and-security-settings.events :as delete-profile]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.contexts.profile.utils :as profile.utils]
[utils.i18n :as i18n]
[utils.security.core :as security]))
(defn valid-password?
[password]
(>= (count password) 6))
(defn on-delete-profile
[password]
#(do
(re-frame/dispatch
[::delete-profile/delete-profile @password])
(reset! password nil)))
(defn delete-profile
[]
(let [password (reagent/atom nil)
text-input-ref (atom nil)]
(fn []
(let [profile @(re-frame/subscribe [:profile/profile])
error @(re-frame/subscribe [:delete-profile/error])
keep-keys-on-keycard? @(re-frame/subscribe
[:delete-profile/keep-keys-on-keycard?])]
(when (and @text-input-ref error (not @password))
(.clear ^js @text-input-ref))
[react/keyboard-avoiding-view {:style {:flex 1}}
[react/scroll-view {:style {:flex 1}}
[react/view {:style {:align-items :center}}
[quo/text
{:weight :bold
:size :x-large}
(i18n/label :t/delete-profile)]]
[list.item/list-item
{:title (profile.utils/displayed-name profile)
:icon [chat-icon.screen/contact-icon-contacts-tab profile]}]
[quo/text
{:style {:margin-horizontal 24}
:align :center
:color :negative}
(i18n/label :t/delete-profile-warning)]
[quo/text-input
{:style {:margin-horizontal 36
:margin-top 36}
:show-cancel false
:secure-text-entry true
:return-key-type :next
:on-submit-editing nil
:auto-focus true
:on-change-text #(reset! password (security/mask-data %))
:bottom-value 36
:get-ref #(reset! text-input-ref %)
:error (when (and error (not @password))
(if (= :wrong-password error)
(i18n/label :t/wrong-password)
(str error)))}]]
[react/view {:style {:align-items :center}}
[quo/separator]
(when (not keep-keys-on-keycard?)
[quo/text
{:style {:margin-horizontal 24 :margin-bottom 16}
:align :center
:color :negative}
(i18n/label :t/delete-profile-warning)])
[react/view
{:style {:margin-vertical 8}}
[quo/button
{:on-press (on-delete-profile password)
:theme :negative
:accessibility-label :delete-profile-confirm
:disabled ((complement valid-password?) @password)}
(i18n/label :t/delete-profile)]]]]))))
@@ -0,0 +1,73 @@
(ns legacy.status-im.ui.screens.privacy-and-security-settings.events
(:require
[clojure.string :as string]
[legacy.status-im.utils.deprecated-types :as types]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn safe-blank?
[s]
(or (not s)
(string/blank? s)))
(re-frame/reg-fx
::delete-profile
(fn [{:keys [address key-uid callback masked-password]}]
(let [hashed-password
(-> masked-password
security/safe-unmask-data
native-module/sha3)]
(native-module/verify
address
hashed-password
(fn [result]
(let [{:keys [error]} (types/json->clj result)]
(log/info "[delete-profile] verify-password" result error)
(if-not (safe-blank? error)
(callback :wrong-password nil)
(native-module/delete-multiaccount
key-uid
(fn [result]
(let [{:keys [error]} (types/json->clj result)]
(callback error nil)))))))))))
(rf/defn delete-profile
{:events [::delete-profile]}
[{:keys [db] :as cofx} masked-password]
(log/info "[delete-profile] delete")
(let [{:keys [key-uid wallet-root-address]} (:profile/profile db)]
{:db (dissoc db :delete-profile/error)
::delete-profile
{:masked-password masked-password
:key-uid key-uid
:address wallet-root-address
:callback
(fn [error result]
(log/info "[delete-profile] callback" error)
(if (safe-blank? error)
(re-frame/dispatch [::on-delete-profile-success result])
(re-frame/dispatch [::on-delete-profile-failure error])))}}))
(rf/defn on-delete-profile-success
{:events [::on-delete-profile-success]}
[cofx]
(log/info "[delete-profile] on-success")
{:effects.utils/show-popup
{:title (i18n/label :t/profile-deleted-title)
:content (i18n/label :t/profile-deleted-content)
:on-dismiss #(re-frame/dispatch [:logout])}})
(rf/defn on-delete-profile-failure
{:events [::on-delete-profile-failure]}
[{:keys [db]} error]
(log/info "[delete-profile] on-failure" error)
{:db (assoc db :delete-profile/error error)})
(rf/defn keep-keys-on-keycard
{:events [::keep-keys-on-keycard]}
[{:keys [db] :as cofx} checked?]
{:db (assoc-in db [:delete-profile/keep-keys-on-keycard?] checked?)})
@@ -0,0 +1,34 @@
(ns legacy.status-im.ui.screens.privacy-and-security-settings.messages-from-contacts-only
(:require-macros [legacy.status-im.utils.views :as views])
(:require
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.react :as react]
[re-frame.core :as re-frame]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/defn handle-messages-from-contacts-only-switched
{:events [::messages-from-contacts-only-switched]}
[cofx value]
(multiaccounts.update/multiaccount-update cofx
:messages-from-contacts-only
value
{}))
(views/defview messages-from-contacts-only-view
[]
(views/letsubs [{:keys [messages-from-contacts-only]} [:profile/profile]]
[react/view {:margin-top 8}
[list.item/list-item
{:active (not messages-from-contacts-only)
:accessory :radio
:title (i18n/label :t/anyone)
:on-press #(re-frame/dispatch [::messages-from-contacts-only-switched false])}]
[list.item/list-item
{:active messages-from-contacts-only
:accessory :radio
:title (i18n/label :t/contacts)
:subtitle (i18n/label :t/messages-from-contacts-only-subtitle)
:subtitle-max-lines 4
:on-press #(re-frame/dispatch [::messages-from-contacts-only-switched true])}]]))
@@ -0,0 +1,175 @@
(ns legacy.status-im.ui.screens.privacy-and-security-settings.views
(:require
[legacy.status-im.multiaccounts.reset-password.core :as reset-password]
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
[legacy.status-im.ui.components.core :as components]
[legacy.status-im.ui.components.list.item :as list.item]
[legacy.status-im.ui.components.react :as react]
[quo.core :as quo]
[re-frame.core :as re-frame]
[react-native.platform :as platform]
[status-im.config :as config]
[status-im.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf])
(:require-macros [legacy.status-im.utils.views :as views]))
(defn separator
[]
[components/separator {:style {:margin-vertical 8}}])
(def titles
{constants/profile-pictures-visibility-contacts-only (i18n/label :t/recent-recipients)
constants/profile-pictures-visibility-everyone (i18n/label :t/everyone)
constants/profile-pictures-visibility-none (i18n/label :t/none)
constants/profile-pictures-show-to-contacts-only (i18n/label :t/recent-recipients)
constants/profile-pictures-show-to-everyone (i18n/label :t/everyone)
constants/profile-pictures-show-to-none (i18n/label :t/none)})
(views/defview privacy-and-security
[]
(views/letsubs [{:keys [preview-privacy?
messages-from-contacts-only
webview-allow-permission-requests?
opensea-enabled?
profile-pictures-visibility]}
[:profile/profile]
has-picture [:profile/has-picture]
profile-pictures-show-to [:multiaccount/profile-pictures-show-to]]
[:<>
[quo/page-nav
{:type :no-title
:background :blur
:icon-name :i/close
:on-press #(rf/dispatch [:navigate-back])}]
[react/scroll-view {:padding-vertical 8}
[components/list-header (i18n/label :t/privacy)]
[list.item/list-item
{:size :small
:title (i18n/label :t/set-dapp-access-permissions)
:on-press #(re-frame/dispatch [:navigate-to :dapps-permissions])
:accessibility-label :dapps-permissions-button
:chevron true}]
[list.item/list-item
{:size :small
:title (if platform/android?
(i18n/label :t/hide-content-when-switching-apps)
(i18n/label :t/hide-content-when-switching-apps-ios))
:container-margin-bottom 8
:active preview-privacy?
:accessory :switch
:on-press #(re-frame/dispatch
[:profile.settings/change-preview-privacy
((complement boolean) preview-privacy?)])}]
(when config/collectibles-enabled?
[list.item/list-item
{:size :small
:title (i18n/label :t/display-collectibles)
:container-margin-bottom 8
:active opensea-enabled?
:accessory :switch
:on-press #(re-frame/dispatch
[::multiaccounts.update/toggle-opensea-nfts-visiblity
(not opensea-enabled?)])}])
[list.item/list-item
{:size :small
:title (i18n/label :t/chat-link-previews)
:chevron true
:on-press #(re-frame/dispatch [:open-modal :legacy-link-previews-settings])
:accessibility-label :chat-link-previews}]
[list.item/list-item
{:size :small
:title (i18n/label :t/accept-new-chats-from)
:chevron true
:accessory :text
:accessory-text (i18n/label (if messages-from-contacts-only
:t/contacts
:t/anyone))
:on-press #(re-frame/dispatch [:navigate-to :messages-from-contacts-only])
:accessibility-label :accept-new-chats-from}]
[list.item/list-item
{:size :small
:title (i18n/label :t/reset-password)
:chevron true
:accessory :text
:on-press #(do
(re-frame/dispatch [::reset-password/clear-form-vals])
(re-frame/dispatch [:navigate-to :reset-password]))
:accessibility-label :reset-password}]
(when platform/android?
[list.item/list-item
{:size :small
:title (i18n/label :t/webview-camera-permission-requests)
:active webview-allow-permission-requests?
:accessory :switch
:subtitle (i18n/label :t/webview-camera-permission-requests-subtitle)
:subtitle-max-lines 2
:on-press #(re-frame/dispatch
[:profile.settings/profile-update
:webview-allow-permission-requests?
((complement boolean) webview-allow-permission-requests?)])}])
[separator]
[components/list-header (i18n/label :t/privacy-photos)]
[list.item/list-item
{:size :small
:title (i18n/label :t/show-profile-pictures)
:accessibility-label :show-profile-pictures
:accessory :text
:accessory-text (get titles profile-pictures-visibility)
:on-press #(re-frame/dispatch [:navigate-to :privacy-and-security-profile-pic])
:chevron true}]
[list.item/list-item
{:size :small
:title (i18n/label :t/show-profile-pictures-to)
:disabled (not has-picture)
:accessibility-label :show-profile-pictures-to
:accessory :text
:accessory-text (get titles profile-pictures-show-to)
:on-press #(re-frame/dispatch [:navigate-to
:privacy-and-security-profile-pic-show-to])
:chevron true}]
[separator]
[list.item/list-item
{:size :small
:theme :negative
:title (i18n/label :t/delete-my-profile)
:on-press #(re-frame/dispatch [:navigate-to :delete-profile])
:accessibility-label :dapps-permissions-button
:chevron true}]]]))
(defn ppst-radio-item
[id value]
[list.item/list-item
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/change-profile-pictures-show-to id])}])
(views/defview profile-pic-show-to
[]
(views/letsubs [{:keys [profile-pictures-show-to]} [:profile/profile]]
[react/view {:margin-top 8}
[ppst-radio-item constants/profile-pictures-show-to-everyone profile-pictures-show-to]
[ppst-radio-item constants/profile-pictures-show-to-contacts-only profile-pictures-show-to]
[ppst-radio-item constants/profile-pictures-show-to-none profile-pictures-show-to]
[react/view {:style {:margin-horizontal 16}}
[components/text {:color :secondary}
(i18n/label :t/privacy-show-to-warning)]]]))
(defn ppvf-radio-item
[id value]
[list.item/list-item
{:active (= value id)
:accessory :radio
:title (get titles id)
:on-press #(re-frame/dispatch [:profile.settings/profile-update :profile-pictures-visibility id])}])
(views/defview profile-pic
[]
(views/letsubs [{:keys [profile-pictures-visibility]} [:profile/profile]]
[react/view {:margin-top 8}
[ppvf-radio-item constants/profile-pictures-visibility-everyone profile-pictures-visibility]
[ppvf-radio-item constants/profile-pictures-visibility-contacts-only profile-pictures-visibility]
[ppvf-radio-item constants/profile-pictures-visibility-none profile-pictures-visibility]]))
@@ -13,6 +13,12 @@
[]
[rn/scroll-view {:flex 1}
[components/list-header "Legacy settings"]
[list.item/list-item
{:icon :main-icons/security
:title (i18n/label :t/privacy-and-security)
:accessibility-label :privacy-and-security-settings-button
:chevron true
:on-press #(re-frame/dispatch [:open-modal :legacy-privacy-and-security])}]
[list.item/list-item
{:icon :main-icons/mobile
:title (i18n/label :t/sync-settings)
@@ -8,10 +8,12 @@
[legacy.status-im.ui.screens.bug-report :as bug-report]
[legacy.status-im.ui.screens.communities.invite :as communities.invite]
[legacy.status-im.ui.screens.communities.members :as members]
[legacy.status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
[legacy.status-im.ui.screens.default-sync-period-settings.view :as default-sync-period-settings]
[legacy.status-im.ui.screens.fleet-settings.views :as fleet-settings]
[legacy.status-im.ui.screens.glossary.view :as glossary]
[legacy.status-im.ui.screens.help-center.views :as help-center]
[legacy.status-im.ui.screens.link-previews-settings.views :as link-previews-settings]
[legacy.status-im.ui.screens.log-level-settings.views :as log-level-settings]
[legacy.status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings]
[legacy.status-im.ui.screens.notifications-settings.views :as notifications-settings]
@@ -19,6 +21,10 @@
[legacy.status-im.ui.screens.offline-messaging-settings.views :as offline-messaging-settings]
[legacy.status-im.ui.screens.pairing.views :as pairing]
[legacy.status-im.ui.screens.peers-stats :as peers-stats]
[legacy.status-im.ui.screens.privacy-and-security-settings.delete-profile :as delete-profile]
[legacy.status-im.ui.screens.privacy-and-security-settings.messages-from-contacts-only :as
messages-from-contacts-only]
[legacy.status-im.ui.screens.privacy-and-security-settings.views :as privacy-and-security]
[legacy.status-im.ui.screens.profile.seed.views :as profile.seed]
[legacy.status-im.ui.screens.profile.user.views :as profile.user]
[legacy.status-im.ui.screens.progress.views :as progress]
@@ -88,6 +94,17 @@
:insets {:top? platform/android?}}
:component profile.user/legacy-settings}
;; PRIVACY AND SECURITY
{:name :legacy-privacy-and-security
:options {:topBar {:visible false}
:insets {:top? platform/android?}}
:component privacy-and-security/privacy-and-security}
{:name :legacy-link-previews-settings
:options {:topBar {:visible false}
:insets {:top? platform/android?}}
:component link-previews-settings/link-previews-settings}
;; SYNC
{:name :legacy-sync-settings
:options {:topBar {:visible false}
@@ -133,6 +150,25 @@
{:name :edit-mailserver
:options {:insets {:top? true}}
:component edit-mailserver/edit-mailserver}
{:name :dapps-permissions
:options {:topBar (topbar-options :t/dapps-permissions)
:insets {:top? true}}
:component dapps-permissions/dapps-permissions}
{:name :messages-from-contacts-only
:options {:topBar (topbar-options :t/accept-new-chats-from)
:insets {:top? true}}
:component messages-from-contacts-only/messages-from-contacts-only-view}
{:name :privacy-and-security-profile-pic-show-to
:options {:topbar (topbar-options :t/show-profile-pictures-to)
:insets {:top? true}}
:component privacy-and-security/profile-pic-show-to}
{:name :privacy-and-security-profile-pic
:options {:topBar (topbar-options :t/show-profile-pictures)
:insets {:top? true}}
:component privacy-and-security/profile-pic}
{:name :manage-dapps-permissions
:options {:insets {:top? true}}
:component dapps-permissions/manage}
{:name :rpc-usage-info
:options {:topBar (topbar-options :t/rpc-usage-info)
:insets {:top? true}}
@@ -160,6 +196,9 @@
:options {:topBar (topbar-options :t/reset-password)
:insets {:top? true}}
:component reset-password/reset-password}
{:name :delete-profile
:insets {:bottom? true}
:component delete-profile/delete-profile}
{:name :default-sync-period-settings
:options {:topBar (topbar-options :t/default-sync-period)
:insets {:top? true}}
@@ -128,6 +128,7 @@
:current-chat-id
:network
:network-status
:peers-count
:peers-summary
:sync-state
:view-id
+130
View File
@@ -0,0 +1,130 @@
(ns legacy.status-im.utils.test
(:require
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]))
(def native-status (js/require "../../modules/react-native-status/nodejs/bindings"))
(def fs (js/require "fs"))
(def path (js/require "path"))
(def os (js/require "os"))
(def tmpdir (.tmpdir os))
(def test-dir-prefix (.join path tmpdir "status-mobile-tests"))
(def test-dir (.mkdtempSync fs test-dir-prefix))
(def initialized? (atom false))
(defn signal-received-callback
[a]
(re-frame/dispatch [:signals/signal-received a]))
;; We poll for signals, could not get callback working
(defn init!
[]
(when-not @initialized?
(.setSignalEventCallback native-status)
(reset! initialized? true)
(js/setInterval (fn []
(.pollSignal native-status signal-received-callback)
100))))
(def ui-helper
(clj->js
{:clearCookies identity
:clearStorageAPIs identity}))
(def encryption-utils
(clj->js
{:sha3
(fn [s] (.sha3 native-status s))
:setBlankPreviewFlag
identity
:encodeTransfer
(fn [to-norm amount-hex]
(.encodeTransfer native-status to-norm amount-hex))
:hexToNumber
(fn [hex] (.hexToNumber native-status hex))
:decodeParameters
(fn [decode-param-json]
(.decodeParameters native-status decode-param-json))
:numberToHex
(fn [num-str] (.numberToHex native-status num-str))
:initKeystore
(fn [key-uid callback]
(callback (.initKeystore native-status
(str test-dir "/keystore/" key-uid))))
:multiformatDeserializePublicKey
(fn [public-key deserialization-key callback]
(callback (.multiformatDeserializePublicKey
native-status
public-key
deserialization-key)))}))
(def account-manager
(clj->js
{:openAccounts
(fn [callback]
(callback (.openAccounts native-status test-dir)))
:createAccountAndLogin
(fn [request] (.createAccountAndLogin native-status request))
:logout
(fn [] (.logout native-status))
:multiAccountImportMnemonic
(fn [json callback]
(callback (.multiAccountImportMnemonic native-status json)))
:multiAccountLoadAccount
(fn [json callback]
(callback (.multiAccountLoadAccount native-status json)))
:multiAccountDeriveAddresses
(fn [json callback]
(callback (.multiAccountDeriveAddresses native-status json)))
:multiAccountGenerateAndDeriveAddresses
(fn [json callback]
(callback (.multiAccountGenerateAndDeriveAddresses native-status json)))
:multiAccountStoreDerived
(fn [json callback]
(callback (.multiAccountStoreDerivedAccounts native-status json)))}))
(def utils
(clj->js
{:backupDisabledDataDir
(fn [] (str test-dir "/backup"))
:keystoreDir (fn [] "")
:toChecksumAddress
(fn [address] (.toChecksumAddress native-status address))
:checkAddressChecksum
(fn [address] (.checkAddressChecksum native-status address))
:validateMnemonic
(fn [json callback] (callback (.validateMnemonic native-status json)))
:isAddress
(fn [address] (.isAddress native-status address))}))
(def log-manager
(clj->js
{:logFileDirectory
(fn [] (str test-dir "/log"))
:initLogging
(fn [enabled mobile-system log-level callback]
(callback (.initLogging native-status
(types/clj->json {:Enabled enabled
:MobileSystem mobile-system
:Level log-level
:File (str test-dir "/geth.log")}))))}))
(def network
(clj->js
{:callPrivateRPC
(fn [payload callback]
(callback (.callPrivateRPC native-status payload)))}))
(def status
(clj->js
{:getNodeConfig
(fn [] (types/clj->json {:WakuV2Config ""}))
:fleets
(fn [] (.fleets native-status))
:startLocalNotifications
identity}))
@@ -130,7 +130,7 @@
status-type]}]
(and
(= status-type constants/visibility-status-inactive)
(pos? (:peer-stats/count db)))
(> (:peers-count db) 0))
;; Disable broadcasting further updates
(conj {:ms 1000
:dispatch
+5 -21
View File
@@ -72,12 +72,10 @@
(log/debug "[native-module] init-keystore" key-uid)
(.initKeystore ^js (encryption) key-uid callback))
(defn initialize-application
[request callback]
(log/debug "[native-module] initialize-application")
(.initializeApplication ^js (account-manager)
(types/clj->json request)
#(callback (types/json->clj %))))
(defn open-accounts
[callback]
(log/debug "[native-module] open-accounts")
(.openAccounts ^js (account-manager) #(callback (types/json->clj %))))
(defn prepare-dir-and-update-config
[key-uid config callback]
@@ -515,14 +513,6 @@
(let [result (.checkAddressChecksum ^js (utils) address)]
(types/json->clj result)))
(defn toggle-centralized-metrics
[enabled callback]
(.toggleCentralizedMetrics ^js (status) (types/clj->json {:enabled enabled}) callback))
(defn add-centralized-metric
[metric]
(.addCentralizedMetric ^js (status) (types/clj->json metric) #(log/debug "pushed metric" % metric)))
(defn address?
[address]
(log/debug "[native-module] address?")
@@ -543,13 +533,6 @@
(log/debug "[native-module] validate-mnemonic")
(.validateMnemonic ^js (utils) mnemonic callback)))
(defn validate-connection-string
[connection-string]
(log/debug "[native-module] validate-connection-string")
(->> connection-string
(.validateConnectionString ^js (utils))
types/json->clj))
(defn delete-multiaccount
"Delete multiaccount from database, deletes multiaccount's database and
key files."
@@ -660,6 +643,7 @@
(native-utils/promisify-native-module-call create-account-from-private-key private-key))
([private-key callback]
(log/debug "[native-module] create-account-from-private-key")
(.createAccountFromPrivateKey ^js (account-manager)
(types/clj->json {:privateKey private-key})
callback)))
@@ -2,7 +2,7 @@
(:require
[quo.components.buttons.button.view :as button]
[quo.components.buttons.predictive-keyboard.style :as style]
[quo.components.info.info-message.view :as info-message]
[quo.components.info.info-message :as info-message]
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.core :as rn]
@@ -57,17 +57,17 @@
:key-fn str}]
:error
[info-message/view
{:icon :i/info
:size :default
:status :error}
[info-message/info-message
{:icon :i/info
:size :default
:type :error}
text]
:info
[info-message/view
(merge {:icon :i/info
:size :default
:status (if (= type :error) :error :default)}
[info-message/info-message
(merge {:icon :i/info
:size :default
:type (if (= type :error) :error :default)}
(when blur?
{:text-color colors/white-opa-70
:icon-color colors/white-opa-40}))
@@ -26,8 +26,7 @@
(reanimated/set-shared-value x-pos clamped-x)
(when (and reached-end? (not sliding-complete?))
(set-sliding-complete true)
(when on-complete
(on-complete reset-fn))))))
(when on-complete (on-complete reset-fn))))))
(gesture/on-end (fn [event]
(let [x-translation (oops/oget event "translationX")
reached-end? (>= x-translation track-width)]
@@ -55,10 +54,9 @@
on-track-layout (rn/use-callback
#(set-track-width (oops/oget % "nativeEvent.layout.width")))
reset-fn (rn/use-callback
(fn [keep-at-end-after-slide?]
(fn []
(set-sliding-complete false)
(when-not keep-at-end-after-slide?
(animations/reset-track-position x-pos))))
(animations/reset-track-position x-pos)))
dimensions (rn/use-callback
(partial utils/get-dimensions
(or track-width constants/default-width)
+48
View File
@@ -0,0 +1,48 @@
(ns quo.components.info.info-message
(:require
[quo.components.icon :as quo.icons]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]))
(defn get-color
[k theme]
(case k
:success (colors/resolve-color :success theme)
:error (colors/resolve-color :danger theme)
:warning (colors/resolve-color :warning theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)))
(defn info-message
"[info-message opts \"message\"]
opts
{:type :default/:success/:error
:size :default/:tiny
:icon :i/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 accessibility-label
container-style]} message]
(let [theme (quo.theme/use-theme)
weight (if (= size :default) :regular :medium)
icon-size (if (= size :default) 16 12)
size (if (= size :default) :paragraph-2 :label)
text-color (or text-color (get-color type theme))
icon-color (or icon-color text-color)]
[rn/view
{:style (merge {:flex-direction :row
:align-items :center}
style
container-style)}
[quo.icons/icon icon
{:color icon-color
:no-color no-icon-color?
:size icon-size}]
[text/text
{:accessibility-label accessibility-label
:size size
:weight weight
:style {:color text-color
:margin-horizontal 4}} message]]))
@@ -1,32 +0,0 @@
(ns quo.components.info.info-message.component-spec
(:require
[quo.components.info.info-message.view :as info-message]
[test-helpers.component :as h]))
(h/describe "Info: Info Message"
(h/test "basic render"
(h/render-with-theme-provider
[info-message/view
{:status :default
:size :default
:accessibility-label :info-message
:icon :i/placeholder} "Message"])
(h/is-truthy (h/get-by-label-text :info-message)))
(h/test "render with correct message"
(h/render-with-theme-provider
[info-message/view
{:status :default
:size :default
:accessibility-label :info-message
:icon :i/placeholder} "Message"])
(h/is-truthy (h/get-by-text "Message")))
(h/test "render icon"
(h/render-with-theme-provider
[info-message/view
{:status :default
:size :default
:accessibility-label :info-message
:icon :i/placeholder} "Message"])
(h/is-truthy (h/get-by-label-text :icon))))
@@ -1,6 +0,0 @@
(ns quo.components.info.info-message.style)
(def container
{:flex-direction :row
:gap 4
:align-items :center})
@@ -1,53 +0,0 @@
(ns quo.components.info.info-message.view
(:require [quo.components.icon :as icons]
[quo.components.info.info-message.style :as style]
[quo.components.markdown.text :as text]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[schema.core :as schema]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:status {:optional true} [:maybe [:enum :default :success :error :warning]]]
[:size {:optional true} [:maybe [:enum :default :tiny]]]
[:blur? {:optional true} [:maybe :boolean]]
[:icon :keyword]
[:color {:optional true} [:maybe :string]]
[:text-color {:optional true} [:maybe :string]]
[:icon-color {:optional true} [:maybe :string]]
[:no-icon-color? {:optional true} [:maybe :boolean]]
[:accessibility-label {:optional true} [:maybe :keyword]]
[:container-style {:optional true} [:maybe :map]]]]
[:message :string]]
:any])
(defn- get-color
[status theme blur?]
(case status
:success (if blur? colors/success-60 (colors/resolve-color :success theme))
:error (if blur? colors/danger-60 (colors/resolve-color :danger theme))
:warning (if blur? colors/warning-60 (colors/resolve-color :warning theme))
(if blur? colors/white-opa-40 (colors/theme-colors colors/neutral-50 colors/neutral-40 theme))))
(defn view-internal
[{:keys [status size blur? icon color icon-color text-color no-icon-color? container-style
accessibility-label]} message]
(let [theme (quo.theme/use-theme)
default-color (get-color status theme blur?)
text-color (or text-color color default-color)
icon-color (or icon-color color default-color)]
[rn/view {:style (merge style/container container-style)}
[icons/icon icon
{:size (if (= size :tiny) 12 16)
:color icon-color
:no-color? no-icon-color?}]
[text/text
{:size (if (= size :tiny) :label :paragraph-2)
:accessibility-label accessibility-label
:style {:color text-color}} message]]))
(def view (schema/instrument #'view-internal ?schema))
@@ -44,14 +44,13 @@
[:label :string]
[:fiat-value :string]
[:token-value :string]
[:container-style {:optional true} [:maybe :map]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:state {:optional true} [:enum :pressed :active :disabled :default]]
[:on-press {:optional true} [:maybe fn?]]]]]
:any])
(defn- view-internal
[{:keys [on-press container-style state customization-color]
[{:keys [on-press state customization-color]
:as props
:or {customization-color :blue}}]
(let [theme (quo.theme/use-theme)
@@ -60,8 +59,7 @@
on-press-out (rn/use-callback #(set-pressed false))
internal-state (if pressed? :pressed state)]
[rn/pressable
{:style (merge (style/container internal-state customization-color theme)
container-style)
{:style (style/container internal-state customization-color theme)
:on-press-in (when-not (= state :disabled) on-press-in)
:on-press-out (when-not (= state :disabled) on-press-out)
:on-press (when-not (= state :disabled) on-press)
+3 -3
View File
@@ -8,7 +8,7 @@
[quo.foundations.colors :as colors]
[react-native.core :as rn]))
(def container
(def container-style
{:margin-horizontal 8
:padding-vertical 8
:padding-horizontal 12
@@ -43,9 +43,9 @@
(defn user
[{:keys [short-chat-key primary-name secondary-name photo-path online? contact? verified?
untrustworthy? on-press on-long-press accessory customization-color theme
allow-multiple-presses? disabled? container-style]}]
allow-multiple-presses? disabled?]}]
[rn/touchable-highlight
{:style (merge container container-style)
{:style container-style
:underlay-color (colors/resolve-color customization-color theme 5)
:allow-multiple-presses? allow-multiple-presses?
:accessibility-label :user-list
@@ -11,7 +11,7 @@
(defn fallback
[{:keys [theme opacity]}]
[{:opacity opacity}
{:opacity 1
{:opacity default-opacity-for-image
:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
@@ -60,13 +60,8 @@
:padding-right 0
:padding-top 4})
(defn card-detail-text
[empty-name? theme]
{:flex 1
:margin-right 8
:color (if empty-name?
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
(colors/theme-colors colors/neutral-100 colors/white theme))})
(def card-detail-text
{:flex 1})
(defn card-loader
[opacity]
@@ -120,7 +115,6 @@
[{:opacity opacity}
{:flex 1
:flex-direction :row
:column-gap 8
:opacity default-opacity-for-image}])
(defn supported-file
@@ -1,6 +1,5 @@
(ns quo.components.profile.collectible-list-item.view
(:require
[clojure.string :as string]
[quo.components.avatars.collection-avatar.view :as collection-avatar]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
@@ -22,7 +21,7 @@
(def cached-load-time 200)
(def error-wait-time 800)
(defn animate-loading-image
(defn on-load-end
[{:keys [load-time set-state loader-opacity image-opacity]}]
(reanimated/animate loader-opacity 0 timing-options-out)
(reanimated/animate image-opacity 1 timing-options-in)
@@ -35,12 +34,6 @@
(set-state (fn [prev-state]
(assoc prev-state :image-loaded? true)))))
(defn on-load
[evt set-state]
(let [source (.. evt -nativeEvent -source)
aspect-ratio (/ (.-width source) (.-height source))]
(set-state (fn [prev-state] (assoc prev-state :image-aspect-ratio aspect-ratio)))))
(defn on-load-error
[set-state]
(js/setTimeout (fn []
@@ -61,12 +54,12 @@
(assoc prev-state :avatar-loaded? true)))))
(defn- fallback-view
[{:keys [label theme image-opacity on-load-end]}]
(rn/use-mount on-load-end)
[reanimated/view {:style (style/fallback {:opacity image-opacity :theme theme})}
[{:keys [label theme image-opacity]}]
[reanimated/view
{:style (style/fallback {:opacity image-opacity
:theme theme})}
[rn/view
[icon/icon :i/sad
{:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[rn/view {:style {:height 4}}]
[text/text
{:size :paragraph-2
@@ -94,43 +87,31 @@
[{:keys [community? avatar-image-src collectible-name theme state set-state]}]
(let [loader-opacity (reanimated/use-shared-value 1)
avatar-opacity (reanimated/use-shared-value 0)
[load-time set-load-time] (rn/use-state (datetime/now))
set-avatar-loaded (fn []
(on-load-avatar {:set-state set-state
:load-time load-time
:loader-opacity loader-opacity
:avatar-opacity avatar-opacity}))
empty-name? (string/blank? collectible-name)]
(rn/use-mount (fn []
(when (string/blank? avatar-image-src)
(set-avatar-loaded))))
[load-time set-load-time] (rn/use-state (datetime/now))]
[rn/view {:style style/card-details-container}
[reanimated/view {:style (style/avatar-container avatar-opacity)}
(cond
(string/blank? avatar-image-src)
[loading-square theme]
community?
[preview-list/view {:type :communities :size :size-20}
(if community?
[preview-list/view
{:type :communities
:size :size-20}
[avatar-image-src]]
:else
[collection-avatar/view
{:size :size-20
:on-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end set-avatar-loaded
:on-load-end #(on-load-avatar {:set-state set-state
:load-time load-time
:loader-opacity loader-opacity
:avatar-opacity avatar-opacity})
:image avatar-image-src}])
[rn/view {:style {:width 8}}]
[text/text
{:size :paragraph-1
:weight :semi-bold
:ellipsize-mode :tail
:number-of-lines 1
:style (style/card-detail-text empty-name? theme)}
(if empty-name?
(i18n/label :t/unknown)
collectible-name)]]
(when-not (:avatar-loaded? state)
:style style/card-detail-text}
collectible-name]]
(when (not (:avatar-loaded? state))
[reanimated/view {:style (style/card-loader loader-opacity)}
[loading-square theme]
[loading-message theme]])]))
@@ -141,44 +122,39 @@
(let [theme (quo.theme/use-theme)
loader-opacity (reanimated/use-shared-value (if supported-file? 1 0))
image-opacity (reanimated/use-shared-value (if supported-file? 0 1))
[load-time set-load-time] (rn/use-state (datetime/now))
set-image-loaded (fn []
(animate-loading-image {:load-time load-time
:set-state set-state
:loader-opacity loader-opacity
:image-opacity image-opacity}))]
[load-time set-load-time] (rn/use-state (datetime/now))]
[rn/view {:style (style/card-view-container theme)}
[rn/view {:style {:aspect-ratio 1}}
(cond
(:image-error? state) [fallback-view
{:image-opacity image-opacity
:on-load-end set-image-loaded
:theme theme
:label (i18n/label :t/cant-fetch-info)}]
(not supported-file?) [fallback-view
{:image-opacity image-opacity
:on-load-end set-image-loaded
:theme theme
:label (i18n/label :t/unsupported-file)}]
(not (:image-loaded? state)) [loading-image
{:loader-opacity loader-opacity
:theme theme
:gradient-color-index gradient-color-index}])
(:image-error? state)
[fallback-view
{:image-opacity image-opacity
:theme theme
:label (i18n/label :t/cant-fetch-info)}]
(not supported-file?)
[fallback-view
{:image-opacity image-opacity
:theme theme
:label (i18n/label :t/unsupported-file)}]
(not (:image-loaded? state))
[loading-image
{:loader-opacity loader-opacity
:theme theme
:gradient-color-index gradient-color-index}])
(when supported-file?
[reanimated/view {:style (style/supported-file image-opacity)}
[rn/image
{:style style/image
:on-load #(on-load % set-state)
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end set-image-loaded
:on-load-end #(on-load-end {:load-time load-time
:set-state set-state
:loader-opacity loader-opacity
:image-opacity image-opacity})
:on-error #(on-load-error set-state)
:source image-src}]])]
(when (and (or (:image-loaded? state)
(not supported-file?))
(not (:image-error? state))
counter)
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
@@ -221,12 +197,11 @@
[reanimated/view {:style (style/supported-file image-opacity)}
[rn/image
{:style style/image
:on-load #(on-load % set-state)
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end #(animate-loading-image {:load-time load-time
:set-state set-state
:loader-opacity loader-opacity
:image-opacity image-opacity})
:on-load-end #(on-load-end {:load-time load-time
:set-state set-state
:loader-opacity loader-opacity
:image-opacity image-opacity})
:on-error #(on-load-error set-state)
:source image-src}]])
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
@@ -244,13 +219,12 @@
(defn- view-internal
[{:keys [container-style type on-press on-long-press supported-file?]
:as props}]
(let [[state set-state] (rn/use-state {:image-loaded? false
:image-aspect-ratio nil
:image-error? false
:avatar-loaded? false})
(let [[state set-state] (rn/use-state {:image-loaded? false
:image-error? false
:avatar-loaded? false})
collectible-ready? (or (:image-loaded? state) (not supported-file?))]
[rn/pressable
{:on-press (when collectible-ready? #(on-press (:image-aspect-ratio state)))
{:on-press (when collectible-ready? on-press)
:on-long-press (when collectible-ready? on-long-press)
:accessibility-label :collectible-list-item
:style container-style}
@@ -1,13 +1,10 @@
(ns quo.components.profile.expanded-collectible.style
(:require [quo.foundations.colors :as colors]))
(defn container
[aspect-ratio]
(cond-> {:align-items :center
:justify-content :center
:border-radius 16}
aspect-ratio (assoc :width "100%"
:aspect-ratio aspect-ratio)))
(def container
{:align-items :center
:justify-content :center
:border-radius 16})
(defn image
[square? aspect-ratio theme]
@@ -28,43 +25,18 @@
:border-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)})
(defn fallback
([theme]
(fallback theme 1))
([theme aspect-ratio]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius 16
:width "100%"
:aspect-ratio aspect-ratio
:align-items :center
:justify-content :center}))
[{:keys [theme]}]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius 16
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
(def counter
{:position :absolute
:top 12
:right 12})
(defn loading-image-with-opacity
[opacity]
[{:align-items :center
:aspect-ratio 1
:border-radius 16
:justify-content :center
:opacity opacity
:position :absolute
:width "100%"
:z-index 1}])
(defn gradient-view
[aspect-ratio]
{:border-radius 16
:width "100%"
:aspect-ratio aspect-ratio
:align-items :center
:justify-content :center})
(defn supported-file
[opacity]
{:opacity opacity})
@@ -1,39 +1,17 @@
(ns quo.components.profile.expanded-collectible.view
(:require
[clojure.string :as string]
[promesa.core :as promesa]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
[quo.components.markdown.text :as text]
[quo.components.profile.expanded-collectible.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.gradients :as gradients]
[quo.theme]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[schema.core :as schema]
[utils.i18n :as i18n]))
(def loader-out 650)
(def image-in 1000)
(def error-wait-time 800)
(defn on-load-end
[{:keys [loader-opacity image-opacity]}]
(reanimated/animate loader-opacity 0 loader-out)
(reanimated/animate image-opacity 1 image-in))
(defn on-load-error
[set-error]
(js/setTimeout set-error error-wait-time))
(defn- loading-image
[{:keys [theme gradient-color-index loader-opacity aspect-ratio]}]
[reanimated/view {:style (style/loading-image-with-opacity loader-opacity)}
[gradients/view
{:theme theme
:container-style (style/gradient-view aspect-ratio)
:color-index gradient-color-index}]])
(defn- counter-view
[counter]
[collectible-counter/view
@@ -43,7 +21,7 @@
(defn- fallback-view
[{:keys [label theme counter on-mount]}]
(rn/use-mount on-mount)
[rn/view {:style (style/fallback theme)}
[rn/view {:style (style/fallback {:theme theme})}
[counter-view counter]
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
@@ -53,71 +31,56 @@
:style {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
label]])
(defn- collectible-image
[{:keys [aspect-ratio theme gradient-color-index supported-file? set-error native-ID
square? image-src on-collectible-load counter]}]
(let [loader-opacity (reanimated/use-shared-value (if supported-file? 1 0))
image-opacity (reanimated/use-shared-value (if supported-file? 0 1))]
[:<>
[loading-image
{:aspect-ratio aspect-ratio
:loader-opacity loader-opacity
:theme theme
:gradient-color-index gradient-color-index}]
[reanimated/view {:style (style/supported-file image-opacity)}
[rn/image
{:style (style/image square? aspect-ratio theme)
:source image-src
:native-ID native-ID
:on-load-end (fn []
(on-load-end {:loader-opacity loader-opacity
:image-opacity image-opacity}))
:on-error #(on-load-error set-error)
:on-load on-collectible-load}]
(when counter
[counter-view counter])
[rn/view {:style (style/collectible-border theme)}]]]))
(defn view-internal
[{:keys [container-style square? on-press counter image-src native-ID supported-file?
on-collectible-load aspect-ratio gradient-color-index]
:or {gradient-color-index :gradient-1
on-collectible-load (fn [])}}]
(let [theme (quo.theme/use-theme)
[error? set-error] (rn/use-state (or (nil? image-src)
(string/blank? image-src)))]
on-collectible-load]}]
(let [theme (quo.theme/use-theme)
[image-size set-image-size] (rn/use-state {})
[image-error? set-image-error] (rn/use-state (or (nil? image-src)
(string/blank? image-src)))]
(rn/use-effect
(fn []
(promesa/let [[image-width image-height] (rn/image-get-size image-src)]
(set-image-size {:width image-width
:height image-height
:aspect-ratio (/ image-width image-height)})))
[image-src])
[rn/pressable
{:style (merge container-style (style/container aspect-ratio))
{:on-press (when (and (not image-error?) supported-file?) on-press)
:accessibility-label :expanded-collectible
:on-press (when (and (not error?) supported-file?)
on-press)}
(if (or (not supported-file?) error?)
:style (merge container-style style/container)}
(cond
(not supported-file?)
[fallback-view
{:label (i18n/label (if-not supported-file?
:t/unsupported-file
:t/cant-fetch-info))
{:label (i18n/label :t/unsupported-file)
:counter counter
:theme theme
:on-mount on-collectible-load}]
[collectible-image
{:aspect-ratio aspect-ratio
:theme theme
:supported-file? supported-file?
:set-error set-error
:native-ID native-ID
:square? square?
:image-src image-src
:on-collectible-load on-collectible-load
:counter counter
:gradient-color-index gradient-color-index}])]))
image-error?
[fallback-view
{:label (i18n/label :t/cant-fetch-info)
:counter counter
:theme theme
:on-mount on-collectible-load}]
:else
[rn/view
[rn/image
{:style (style/image square? (:aspect-ratio image-size) theme)
:source image-src
:native-ID native-ID
:on-error #(set-image-error true)
:on-load on-collectible-load}]
(when counter
[counter-view counter])
[rn/view {:style (style/collectible-border theme)}]])]))
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:aspect-ratio {:optional true} [:maybe number?]]
[:image-src {:optional true} [:maybe string?]]
[:supported-file? {:optional true} [:maybe boolean?]]
[:container-style {:optional true} [:maybe :map]]
@@ -125,8 +88,7 @@
[:square? {:optional true} [:maybe boolean?]]
[:counter {:optional true} [:maybe string?]]
[:on-press {:optional true} [:maybe fn?]]
[:on-collectible-load {:optional true} [:maybe fn?]]
[:gradient-color-index {:optional true} [:maybe keyword?]]]]]
[:on-collectible-load {:optional true} [:maybe fn?]]]]]
:any])
(def view (schema/instrument #'view-internal ?schema))
@@ -12,8 +12,7 @@
[{:keys [checked? blur? accessibility-label container-style on-change icon customization-color]} label]
(let [theme (quo.theme/use-theme)]
[rn/touchable-without-feedback
{:on-press (when on-change
#(on-change (not checked?)))
{:on-press on-change
:accessibility-label :disclaimer-touchable-opacity}
[rn/view {:style (merge container-style (style/container blur? theme))}
[selectors/view
@@ -6,14 +6,8 @@
[{:keys [size card? blur? actionable? theme]}]
{:flex-direction :row
:justify-content :space-between
:padding-vertical (case size
:default 8
:large 12
nil)
:padding-horizontal (case size
:default 12
:large 16
nil)
:padding-vertical (when (= size :default) 8)
:padding-horizontal (when (= size :default) 12)
:border-radius 16
:border-width (when (and card? (not= size :small)) 1)
:background-color (if blur?
@@ -30,27 +24,15 @@
(defn loading-container
[size blur? theme]
{:width (case size
:large 132
:small 72
132)
:height (case size
:large 16
:small 10
16)
{:width (if (= size :default) 132 72)
:height (if (= size :default) 16 10)
:background-color (if blur?
colors/white-opa-5
(colors/theme-colors colors/neutral-5
colors/neutral-90
theme))
:border-radius (case size
:large 6
:small 3
6)
:margin-vertical (case size
:large 4
:small 3
4)})
:border-radius (if (= size :default) 6 3)
:margin-vertical (if (= size :default) 4 3)})
(def subtitle-container
{:flex-direction :row
@@ -51,7 +51,7 @@
(defn color
[blur? theme]
{:color (if blur?
colors/white-opa-40
colors/white-opa-70
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))})
(defn label-dot
@@ -6,7 +6,7 @@
[:type {:optional true}
[:maybe
[:enum :default :multiuser :group :channel :community :token :network :multinetwork :account
:collectible :address :icon :audio :wallet-user :dapp]]]
:collectible :address :icon :audio :wallet-user]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:container-style {:optional true} [:maybe :map]]
[:blur? {:optional true} [:maybe :boolean]]
+83 -90
View File
@@ -17,18 +17,16 @@
[schema.core :as schema]))
(defn- tag-skeleton
[{:keys [size text theme]
:or {size 24
theme (quo.theme/use-theme)}}
logo-component]
[rn/view {:style (style/tag-container size)}
logo-component
[rn/view {:style (style/tag-spacing size)}
[text/text
{:style (style/text theme)
:weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)}
text]]])
[{:keys [size text] :or {size 24}} logo-component]
(let [theme (quo.theme/use-theme)]
[rn/view {:style (style/tag-container size)}
logo-component
[rn/view {:style (style/tag-spacing size)}
[text/text
{:style (style/text theme)
:weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)}
text]]]))
(defn- communities-tag
[{:keys [size community-logo community-name blur? channel? channel-name]}]
@@ -83,100 +81,95 @@
context]]]))
(defn- view-internal
[{:keys [type theme size state blur? customization-color profile-picture full-name users
[{:keys [type size state blur? customization-color profile-picture full-name users
group-name amount token network-logo network-name networks
account-name emoji collectible collectible-name collectible-number
dapp-name dapp-logo duration container-style]
account-name emoji collectible collectible-name collectible-number duration container-style]
:or {customization-color :blue
type :default
state :default
theme (quo.theme/use-theme)}
state :default}
:as props}]
[rn/view {:style (merge {:align-items :flex-start} container-style)}
[rn/view
{:style (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})
:accessibility-label :context-tag}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false
:ring? false
:customization-color customization-color}]]
(let [theme (quo.theme/use-theme)]
[rn/view {:style (merge {:align-items :flex-start} container-style)}
[rn/view
{:style (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})
:accessibility-label :context-tag}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false
:ring? false
:customization-color customization-color}]]
:multiuser
[preview-list/view {:type :user :size :size-20}
users]
:multiuser
[preview-list/view {:type :user :size :size-20}
users]
:multinetwork
[preview-list/view {:type :network :size :size-20}
networks]
:multinetwork
[preview-list/view {:type :network :size :size-20}
networks]
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view
{:style (style/token-logo size)
:token token
:size (if (= size 24) :size-20 :size-28)}]]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view
{:style (style/token-logo size)
:token token
:size (if (= size 24) :size-20 :size-28)}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size (if (= size 24) 20 28)}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view
{:customization-color customization-color
:emoji emoji
:size (if (= size 24) 20 28)}]]
:address
[address-tag props]
:address
[address-tag props]
:icon
[icon-tag props]
:icon
[icon-tag props]
:wallet-user
[tag-skeleton {:theme theme :size size :text full-name}
[wallet-user-avatar/wallet-user-avatar
{:full-name full-name
:size (if (= size 24) :size-20 :size-24)
:customization-color customization-color}]]
:wallet-user
[tag-skeleton {:theme theme :size size :text full-name}
[wallet-user-avatar/wallet-user-avatar
{:full-name full-name
:size (if (= size 24) :size-20 :size-24)
:customization-color customization-color}]]
:dapp
[tag-skeleton {:theme theme :size size :text dapp-name}
[rn/image {:style (style/circle-logo size) :source dapp-logo}]]
nil)]])
nil)]]))
(def view (schema/instrument #'view-internal component-schema/?schema))
+1 -1
View File
@@ -102,7 +102,7 @@
:container-style container-style
:theme theme))
:on-press #(when (= action :selector) (on-press))
:pointer-events (when (= action :selector) :box-only)}
:pointer-events :box-only}
[rn/view {:style style/header-container}
[avatar props]
[rn/view
+2 -2
View File
@@ -68,7 +68,7 @@
quo.components.graph.wallet-graph.view
quo.components.header
quo.components.icon
quo.components.info.info-message.view
quo.components.info.info-message
quo.components.info.information-box.view
quo.components.inputs.address-input.view
quo.components.inputs.input.view
@@ -301,7 +301,7 @@
(def icon quo.components.icon/icon)
;;;; Info
(def info-message quo.components.info.info-message.view/view)
(def info-message quo.components.info.info-message/info-message)
(def information-box quo.components.info.information-box.view/view)
;;;; Inputs
-1
View File
@@ -41,7 +41,6 @@
quo.components.dropdowns.network-dropdown.component-spec
quo.components.gradient.gradient-cover.component-spec
quo.components.graph.wallet-graph.component-spec
quo.components.info.info-message.component-spec
quo.components.inputs.address-input.component-spec
quo.components.inputs.input.component-spec
quo.components.inputs.locked-input.component-spec
+6 -7
View File
@@ -24,13 +24,12 @@
(get ui k))
(def dapps
{:coingecko (js/require "../resources/images/dapps/CoinGecko.png")
:1inch (js/require "../resources/images/dapps/1inch.png")
:aave (js/require "../resources/images/dapps/Aave.png")
:uniswap (js/require "../resources/images/dapps/Uniswap.png")
:zapper (js/require "../resources/images/dapps/Zapper.png")
:zerion (js/require "../resources/images/dapps/Zerion.png")
:wallet-connect (js/require "../resources/images/dapps/WalletConnect.png")})
{:coingecko (js/require "../resources/images/dapps/CoinGecko.png")
:1inch (js/require "../resources/images/dapps/1inch.png")
:aave (js/require "../resources/images/dapps/Aave.png")
:uniswap (js/require "../resources/images/dapps/Uniswap.png")
:zapper (js/require "../resources/images/dapps/Zapper.png")
:zerion (js/require "../resources/images/dapps/Zerion.png")})
(defn get-dapp
[k]
-2
View File
@@ -22,8 +22,6 @@
(clj->js {:proposal proposal
:supportedNamespaces supported-namespaces})))
;; Get an error from this list:
;; https://github.com/WalletConnect/walletconnect-monorepo/blob/c6e9529418a0c81d4efcc6ac4e61f242a50b56c5/packages/utils/src/errors.ts
(defn get-sdk-error
[error-key]
(getSdkError error-key))
+3 -4
View File
@@ -11,10 +11,9 @@
(defn get-label-by-type
[biometric-type]
(condp = biometric-type
constants/biometrics-type-android (i18n/label :t/biometric-fingerprint)
constants/biometrics-type-face-id (i18n/label :t/biometric-faceid)
constants/biometrics-type-touch-id (i18n/label :t/biometric-touchid)
(i18n/label :t/biometric)))
constants/biometrics-type-android (i18n/label :t/biometric-fingerprint)
constants/biometrics-type-face-id (i18n/label :t/biometric-faceid)
(i18n/label :t/biometric-touchid)))
(defn get-icon-by-type
[biometric-type]
@@ -1,24 +0,0 @@
(ns status-im.common.check-before-syncing.style)
(def buttons-container
{:flex-direction :row
:justify-content :space-between
:gap 12
:padding-vertical 12})
(def button {:flex 1})
(def checkbox
{:margin-top 16
:flex-direction :row
:align-items :center})
(def checkbox-text {:margin-left 10})
(def checkboxes-container {:margin-bottom 10 :padding-right 10})
(def header {:margin-bottom 8})
(def description {:margin-right -33})
(def view-container {:padding-horizontal 33})
@@ -1,74 +0,0 @@
(ns status-im.common.check-before-syncing.view
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.common.check-before-syncing.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def checks
[(i18n/label :t/check-before-syncing-doc-checkbox-1)
(i18n/label :t/check-before-syncing-doc-checkbox-2)
(i18n/label :t/check-before-syncing-doc-checkbox-3)])
(defn- checkbox
[on-change customization-color description]
[rn/view {:style style/checkbox}
[quo/selectors
{:type :checkbox
:blur? true
:customization-color customization-color
:on-change on-change}]
[quo/text {:style style/checkbox-text} description]])
(defn- compute-new-checked-count
[set-checked-count checked?]
(if checked?
(set-checked-count inc)
(set-checked-count dec)))
(defn- hide-bottom-sheet
[]
(rf/dispatch [:hide-bottom-sheet]))
(defn view
[{:keys [on-submit customization-color]}]
(let [[checked-count set-checked-count] (rn/use-state 0)
on-change (partial compute-new-checked-count set-checked-count)
render-checkbox (rn/use-callback
(partial checkbox on-change customization-color)
[customization-color])
on-cancel hide-bottom-sheet
on-continue (rn/use-callback
(fn []
(hide-bottom-sheet)
(on-submit))
[on-submit])]
[rn/view
{:style style/view-container
:accessibility-label :check-before-syncing-bottom-sheet}
[quo/text
{:weight :semi-bold
:size :heading-2
:style style/header} (i18n/label :t/check-before-syncing)]
[quo/text {:style style/description} (i18n/label :t/check-before-syncing-doc-description)]
(into
[rn/view {:style style/checkboxes-container}]
(mapv render-checkbox checks))
[rn/view {:style style/buttons-container}
[quo/button
{:type :grey
:container-style style/button
:accessibility-label :cancel-button
:on-press on-cancel}
(i18n/label :t/cancel)]
[quo/button
{:container-style style/button
:disabled? (not= checked-count (count checks))
:customization-color (or customization-color :blue)
:accessibility-label :continue-button
:on-press on-continue}
(i18n/label :t/continue)]]]))
@@ -6,8 +6,7 @@
(defn contact-list-item
[{:keys [on-press on-long-press accessory allow-multiple-presses? disabled?]}
{:keys [primary-name secondary-name public-key compressed-key ens-verified added?
container-style]}
{:keys [primary-name secondary-name public-key compressed-key ens-verified added?]}
theme]
(let [photo-path (rf/sub [:chats/photo-path public-key])
online? (rf/sub [:visibility-status-updates/online? public-key])
@@ -26,5 +25,4 @@
:on-press on-press
:on-long-press on-long-press
:accessory accessory
:container-style container-style
:disabled? disabled?}]))
@@ -1,7 +1,6 @@
(ns status-im.common.floating-button-page.floating-container.view
(:require
[quo.core :as quo]
[quo.foundations.colors :as colors]
[quo.theme :as quo.theme]
[react-native.core :as rn]
[status-im.common.floating-button-page.floating-container.style :as style]))
@@ -10,10 +9,9 @@
[child]
(let [theme (quo.theme/use-theme)]
[quo/blur
{:blur-amount 52
:blur-radius 20
:blur-type :transparent
:blur-overlay-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)}
{:blur-amount 12
:blur-radius 12
:blur-type theme}
[rn/view {:style style/blur-inner-container}
child]]))
+2 -4
View File
@@ -35,9 +35,7 @@
user-in-syncing-devices-screen? (or (= (:view-id db) :screen/onboarding.syncing-progress)
(= (:view-id db) :screen/profile.profiles)
(= (:view-id db) :screen/onboarding.syncing-progress-intro))
user-in-sign-in-intro-screen? (= (:view-id db) :screen/onboarding.sign-in-intro)
keystore-files-transfer-action? (= action
constants/local-pairing-action-keystore-files-transfer)]
user-in-sign-in-intro-screen? (= (:view-id db) :screen/onboarding.sign-in-intro)]
(merge {:db (cond-> db
connection-success?
(assoc-in [:syncing :pairing-status] :connected)
@@ -63,7 +61,7 @@
(and completed-pairing? receiver?)
{:dispatch [:profile.login/local-paired-user]}
(and error-on-pairing? (some? error) (not keystore-files-transfer-action?))
(and error-on-pairing? (some? error))
{:dispatch [:toasts/upsert
{:type :negative
:text error}]}))))
@@ -31,10 +31,10 @@
:on-change-text #(reset! entered-password %)}]
(when (not-empty error)
[quo/info-message
{:status :error
:size :default
:icon :i/info
:container-style {:margin-top 8}}
{:type :error
:size :default
:icon :i/info
:containstyle {:margin-top 8}}
(i18n/label :t/oops-wrong-password)])
[quo/button
{:container-style {:margin-bottom 12 :margin-top 40}
@@ -1,17 +0,0 @@
(ns status-im.common.peer-stats.events
(:require
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/reg-event-fx :peer-stats/get-count
(fn []
{:fx [[:json-rpc/call
[{:method :wakuext_peers
:on-success [:peer-stats/get-count-success]
:on-error (fn [error]
(log/error "failed to fetch wakuv2 peer count"
{:error error}))}]]]}))
(rf/reg-event-fx :peer-stats/get-count-success
(fn [{:keys [db]} [response]]
{:db (assoc db :peer-stats/count (count response))}))
+4 -2
View File
@@ -195,7 +195,7 @@
true)
(defn view
[{:keys [title subtitle validate-fn on-success-scan error-message share-button?]}]
[{:keys [title subtitle validate-fn on-success-scan error-message share-button? import-keypair?]}]
(let [insets (safe-area/get-insets)
qr-code-succeed? (reagent/atom false)
qr-view-finder (reagent/atom {})
@@ -233,7 +233,9 @@
:set-qr-code-succeeded (fn [value]
(when on-success-scan
(on-success-scan value))
(rf/dispatch [:navigate-back]))
(if import-keypair?
(set-rescan-timeout)
(rf/dispatch [:navigate-back])))
:set-rescan-timeout set-rescan-timeout}])
[rn/view {:style (style/root-container (:top insets))}
[header
+13 -2
View File
@@ -10,6 +10,7 @@
[status-im.contexts.communities.discover.events]
[status-im.contexts.profile.push-notifications.local.events :as local-notifications]
[taoensso.timbre :as log]
[utils.debounce :as debounce]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
@@ -19,10 +20,17 @@
peers-count (count peers-summary)]
(rf/merge cofx
{:db (assoc db
:peers-summary peers-summary
:peer-stats/count peers-count)}
:peers-summary peers-summary
:peers-count peers-count)}
(visibility-status-updates/peers-summary-change peers-count))))
(rf/reg-event-fx :wakuv2-peer-stats
(fn [{:keys [db]} [^js peer-stats-js]]
(let [peer-stats (transforms/js->clj peer-stats-js)]
{:db (assoc db
:peer-stats peer-stats
:peers-count (count (:peers peer-stats)))})))
(rf/defn process
{:events [:signals/signal-received]}
[{:keys [db] :as cofx} event-str]
@@ -38,6 +46,9 @@
"wallet"
{:fx [[:dispatch [:wallet/signal-received event-js]]]}
"wakuv2.peerstats"
(debounce/debounce-and-dispatch [:wakuv2-peer-stats event-js] 1000)
"envelope.sent"
(messages.transport/update-envelopes-status
cofx
@@ -32,8 +32,9 @@
:on-cancel #(rf/dispatch [:standard-auth/authorize-with-password
args-with-biometric-btn])
:on-success (fn []
(rf/dispatch [:standard-auth/on-biometric-success on-auth-success])
(rf/dispatch [:standard-auth/close on-close]))
(when (fn? on-close)
(on-close))
(rf/dispatch [:standard-auth/on-biometric-success on-auth-success]))
:on-fail (fn [err]
(rf/dispatch [:standard-auth/authorize-with-password
args-with-biometric-btn])
@@ -47,7 +48,6 @@
[{:keys [db]} [on-auth-success]]
(let [key-uid (get-in db [:profile/profile :key-uid])]
{:fx [[:keychain/get-user-password [key-uid on-auth-success]]
[:dispatch [:standard-auth/set-success true]]
[:dispatch [:standard-auth/reset-login-password]]]}))
(schema/=> on-biometric-success events-schema/?on-biometric-success)
@@ -74,7 +74,6 @@
(fn [password]
(let [sha3-pwd (security/hash-masked-password password)
on-auth-success-callback #(on-auth-success sha3-pwd)]
(rf/dispatch [:standard-auth/set-success true])
(rf/dispatch [:standard-auth/reset-login-password])
(if has-partially-operable-accounts?
(rf/dispatch [:wallet/make-partially-operable-accounts-fully-operable
@@ -93,7 +92,10 @@
{:fx [[:dispatch [:standard-auth/reset-login-password]]
[:dispatch
[:show-bottom-sheet
{:on-close #(rf/dispatch [:standard-auth/close on-close])
{:on-close (fn []
(rf/dispatch [:standard-auth/reset-login-password])
(when on-close
(on-close)))
:theme theme
:shell? blur?
:content #(bottom-sheet-password-view args)}]]]})
@@ -105,23 +107,3 @@
:standard-auth/reset-login-password
(fn [{:keys [db]}]
{:db (update db :profile/login dissoc :password :error)}))
(rf/reg-fx
:standard-auth/on-close
(fn [{:keys [on-close success?]}]
(when on-close
(on-close success?))))
(rf/reg-event-fx
:standard-auth/close
(fn [{:keys [db]} [on-close]]
{:db (assoc-in db [:profile/login :success?] false)
:fx [[:dispatch [:standard-auth/reset-login-password]]
[:standard-auth/on-close
{:on-close on-close
:success? (get-in db [:profile/login :success?])}]]}))
(rf/reg-event-fx
:standard-auth/set-success
(fn [{:keys [db]} [success?]]
{:db (assoc-in db [:profile/login :success?] success?)}))
@@ -16,7 +16,8 @@
[error]
(if (and (some? error)
(or (= error "file is not a database")
(string/starts-with? (string/lower-case error) "failed")))
(string/starts-with? error "failed to set ")
(string/starts-with? error "Failed")))
(i18n/label :t/oops-wrong-password)
error))
@@ -33,9 +34,9 @@
[theme])]
[rn/view {:style style/error-message}
[quo/info-message
{:status :error
:size :default
:icon :i/info}
{:type :error
:size :default
:icon :i/info}
error-message]
[rn/pressable
{:hit-slop {:top 6 :bottom 20 :left 0 :right 0}
@@ -16,8 +16,7 @@
on-complete (rn/use-callback
(fn [reset]
(rf/dispatch [:standard-auth/authorize
{:on-close (fn [success?]
(js/setTimeout #(reset success?) 200))
{:on-close #(js/setTimeout reset 200)
:auth-button-icon-left auth-button-icon-left
:theme theme
:blur? blur?
+1 -5
View File
@@ -25,8 +25,6 @@
(goog-define ALCHEMY_OPTIMISM_GOERLI_TOKEN "")
(goog-define ALCHEMY_OPTIMISM_SEPOLIA_TOKEN "")
(goog-define WALLET_CONNECT_PROJECT_ID "87815d72a81d739d2a7ce15c2cfdefb3")
(goog-define MIXPANEL_APP_ID "3350627")
(goog-define MIXPANEL_TOKEN "5c73bda2d36a9f688a5ee45641fb6775")
(def mainnet-rpc-url (str "https://eth-archival.rpc.grove.city/v1/" POKT_TOKEN))
(def goerli-rpc-url (str "https://goerli-archival.gateway.pokt.network/v1/lb/" POKT_TOKEN))
@@ -41,9 +39,6 @@
(def opensea-link "https://opensea.io")
(def opensea-tesnet-link "https://testnets.opensea.io")
(def mixpanel-app-id MIXPANEL_APP_ID)
(def mixpanel-token MIXPANEL_TOKEN)
(def opensea-api-key OPENSEA_API_KEY)
(def bootnodes-settings-enabled? (enabled? (get-config :BOOTNODES_SETTINGS_ENABLED "1")))
(def mailserver-confirmations-enabled? (enabled? (get-config :MAILSERVER_CONFIRMATIONS_ENABLED)))
@@ -63,6 +58,7 @@
(def quo-preview-enabled? (enabled? (get-config :ENABLE_QUO_PREVIEW "0")))
(def database-management-enabled? (enabled? (get-config :DATABASE_MANAGEMENT_ENABLED "0")))
(def debug-webview? (enabled? (get-config :DEBUG_WEBVIEW "0")))
(def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1")))
(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0")))
(def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0")))
(def swap-enabled? (enabled? (get-config :SWAP_ENABLED "0")))
+1 -18
View File
@@ -281,9 +281,6 @@
(def ^:const wallet-connect-supported-events #{"accountsChanged" "chainChanged"})
(def ^:const wallet-connect-session-proposal-event "session_proposal")
(def ^:const wallet-connect-session-request-event "session_request")
(def ^:const wallet-connect-user-rejected-error-key "USER_REJECTED")
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
(def ^:const dapp-permission-contact-code "contact-code")
(def ^:const dapp-permission-web3 "web3")
@@ -370,18 +367,16 @@
(def ^:const local-pairing-role-receiver "receiver")
;; sender and receiver events
(def ^:const local-pairing-event-peer-discovered "peer-discovered")
(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")
(def ^:const local-pairing-event-received-installation "received-installation")
;; receiver events
(def ^:const local-pairing-event-received-account "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-received-keystore-files "received-keystore-files")
(def ^:const local-pairing-event-received-installation "received-installation")
(def ^:const local-pairing-event-errors
#{local-pairing-event-connection-error
@@ -392,8 +387,6 @@
(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 local-pairing-action-peer-discovery 5)
(def ^:const local-pairing-action-keystore-files-transfer 6)
(def ^:const serialization-key
"We pass this serialization key as a parameter to MultiformatSerializePublicKey
@@ -510,9 +503,6 @@
(def ^:const optimism-network-name :optimism)
(def ^:const arbitrum-network-name :arbitrum)
(def ^:const layer-1-network 1)
(def ^:const layer-2-network 2)
(def ^:const default-network-names [mainnet-network-name optimism-network-name arbitrum-network-name])
(def ^:const default-network-count (count default-network-names))
@@ -558,10 +548,3 @@
(def ^:const community-joined-notification-type "communityJoined")
(def ^:const default-telemetry-server-url "https://telemetry.status.im")
(def ^:const contact-item-height 56)
(def ^:const slippages [0.1 0.5 1])
(def ^:const default-slippage 0.5)
(def ^:const max-recommended-slippage 5)
(def ^:const max-slippage-decimal-places 2)
@@ -1,9 +0,0 @@
(ns status-im.contexts.centralized-metrics.effects
(:require
[native-module.core :as native-module]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(rf/reg-fx :effects.centralized-metrics/toggle-metrics
(fn [enabled?]
(native-module/toggle-centralized-metrics enabled? #(log/debug "toggled-metrics" % enabled?))))
@@ -1,33 +0,0 @@
(ns status-im.contexts.centralized-metrics.events
(:require
[native-module.core :as native-module]
[re-frame.interceptor :as interceptor]
status-im.contexts.centralized-metrics.effects
[status-im.contexts.centralized-metrics.tracking :as tracking]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn push-event?
[db]
(or (not (:centralized-metrics/user-confirmed? db))
(:centralized-metrics/enabled? db)))
(defn centralized-metrics-interceptor
[context]
(when-let [event (tracking/tracked-event (interceptor/get-coeffect context :event))]
(log/debug "tracking event" event)
(when (push-event? (interceptor/get-coeffect context :db))
(native-module/add-centralized-metric event)))
context)
(def interceptor
(interceptor/->interceptor
:id :centralized-metrics
:after centralized-metrics-interceptor))
(rf/reg-event-fx :centralized-metrics/toggle-centralized-metrics
(fn [{:keys [db]} [enabled?]]
{:fx [[:effects.centralized-metrics/toggle-metrics enabled?]]
:db (assoc db
:centralized-metrics/user-confirmed? true
:centralized-metrics/enabled? enabled?)}))
@@ -1,37 +0,0 @@
(ns status-im.contexts.centralized-metrics.events-test
(:require
[cljs.test :refer-macros [deftest is testing]]
matcher-combinators.test
[status-im.contexts.centralized-metrics.events :as events]
[status-im.contexts.centralized-metrics.tracking :as tracking]
[test-helpers.unit :as h]))
(deftest push-event-test
(testing "returns correct boolean value"
(is (true? (events/push-event? {:centralized-metrics/user-confirmed? false})))
(is (true? (events/push-event? {:centralized-metrics/enabled? true})))
(is (false? (events/push-event? {:centralized-metrics/user-confirmed? true
:centralized-metrics/enabled? false})))))
(deftest centralized-metrics-interceptor-test
(testing "processes context correctly"
(with-redefs [tracking/tracked-event (fn [_] {:metric "mocked-event"})
events/push-event? (fn [_] true)]
(let [context {:coeffects {:event [:some-event]
:db {:centralized-metrics/enabled? true}}}]
(is (= context (events/centralized-metrics-interceptor context)))))))
(h/deftest-event :centralized-metrics/toggle-centralized-metrics
[event-id dispatch]
(testing "toggling value to true"
(let [enabled? true
expected-fxs {:db {:centralized-metrics/user-confirmed? true
:centralized-metrics/enabled? enabled?}
:fx [[:effects.centralized-metrics/toggle-metrics enabled?]]}]
(is (match? expected-fxs (dispatch [event-id enabled?])))))
(testing "toggling value to false"
(let [enabled? false
expected-fxs {:db {:centralized-metrics/user-confirmed? true
:centralized-metrics/enabled? enabled?}
:fx [[:effects.centralized-metrics/toggle-metrics enabled?]]}]
(is (match? expected-fxs (dispatch [event-id enabled?]))))))
@@ -1,40 +0,0 @@
(ns status-im.contexts.centralized-metrics.tracking
(:require
[legacy.status-im.utils.build :as build]
[react-native.platform :as platform]))
(defn user-journey-event
[action]
{:metric
{:eventName "user-journey"
:platform platform/os
:appVersion build/app-short-version
:eventValue {:action action}}})
(def ^:const app-started-event "app-started")
(def ^:const navigate-to-create-profile-event "navigate-to-create-profile")
(def ^:const communities-tab-clicked "communities-tab-clicked")
(def ^:const wallet-tab-clicked "wallet-tab-clicked")
(def ^:const chats-tab-clicked "chats-tab-clicked")
(defn track-view-id-event
[view-id]
(case view-id
:communities-stack (user-journey-event communities-tab-clicked)
:chats-stack (user-journey-event chats-tab-clicked)
:wallet-stack (user-journey-event wallet-tab-clicked)
nil))
(defn tracked-event
[[event-name second-parameter]]
(case event-name
:onboarding/navigate-to-create-profile
(user-journey-event navigate-to-create-profile-event)
:profile/get-profiles-overview-success
(user-journey-event app-started-event)
:set-view-id
(track-view-id-event second-parameter)
nil))
@@ -1,35 +0,0 @@
(ns status-im.contexts.centralized-metrics.tracking-test
(:require
[cljs.test :refer-macros [deftest is testing]]
[legacy.status-im.utils.build :as build]
[react-native.platform :as platform]
[status-im.contexts.centralized-metrics.tracking :as tracking]))
(deftest user-journey-event-test
(testing "creates correct metric event"
(let [action "some-action"
expected {:metric {:eventName "user-journey"
:platform platform/os
:appVersion build/app-short-version
:eventValue {:action action}}}]
(is (= expected (tracking/user-journey-event action))))))
(deftest track-view-id-event-test
(testing "returns correct event for view-id"
(is (= (tracking/user-journey-event tracking/communities-tab-clicked)
(tracking/track-view-id-event :communities-stack)))
(is (= (tracking/user-journey-event tracking/chats-tab-clicked)
(tracking/track-view-id-event :chats-stack)))
(is (= (tracking/user-journey-event tracking/wallet-tab-clicked)
(tracking/track-view-id-event :wallet-stack)))
(is (nil? (tracking/track-view-id-event :unknown-stack)))))
(deftest tracked-event-test
(testing "returns correct event for given inputs"
(is (= (tracking/user-journey-event tracking/navigate-to-create-profile-event)
(tracking/tracked-event [:onboarding/navigate-to-create-profile])))
(is (= (tracking/user-journey-event tracking/app-started-event)
(tracking/tracked-event [:profile/get-profiles-overview-success])))
(is (= (tracking/track-view-id-event :wallet-stack)
(tracking/tracked-event [:set-view-id :wallet-stack])))
(is (nil? (tracking/tracked-event [:unknown-event])))))
@@ -105,10 +105,10 @@
:max-length constants/max-group-chat-name-length}]
(when error-message
[quo/info-message
{:status :error
:icon :i/info
:size :default
:container-style {:margin-top 8 :margin-left 20 :margin-bottom 16}}
{:type :error
:icon :i/info
:size :default
:style {:margin-top 8 :margin-left 20 :margin-bottom 16}}
error-message])
[quo/divider-line]
[rn/view
@@ -173,21 +173,20 @@
(defn avatar-view
[{:keys [contact chat-id full-name color muted? image]}]
[rn/view {:style {:justify-content :center}}
(if contact ; `contact` is passed when it's not a group chat
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])]
[quo/user-avatar
(cond-> {:full-name full-name
:size :small
:online? online?
:profile-picture photo-path}
muted?
(assoc :ring? false))])
[quo/group-avatar
{:customization-color color
:picture (when image {:uri image})
:size :size-32}])])
(if contact ; `contact` is passed when it's not a group chat
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])]
[quo/user-avatar
(cond-> {:full-name full-name
:size :small
:online? online?
:profile-picture photo-path}
muted?
(assoc :ring? false))])
[quo/group-avatar
{:customization-color color
:picture (when image {:uri image})
:size :size-32}]))
(defn- notification-layout
[child]
+1 -2
View File
@@ -66,8 +66,7 @@
(chat-list-item/chat-list-item item theme))
:scroll-event-throttle 8
:content-container-style {:padding-bottom
jump-to.constants/floating-shell-button-height
:padding-top 8}
jump-to.constants/floating-shell-button-height}
:on-scroll #(common.banner/set-scroll-shared-value
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
:shared-value scroll-shared-value})}])))
@@ -98,8 +98,9 @@
window-height
loading-indicator-page-loading-height)]
[rn/view {:padding-top top-spacing}
;; Don't use animated loading skeleton https://github.com/status-im/status-mobile/issues/17426
[quo/skeleton-list (skeleton-list-props :messages parent-height false)]]))
;; Only use animated loading skeleton for ios
;; https://github.com/status-im/status-mobile/issues/17426
[quo/skeleton-list (skeleton-list-props :messages parent-height platform/ios?)]]))
(defn header-height
[{:keys [insets able-to-send-message? images reply edit link-previews? input-content-height]}]

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