Compare commits

...
Author SHA1 Message Date
Volodymyr Kozieiev 0aede3510d status-im/utils/fx replaced with utils/re-frame to avoid unambiguities 2022-12-23 16:59:17 +00:00
yqrashawn 39e29cfb5a feat: replace clj-fmt with zprint (#14520) 2022-12-20 21:57:49 +08:00
yqrashawn 37909c2d81 feat: toast component (#14376) 2022-12-20 21:52:28 +08:00
yqrashawn 01660765b7 refactor: delete message related code (#14548) 2022-12-20 21:42:50 +08:00
Brian Sztamfater c0c0742687 feat: record audio button
Signed-off-by: Brian Sztamfater <brian@status.im>
2022-12-20 10:01:19 -03:00
Siddarth Kumar b074e9c58e moving security from status-im ns to root utils (#14567)
making a lint a fix

update old decision doc

fixing issues while poorly rebasing

fix incorrect ns imports
2022-12-20 17:56:21 +05:30
Icaro Motta 8cf95cdb30 New make target to run tests via REPL (#14576) 2022-12-20 09:07:00 -03:00
Omar Basem ba41d4b271 Photo Selector 2 (#14487)
* Photo Selector (2)
2022-12-20 07:36:06 +04:00
Guilherme Devincenzi 003b0ffb1e feat: add privacy options component (#14500) 2022-12-19 20:12:58 +01:00
Parvesh Monu dbd61a34a0 Update shell placeholder screen with new designs (#14572) 2022-12-19 14:51:53 +05:30
Yevheniia Berdnyk cbb6571954 e2e: Updated tests 702807 and 702808 2022-12-19 04:02:57 +02:00
Siddarth Kumar 7b72391e60 remove comment blocks which are not useful (#14563)
Adding a series of // characters (i.e., a "comment bar") above every method in an Objective-C file would not provide any real benefit, and would in fact be redundant, as the method list in Xcode already serves as a visual separator for methods in a class.
The #pragma mark directive,  is a more concise and effective way to add separators and group related methods in a class. We should use #pragma mark to create a separator line and add a heading to describe the methods in a particular section.
2022-12-16 22:39:39 +05:30
Icaro Motta 269d13e2f8 Move Activity Center to new app structure (#14554) 2022-12-16 10:45:00 -03:00
Siddarth Kumar fc07fbf787 UI for mobile to mobile local pairing - updated (#14514)
* ui for local pairing

lint-fix

removed un-necessary +

addressing some of the feedback on PR

more feedback + removing feature toggle from ui

getting rid of comments/log messages over here

tidy up logs

fix typos and more i18n stuff

swap % with a named parameter

getting rid of global state + lint-fix

get rid of un-used function

icon guidelines and more kebab case stuff :>

moving stuff to events and utils namespace

:main-icons -> :i :)

address feedback and adhere to guidelines etc

fixed the :t/ qualification

moree feedback :-D

referring status-im.utils.security for now

adding "cs" to constants

make tests pass

re-frame to rf

addressing feedback

moving icons to icons2 & renaming stuff

trying to make this file the way it was before

missed out on updating these references

getting rid of the icons moved to icons2

This reverts commit be8552c0d3daaf7a7333cfeaf304d97c86d50d3e.

fixing mistakes

getting rid of the s

* this rename makes sense to me

* adding an alias to the view

* fixed broken up namespaces
2022-12-16 18:40:56 +05:30
278 changed files with 14297 additions and 9907 deletions
+20 -20
View File
@@ -1,20 +1,20 @@
{:lint-as {status-im.utils.views/defview clojure.core/defn
status-im.utils.views/letsubs clojure.core/let
reagent.core/with-let clojure.core/let
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
quo.react/with-deps-check clojure.core/fn
quo.previews.preview/list-comp clojure.core/for
status-im.utils.styles/def clojure.core/def
status-im.utils.styles/defn clojure.core/defn
status-im.test-helpers/deftest-sub clojure.core/defn
taoensso.tufte/defnp clojure.core/defn}
:linters {:consistent-alias {:level :error
:aliases {clojure.string string
taoensso.timbre log}}
:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
;; TODO remove number when this is fixed
;; https://github.com/borkdude/clj-kondo/issues/867
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
number
status-im.test-helpers/restore-app-db]}}}
{:lint-as {status-im.utils.views/defview clojure.core/defn
status-im.utils.views/letsubs clojure.core/let
reagent.core/with-let clojure.core/let
utils.re-frame/defn clj-kondo.lint-as/def-catch-all
quo.react/with-deps-check clojure.core/fn
quo.previews.preview/list-comp clojure.core/for
status-im.utils.styles/def clojure.core/def
status-im.utils.styles/defn clojure.core/defn
status-im.test-helpers/deftest-sub clojure.core/defn
taoensso.tufte/defnp clojure.core/defn}
:linters {:consistent-alias {:level :error
:aliases {clojure.string string
taoensso.timbre log}}
:invalid-arity {:skip-args [utils.re-frame/defn]}
;; TODO remove number when this is fixed
;; https://github.com/borkdude/clj-kondo/issues/867
:unresolved-symbol {:exclude [PersistentPriorityMap.EMPTY
number
status-im.test-helpers/restore-app-db]}}
:config-in-ns {mocks.js-dependencies {:linters {:clojure-lsp/unused-public-var {:level :off}}}}}
+1
View File
@@ -32,3 +32,4 @@ COMMANDS_ENABLED=1
TWO_MINUTES_SYNCING=1
SWAP_ENABLED=1
STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1
+1
View File
@@ -32,3 +32,4 @@ COMMUNITIES_MANAGEMENT_ENABLED=1
DELETE_MESSAGE_ENABLED=1
TWO_MINUTES_SYNCING=1
STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1
+1
View File
@@ -34,3 +34,4 @@ DELETE_MESSAGE_ENABLED=1
TWO_MINUTES_SYNCING=1
ENABLE_QUO_PREVIEW=1
STICKERS_TEST_ENABLED=1
LOCAL_PAIRING_ENABLED=1
+47
View File
@@ -0,0 +1,47 @@
;; -*- mode: clojure -*-
;; vi: ft=clojure
{:width 105
:style [;; community style
;; https://github.com/kkinnear/zprint/blob/main/doc/reference.md#community
:community
;; no comma in map
:no-comma
:custom-justify
;; respect all newlines
;; https://github.com/kkinnear/zprint/blob/main/doc/reference.md#respect-nl
:respect-nl
;; respect blank line
;; https://github.com/kkinnear/zprint/blob/main/doc/reference.md#respect-bl
:respect-bl]
:fn-map
{"reg-sub" :arg1-pair
"list-comp" :binding
"defview" :arg1-body
"letsubs" :binding
"testing" :arg1-body
"deftest-sub" :arg1-body
"with-deps-check" :arg1-body
"ns" [:arg1-body
{:list {:respect-nl? false}
:vector {:respect-nl? false}}]
"->" [:noarg1-body
{:list {:constant-pair? false :force-nl? false}
:next-inner-restore [[:list :constant-pair?]]}]
"set!" "reset!"
"assoc-when" "assoc"
"assoc-some" "assoc"
"conj-when" "conj"
"conj-some" "conj"}
:remove {:fn-force-nl #{:noarg1-body}}
:style-map
{:no-comma {:map {:comma? false}}
:rj-var {:pair {:justify {:max-variance 1000}}}
:custom-justify
{:doc "Justify everything using pre-1.1.2 approach"
:binding {:justify? true :justify {:max-variance 1000}}
:map {:justify? true :justify {:max-variance 1000}}
:pair {:justify? true :justify {:max-variance 1000}}}}}
+18 -6
View File
@@ -285,16 +285,20 @@ endif
# Tests
#--------------
lint: export TARGET := clojure
lint: export TARGET := default
lint: ##@test Run code style checks
sh scripts/lint-re-frame-in-quo-components.sh && \
clj-kondo --config .clj-kondo/config.edn --cache false --lint src && \
TARGETS=$$(git diff --diff-filter=d --cached --name-only src && echo src) && \
clojure -Scp "$$CLASS_PATH" -m cljfmt.main check --indents indentation.edn $$TARGETS
TARGETS=$$(git diff --diff-filter=d --cached --name-only | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$ || echo shadow-cljs.edn) && \
zprint '{:search-config? true}' -fc $$TARGETS
lint-fix: export TARGET := clojure
lint-fix: export TARGET := default
lint-fix: ##@test Run code style checks and fix issues
clojure -Scp "$$CLASS_PATH" -m cljfmt.main fix src --indents indentation.edn
TARGETS=$$(git diff --diff-filter=d --cached --name-only | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$ || echo shadow-cljs.edn) && \
clojure-lsp clean-ns --filenames $$(echo $$TARGETS | xargs | sed -e 's/ /,/g') && \
zprint '{:search-config? true}' -fw $$TARGETS && \
zprint '{:search-config? true}' -fw $$TARGETS
shadow-server: export TARGET := clojure
shadow-server:##@ Start shadow-cljs in server mode for watching
@@ -305,6 +309,14 @@ test-watch: ##@ Watch tests and re-run no changes to cljs files
yarn install
nodemon --exec 'yarn shadow-cljs compile mocks && yarn shadow-cljs compile test && node --require ./test-resources/override.js target/test/test.js' -e cljs
test-watch-for-repl: export TARGET := clojure
test-watch-for-repl: ##@ Watch tests and support REPL connections
yarn install
rm -f target/test/test.js
concurrently --kill-others --prefix-colors 'auto' --names 'build,repl' \
'yarn shadow-cljs compile mocks && yarn shadow-cljs watch test --verbose' \
'until [ -f ./target/test/test.js ] ; do sleep 1 ; done ; node --require ./test-resources/override.js ./target/test/test.js --repl'
test: export TARGET := clojure
test: ##@test Run tests once in NodeJS
# Here we create the gyp bindings for nodejs
@@ -319,7 +331,7 @@ run-visual-test-ios: XCODE_DERIVED_DATA := $(HOME)/Library/Developer/Xcode/Deriv
run-visual-test-ios: APPLICATION_NAME := StatusIm-brfnruzfrkkycpbndmdoeyrigthc
run-visual-test-ios: export TEST_BINARY_PATH := $(XCODE_DERIVED_DATA)/$(APPLICATION_NAME)/Build/Products/Debug-iphonesimulator/StatusIm.app
run-visual-test-ios: ##@test Run tests once in NodeJS
detox test --configuration ios.sim.debug
detox test --configuration ios.sim.debug
component-test-watch: export TARGET := clojure
component-test-watch: export COMPONENT_TEST := true
@@ -20,6 +20,8 @@ printed out by mistake in a log entry (see https://github.com/status-im/status-m
To minimize the risk of leaking passwords through logs, we should not pass
passwords as strings in our codebase. We introduced a new type `MaskedData` in
`status-im.utils.security`.
update (16-Dec-2022) `status-im.utils.security` is now moved over to `utils.security.core`
We use `(security/mask-data <data to hide>` to wrap sensitive data into this
type and then use `(security/unmask <masked-data>)` to get the plaintext back.
-1
View File
@@ -1 +0,0 @@
{letsubs [[:inner 0]]}
@@ -940,6 +940,52 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject(configJSON);
final String keyUID = jsonConfig.getString("keyUID");
final String keyStorePath = this.getKeyStorePath(keyUID);
jsonConfig.put("keystorePath", keyStorePath);
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString());
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException {
final JSONObject jsonConfig = new JSONObject(configJSON);
final String keyStorePath = pathCombine(this.getNoBackupDirectory(), "/keystore");
jsonConfig.put("keystorePath", keyStorePath);
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.inputConnectionStringForBootstrapping(connectionString,jsonConfig.toString());
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void hashTypedData(final String data, final Callback callback) {
Log.d(TAG, "hashTypedData");
@@ -90,26 +90,25 @@ static RCTBridge *bridge;
RCT_EXPORT_MODULE();
////////////////////////////////////////////////////////////////////
#pragma mark - shouldMoveToInternalStorage
//////////////////////////////////////////////////////////////////// shouldMoveToInternalStorage
RCT_EXPORT_METHOD(shouldMoveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) {
// Android only
onResultCallback(@[[NSNull null]]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - moveToInternalStorage
//////////////////////////////////////////////////////////////////// moveToInternalStorage
RCT_EXPORT_METHOD(moveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) {
// Android only
onResultCallback(@[[NSNull null]]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - InitKeystore method
//////////////////////////////////////////////////////////////////// StopNode
RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -132,9 +131,9 @@ RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID
});
}
////////////////////////////////////////////////////////////////////
#pragma mark - SendLogs method
//////////////////////////////////////////////////////////////////// sendLogs
RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
jsLogs:(NSString *)jsLogs
callback:(RCTResponseSenderBlock)callback) {
@@ -196,7 +195,6 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
callback(@[zipFile.absoluteString]);
}
//////////////////////////////////////////////////////////////////// addPeer
RCT_EXPORT_METHOD(exportLogs:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"exportLogs() method called");
@@ -205,7 +203,6 @@ RCT_EXPORT_METHOD(exportLogs:(RCTResponseSenderBlock)callback) {
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// addPeer
RCT_EXPORT_METHOD(addPeer:(NSString *)enode
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoAddPeer(enode);
@@ -215,7 +212,6 @@ RCT_EXPORT_METHOD(addPeer:(NSString *)enode
#endif
}
//////////////////////////////////////////////////////////////////// multiAccountImportPrivateKey
RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -226,7 +222,6 @@ RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID
callback(@[result]);
}
////////////////////////////////////verify//////////////////////////////// multiAccountImportPrivateKey
RCT_EXPORT_METHOD(deleteImportedKey:(NSString *)keyUID
address:(NSString *)address
password:(NSString *)password
@@ -239,7 +234,6 @@ RCT_EXPORT_METHOD(deleteImportedKey:(NSString *)keyUID
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountGenerateAndDeriveAddresses
RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -249,7 +243,6 @@ RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// MultiAccountStoreAccount
RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -259,7 +252,6 @@ RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// MultiAccountLoadAccount
RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -269,7 +261,6 @@ RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// MultiAccountReset
RCT_EXPORT_METHOD(multiAccountReset:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountReset() method called");
@@ -278,7 +269,6 @@ RCT_EXPORT_METHOD(multiAccountReset:(RCTResponseSenderBlock)callback) {
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountStoreDerived
RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -288,7 +278,6 @@ RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountImportPrivateKey
RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -298,7 +287,6 @@ RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// hashTransaction
RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -308,7 +296,6 @@ RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// hashMessage
RCT_EXPORT_METHOD(hashMessage:(NSString *)message
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -318,7 +305,40 @@ RCT_EXPORT_METHOD(hashMessage:(NSString *)message
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// hashTypedData
RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON
callback:(RCTResponseSenderBlock)callback) {
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
NSString *keyUID = [configDict objectForKey:@"keyUID"];
NSURL *multiaccountKeystoreDir = [self getKeyStoreDir:keyUID];
NSString *keystoreDir = multiaccountKeystoreDir.path;
[configDict setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO];
NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON);
callback(@[result]);
}
RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
configJSON:(NSString *)configJSON
callback:(RCTResponseSenderBlock)callback) {
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:nil];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSString *keystoreDir = multiaccountKeystoreDir.path;
[configDict setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [configDict bv_jsonStringWithPrettyPrint:NO];
NSString *result = StatusgoInputConnectionStringForBootstrapping(cs,modifiedConfigJSON);
callback(@[result]);
}
RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -328,7 +348,6 @@ RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// hashTypedDataV4
RCT_EXPORT_METHOD(hashTypedDataV4:(NSString *)data
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -338,7 +357,6 @@ RCT_EXPORT_METHOD(hashTypedDataV4:(NSString *)data
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// sendTransactionWithSignature
RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON
signature:(NSString *)signature
callback:(RCTResponseSenderBlock)callback) {
@@ -349,7 +367,6 @@ RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountImportMnemonic
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -359,7 +376,6 @@ RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountDeriveAddresses
RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -379,7 +395,6 @@ RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
return [json valueForKey:@"key-uid"];
}
//////////////////////////////////////////////////////////////////// prepareDirAndUpdateConfig
-(NSString *) prepareDirAndUpdateConfig:(NSString *)config
withKeyUID:(NSString *)keyUID {
NSFileManager *fileManager = [NSFileManager defaultManager];
@@ -452,7 +467,6 @@ RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
}
//////////////////////////////////////////////////////////////////// prepareDirAndUpdateConfig
RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID
config:(NSString *)config
callback:(RCTResponseSenderBlock)callback) {
@@ -464,7 +478,6 @@ RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID
callback(@[updatedConfig]);
}
//////////////////////////////////////////////////////////////////// saveAccountAndLogin
RCT_EXPORT_METHOD(saveAccountAndLogin:(NSString *)multiaccountData
password:(NSString *)password
settings:(NSString *)settings
@@ -481,7 +494,6 @@ RCT_EXPORT_METHOD(saveAccountAndLogin:(NSString *)multiaccountData
NSLog(@"%@", result);
}
//////////////////////////////////////////////////////////////////// saveAccountAndLoginWithKeycard
RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData
password:(NSString *)password
settings:(NSString *)settings
@@ -502,11 +514,11 @@ RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData
- (NSString *) getExportDbFilePath {
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:filePath]) {
[fileManager removeItemAtPath:filePath error:nil];
}
return filePath;
}
@@ -543,7 +555,6 @@ RCT_EXPORT_METHOD(saveAccountAndLoginWithKeycard:(NSString *)multiaccountData
}
}
//////////////////////////////////////////////////////////////////// login
RCT_EXPORT_METHOD(login:(NSString *)accountData
password:(NSString *)password) {
#if DEBUG
@@ -555,7 +566,6 @@ RCT_EXPORT_METHOD(login:(NSString *)accountData
NSLog(@"%@", result);
}
//////////////////////////////////////////////////////////////////// loginWithConfig
RCT_EXPORT_METHOD(loginWithConfig:(NSString *)accountData
password:(NSString *)password
configJSON:(NSString *)configJSON) {
@@ -568,7 +578,6 @@ RCT_EXPORT_METHOD(loginWithConfig:(NSString *)accountData
NSLog(@"%@", result);
}
//////////////////////////////////////////////////////////////////// loginWithKeycard
RCT_EXPORT_METHOD(loginWithKeycard:(NSString *)accountData
password:(NSString *)password
chatKey:(NSString *)chatKey) {
@@ -583,7 +592,6 @@ RCT_EXPORT_METHOD(loginWithKeycard:(NSString *)accountData
NSLog(@"%@", result);
}
//////////////////////////////////////////////////////////////////// logout
RCT_EXPORT_METHOD(logout) {
#if DEBUG
NSLog(@"Logout() method called");
@@ -593,7 +601,6 @@ RCT_EXPORT_METHOD(logout) {
NSLog(@"%@", result);
}
//////////////////////////////////////////////////////////////////// openAccounts
RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"OpenAccounts() method called");
@@ -607,7 +614,6 @@ RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) {
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// verityAccountPassword
RCT_EXPORT_METHOD(verify:(NSString *)address
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
@@ -624,7 +630,6 @@ RCT_EXPORT_METHOD(verify:(NSString *)address
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// verifyDatabasePassword
RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
@@ -635,7 +640,6 @@ RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// changeDatabasePassword
RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID
currentPassword:(NSString *)currentPassword
newPassword:(NSString *)newPassword
@@ -648,7 +652,6 @@ RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// convertToKeycardAccount
RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID
accountData:(NSString *)accountData
settings:(NSString *)settings
@@ -663,9 +666,9 @@ RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - SendTransaction
//////////////////////////////////////////////////////////////////// sendTransaction
RCT_EXPORT_METHOD(sendTransaction:(NSString *)txArgsJSON
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
@@ -676,9 +679,9 @@ RCT_EXPORT_METHOD(sendTransaction:(NSString *)txArgsJSON
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - SignMessage
//////////////////////////////////////////////////////////////////// signMessage
RCT_EXPORT_METHOD(signMessage:(NSString *)message
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -688,9 +691,9 @@ RCT_EXPORT_METHOD(signMessage:(NSString *)message
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - Recover
//////////////////////////////////////////////////////////////////// recover
RCT_EXPORT_METHOD(recover:(NSString *)message
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -700,9 +703,9 @@ RCT_EXPORT_METHOD(recover:(NSString *)message
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - SignTypedData
//////////////////////////////////////////////////////////////////// signTypedData
RCT_EXPORT_METHOD(signTypedData:(NSString *)data
account:(NSString *)account
password:(NSString *)password
@@ -714,9 +717,9 @@ RCT_EXPORT_METHOD(signTypedData:(NSString *)data
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - SignTypedDataV4
//////////////////////////////////////////////////////////////////// signTypedDataV4
RCT_EXPORT_METHOD(signTypedDataV4:(NSString *)data
account:(NSString *)account
password:(NSString *)password
@@ -728,9 +731,9 @@ RCT_EXPORT_METHOD(signTypedDataV4:(NSString *)data
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - SignGroupMembership
//////////////////////////////////////////////////////////////////// signGroupMembership
RCT_EXPORT_METHOD(signGroupMembership:(NSString *)content
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -740,9 +743,9 @@ RCT_EXPORT_METHOD(signGroupMembership:(NSString *)content
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - ExtractGroupMembershipSignatures
//////////////////////////////////////////////////////////////////// extractGroupMembershipSignatures
RCT_EXPORT_METHOD(extractGroupMembershipSignatures:(NSString *)content
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
@@ -752,9 +755,9 @@ RCT_EXPORT_METHOD(extractGroupMembershipSignatures:(NSString *)content
callback(@[result]);
}
////////////////////////////////////////////////////////////////////
#pragma mark - GetNodeConfig
//////////////////////////////////////////////////////////////////// getNodeConfig
RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"GetNodeConfig() method called");
@@ -764,9 +767,9 @@ RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) {
}
////////////////////////////////////////////////////////////////////
#pragma mark - only android methods
////////////////////////////////////////////////////////////////////
RCT_EXPORT_METHOD(setAdjustResize) {
#if DEBUG
NSLog(@"setAdjustResize() works only on Android");
@@ -957,10 +960,10 @@ RCT_EXPORT_METHOD(exportUnencryptedDatabase:(NSString *)accountData
#if DEBUG
NSLog(@"exportUnencryptedDatabase() method called");
#endif
NSString *filePath = [self getExportDbFilePath];
StatusgoExportUnencryptedDatabase(accountData, password, filePath);
callback(@[filePath]);
}
@@ -995,7 +998,7 @@ RCT_EXPORT_METHOD(deactivateKeepAwake)
});
}
//// deviceinfo
#pragma mark - deviceinfo
- (bool) is24Hour
{
+259 -181
View File
@@ -51,6 +51,45 @@
}
},
{
"path": "borkdude/edamame/0.0.11-alpha.28/edamame-0.0.11-alpha.28",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "488f403591739aab5a68ce6e7f82c0e855c23fd6",
"sha256": "1cw712kzza733g55s02ql35q630zd8j8nmnpivcczjkg240jans4"
},
"jar": {
"sha1": "371f3e232e7fdb04b7b2044825eb9822280e8f93",
"sha256": "1iyxq6jypjd875cgdyllknh27mx5fnkyjz80mr927d5i94r0ywj4"
}
},
{
"path": "borkdude/sci.impl.reflector/0.0.1/sci.impl.reflector-0.0.1",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "eb3aff6c7db85d91f7e05b98e06d1354a4fce36c",
"sha256": "1bvr7cvpbvqi7swypzpbfrig16zipwvmg4m47y2x5chs5czwxv15"
},
"jar": {
"sha1": "33dfc86102e0ea400498cbca47572459c1c43b00",
"sha256": "0a5gxmj8kzc01y9bn7l4x7c1v5q9wcbvw5hdr525d3ylsyl6xfkw"
}
},
{
"path": "borkdude/sci/0.2.1-alpha.1/sci-0.2.1-alpha.1",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "516cb8e3a8e430d59d9c3e7a51f9f859e3b249e0",
"sha256": "1nrww29m90q1avaahw7i5418c18crc3cidhbg3ml7h7vjjplsl9y"
},
"jar": {
"sha1": "96e39dcbc3fb3a41c6bf2e628303cf0f534b28a3",
"sha256": "1cjvz85ls982rmx90igv4mcfaa53fj5z29df9mf4jplyig3l9dxb"
}
},
{
"path": "cider/cider-nrepl/0.25.3/cider-nrepl-0.25.3",
"host": "https://repo.clojars.org",
@@ -78,15 +117,15 @@
},
{
"path": "cljfmt/cljfmt/0.6.7/cljfmt-0.6.7",
"path": "clj-stacktrace/clj-stacktrace/0.2.8/clj-stacktrace-0.2.8",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "3d7ac9112908c9c9349adc056d1d06ae2cd33c21",
"sha256": "1q46q43mykn61f032y5734j84gcjca41pwd3iik9xghnzmphy2mn"
"sha1": "c5a47e6858344c9fd42eecafc7920a7a18d6126d",
"sha256": "1az0fs9k5xvzl8bz564apd77kqc83nl8sxsrvmswmbmkamvy4hd3"
},
"jar": {
"sha1": "91e8afa2c19db72acdef7f881aad905871ba6e69",
"sha256": "0ara83gaqnafjgr2aqz5zqmywdsmhsz483xkkxpiwbn9lfqvidmh"
"sha1": "b0654b98763199ee57182526465d823492d1cc3f",
"sha256": "1029wd82qyxv6ji9pd38m32nqia56h6845lqv4ym4dsz5i201g9a"
}
},
@@ -104,15 +143,15 @@
},
{
"path": "cljsjs/react/17.0.1-0/react-17.0.1-0",
"path": "cljsjs/react-dom-server/17.0.1-0/react-dom-server-17.0.1-0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "d5d3681281585d981375fe7bb29362bfcd0d4449",
"sha256": "0rskh6mfq5h0l0wybs68w9v585a6zlnnfgrvsf5k3h51fk2p28da"
"sha1": "ff154f318e1f63061b5bd42d9a38fc8547360cb4",
"sha256": "166ynlrph7rx3nql0c85c37vcbcsnwbjamk71hw74rz451pgnncr"
},
"jar": {
"sha1": "726da8a9305a865df90d81e9a8d58f87ff0ee8bd",
"sha256": "0bfmvw8gk98vdf9azll6041r1jaz1pmb0dyb35cfc8dr3mmr4ag7"
"sha1": "d5c53eca9f3884402c76268b82e3828223dcbf90",
"sha256": "1530hwqpxzxfjm6dy77whqwjzzx79jpnd9xvnkxy1lnk7l7lj494"
}
},
@@ -130,15 +169,15 @@
},
{
"path": "cljsjs/react-dom-server/17.0.1-0/react-dom-server-17.0.1-0",
"path": "cljsjs/react/17.0.1-0/react-17.0.1-0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "ff154f318e1f63061b5bd42d9a38fc8547360cb4",
"sha256": "166ynlrph7rx3nql0c85c37vcbcsnwbjamk71hw74rz451pgnncr"
"sha1": "d5d3681281585d981375fe7bb29362bfcd0d4449",
"sha256": "0rskh6mfq5h0l0wybs68w9v585a6zlnnfgrvsf5k3h51fk2p28da"
},
"jar": {
"sha1": "d5c53eca9f3884402c76268b82e3828223dcbf90",
"sha256": "1530hwqpxzxfjm6dy77whqwjzzx79jpnd9xvnkxy1lnk7l7lj494"
"sha1": "726da8a9305a865df90d81e9a8d58f87ff0ee8bd",
"sha256": "0bfmvw8gk98vdf9azll6041r1jaz1pmb0dyb35cfc8dr3mmr4ag7"
}
},
@@ -272,32 +311,6 @@
}
},
{
"path": "com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "7d5e372ff32c90095800f96d8308c41af0285a41",
"sha256": "1dj7p0m0kwnjvy1y3kq63zb6bw0azjf79i5xbccmy3wv63b1vqrg"
},
"jar": {
"sha1": "7e060dd5b19431e6d198e91ff670644372f60fbd",
"sha256": "1hn5plp7iyl626h8mrra56sysfm2qannj1dapr1m5afwkb24vfk1"
}
},
{
"path": "com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "5e902aae26ac5c36f6420f689f43333129dd69e2",
"sha256": "10vzlnl8vbjv2jqf818wdb7kgy9c6qjka7fjmmi3vdpg1mcn6pv6"
},
"jar": {
"sha1": "c9ad4a0850ab676c5c64461a05ca524cdfff59f1",
"sha256": "170rflxnqnah0265ik2aylmxkshyqbf2zas9bp2l32xqj9l6jsaf"
}
},
{
"path": "com/google/elemental2/elemental2-core/1.0.0-RC1/elemental2-core-1.0.0-RC1",
"host": "https://repo1.maven.org/maven2",
@@ -428,6 +441,19 @@
}
},
{
"path": "com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "5e902aae26ac5c36f6420f689f43333129dd69e2",
"sha256": "10vzlnl8vbjv2jqf818wdb7kgy9c6qjka7fjmmi3vdpg1mcn6pv6"
},
"jar": {
"sha1": "c9ad4a0850ab676c5c64461a05ca524cdfff59f1",
"sha256": "170rflxnqnah0265ik2aylmxkshyqbf2zas9bp2l32xqj9l6jsaf"
}
},
{
"path": "com/ibm/icu/icu4j/66.1/icu4j-66.1",
"host": "https://repo1.maven.org/maven2",
@@ -441,58 +467,6 @@
}
},
{
"path": "commons-codec/commons-codec/1.10/commons-codec-1.10",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "44b9477418d2942d45550f7e7c66c16262062d0e",
"sha256": "1yscxabk7i59vgfjg7c1y3prj39h1d8prnwgxbisc4ni29qdpf5x"
},
"jar": {
"sha1": "4b95f4897fa13f2cd904aee711aeafc0c5295cd8",
"sha256": "0scm6321zz76dc3bs8sy2qyami755lz4lq5455gl67bi9slxyha2"
}
},
{
"path": "commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "65112009d674333c1acfafb4e198ff250d710764",
"sha256": "007nyd66fqp3fbrmnsbfp1fpkhmr2lk33qmkp3salqld3xd7qlc8"
},
"jar": {
"sha1": "f95188e3d372e20e7328706c37ef366e5d7859b0",
"sha256": "1xyyl54sfxsdcwxdyq6b0azmr31b4dwqns850jjkw9a9dwrh5v54"
}
},
{
"path": "commons-io/commons-io/2.6/commons-io-2.6",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "5060835593e5b6ed18c82fc2e782f0a3c30a00b1",
"sha256": "0q4a6fp6xkyd86ikymkyv2plhf9vj8aqvggxg9d1yad2jcw8c8qc"
},
"jar": {
"sha1": "815893df5f31da2ece4040fe0a12fd44b577afaf",
"sha256": "04v5fg53jl9gbn6pyz3l7kbpxv0xjzyasnw6yd1a3hhacq2d6xzq"
}
},
{
"path": "compojure/compojure/1.5.2/compojure-1.5.2",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "9e8da477b6682094d56802cb155291a2acb829bd",
"sha256": "036z64iprypccz03iq7lqxvw99xjh4xlsfmfwbs37pmhfnfmbdnx"
},
"jar": {
"sha1": "0b5258d0616ffc5f64c2b6d95f09de56d24df439",
"sha256": "1s2k05lwnlm9a66mxnsss437i9gp70dny8y2rlfkl090s6mdqsaf"
}
},
{
"path": "com/taoensso/encore/2.105.0/encore-2.105.0",
"host": "https://repo.clojars.org",
@@ -571,6 +545,58 @@
}
},
{
"path": "commons-codec/commons-codec/1.10/commons-codec-1.10",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "44b9477418d2942d45550f7e7c66c16262062d0e",
"sha256": "1yscxabk7i59vgfjg7c1y3prj39h1d8prnwgxbisc4ni29qdpf5x"
},
"jar": {
"sha1": "4b95f4897fa13f2cd904aee711aeafc0c5295cd8",
"sha256": "0scm6321zz76dc3bs8sy2qyami755lz4lq5455gl67bi9slxyha2"
}
},
{
"path": "commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "65112009d674333c1acfafb4e198ff250d710764",
"sha256": "007nyd66fqp3fbrmnsbfp1fpkhmr2lk33qmkp3salqld3xd7qlc8"
},
"jar": {
"sha1": "f95188e3d372e20e7328706c37ef366e5d7859b0",
"sha256": "1xyyl54sfxsdcwxdyq6b0azmr31b4dwqns850jjkw9a9dwrh5v54"
}
},
{
"path": "commons-io/commons-io/2.6/commons-io-2.6",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "5060835593e5b6ed18c82fc2e782f0a3c30a00b1",
"sha256": "0q4a6fp6xkyd86ikymkyv2plhf9vj8aqvggxg9d1yad2jcw8c8qc"
},
"jar": {
"sha1": "815893df5f31da2ece4040fe0a12fd44b577afaf",
"sha256": "04v5fg53jl9gbn6pyz3l7kbpxv0xjzyasnw6yd1a3hhacq2d6xzq"
}
},
{
"path": "compojure/compojure/1.5.2/compojure-1.5.2",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "9e8da477b6682094d56802cb155291a2acb829bd",
"sha256": "036z64iprypccz03iq7lqxvw99xjh4xlsfmfwbs37pmhfnfmbdnx"
},
"jar": {
"sha1": "0b5258d0616ffc5f64c2b6d95f09de56d24df439",
"sha256": "1s2k05lwnlm9a66mxnsss437i9gp70dny8y2rlfkl090s6mdqsaf"
}
},
{
"path": "crypto-equality/crypto-equality/1.0.0/crypto-equality-1.0.0",
"host": "https://repo.clojars.org",
@@ -649,6 +675,19 @@
}
},
{
"path": "hashp/hashp/0.2.1/hashp-0.2.1",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "32530b9106a64fd5442d2aa27c6da4175d1f1440",
"sha256": "1z94k8c52r87rq3nhc0mqazcxff6d4phi8gy1bgndhiz4nq1mia7"
},
"jar": {
"sha1": "fb501db2eb4a028c1875382d58c17c381aec47b8",
"sha256": "1lwirzb60zvksvkb3arpwi4fk1xnp0x5ljmrca5vf7dq25lmwmsd"
}
},
{
"path": "hiccup/hiccup/1.0.5/hiccup-1.0.5",
"host": "https://repo.clojars.org",
@@ -779,6 +818,32 @@
}
},
{
"path": "mvxcvi/arrangement/1.2.0/arrangement-1.2.0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "4f19bd291595870162eadd35456a0b2e76444a64",
"sha256": "1qqnl05nwcjnzhlgplcsbckrp8pqvf8n6bf8kr8rz7lz2q4px3vb"
},
"jar": {
"sha1": "036e640bb9e14c2aa95589a45a018eb8358ce3f6",
"sha256": "1m3v1rkpdmv7aym5vq2swh0mf9mg7xppdr3vrl4g6qm3s42c24b7"
}
},
{
"path": "mvxcvi/puget/1.3.1/puget-1.3.1",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "07104dc20a13c7e255fffee4f16de9a6873c187f",
"sha256": "1129rb3qksg7n85j03k6d3sr6868g724097vxids1r4wqj2phxkf"
},
"jar": {
"sha1": "a4f7dcf71ccd8d69d4ecd2b19f3d671dfc169308",
"sha256": "029znh7p8f1h91gri4jhzwqsa0rnn3i34yr3kav55npym2sw5sfp"
}
},
{
"path": "net/cgrand/macrovich/0.2.1/macrovich-0.2.1",
"host": "https://repo.clojars.org",
@@ -884,15 +949,15 @@
},
{
"path": "org/clojure/core.rrb-vector/0.1.1/core.rrb-vector-0.1.1",
"path": "org/clojure/core.rrb-vector/0.1.2/core.rrb-vector-0.1.2",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "3231642aa1dcf628c864a5f208cd293fbd6a385a",
"sha256": "18kk5sds5lg8r2kidhz9qpgyrvggkj8j4sgfdsmyyl93w3f16lnp"
"sha1": "e9336ac820c5a7e07fe0aa431df981cbab6db3e3",
"sha256": "07q9qmxc7ggaxh27imgs34svn4j269rhslbnrs63ahrqzk5bmqlf"
},
"jar": {
"sha1": "aafb7677ec1e9f344fc834bbbdb91e8ba02af474",
"sha256": "0cqyy1vqrhilgwrdxsibd7360ch3hhwjnbbnzsak38v6i6mg66xl"
"sha1": "0404feea925608b921b56acd11d3b187a0d33fe4",
"sha256": "13hkx1285f2imqlj6wbgyxki2yg8rmfr49iq1zijxm1cgfx8xyai"
}
},
@@ -935,19 +1000,6 @@
}
},
{
"path": "org/clojure/google-closure-library/0.0-20191016-6ae1f72f/google-closure-library-0.0-20191016-6ae1f72f",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "dea94d117aa88d75e281f877914454f79df06bf2",
"sha256": "1nysls9ywj3b3zvlfwy68kayx47r4bacidmq1vx8w4h043l9kxrr"
},
"jar": {
"sha1": "6025affb7181cd40418600864f58eed1ea80055d",
"sha256": "0w6waii2qps7vp3nzbj5nai809xdq26ss0cabl4wz1s8fc6js6qw"
}
},
{
"path": "org/clojure/google-closure-library-third-party/0.0-20191016-6ae1f72f/google-closure-library-third-party-0.0-20191016-6ae1f72f",
"host": "https://repo1.maven.org/maven2",
@@ -961,6 +1013,19 @@
}
},
{
"path": "org/clojure/google-closure-library/0.0-20191016-6ae1f72f/google-closure-library-0.0-20191016-6ae1f72f",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "dea94d117aa88d75e281f877914454f79df06bf2",
"sha256": "1nysls9ywj3b3zvlfwy68kayx47r4bacidmq1vx8w4h043l9kxrr"
},
"jar": {
"sha1": "6025affb7181cd40418600864f58eed1ea80055d",
"sha256": "0w6waii2qps7vp3nzbj5nai809xdq26ss0cabl4wz1s8fc6js6qw"
}
},
{
"path": "org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176",
"host": "https://repo1.maven.org/maven2",
@@ -987,19 +1052,6 @@
}
},
{
"path": "org/clojure/tools.analyzer/1.0.0/tools.analyzer-1.0.0",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "fa72b6392b31762b55e0dc3de1c220ecdc6bb8a7",
"sha256": "1yg46a9zbga7rsrhwdv877hh60hcbyaykn37r3i50icxmgqcylq4"
},
"jar": {
"sha1": "d2fb65426c7998647fb1fb3db1fb5b222ab91df6",
"sha256": "0mj1xi3v03fzcw1smpayvbvbgly2p3ysbgfz7jgfdhmxi4gl6gs6"
}
},
{
"path": "org/clojure/tools.analyzer.jvm/1.1.0/tools.analyzer.jvm-1.1.0",
"host": "https://repo1.maven.org/maven2",
@@ -1013,6 +1065,19 @@
}
},
{
"path": "org/clojure/tools.analyzer/1.0.0/tools.analyzer-1.0.0",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "fa72b6392b31762b55e0dc3de1c220ecdc6bb8a7",
"sha256": "1yg46a9zbga7rsrhwdv877hh60hcbyaykn37r3i50icxmgqcylq4"
},
"jar": {
"sha1": "d2fb65426c7998647fb1fb3db1fb5b222ab91df6",
"sha256": "0mj1xi3v03fzcw1smpayvbvbgly2p3ysbgfz7jgfdhmxi4gl6gs6"
}
},
{
"path": "org/clojure/tools.cli/1.0.194/tools.cli-1.0.194",
"host": "https://repo1.maven.org/maven2",
@@ -1078,19 +1143,6 @@
}
},
{
"path": "org/graalvm/js/js/20.1.0/js-20.1.0",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "95452a7fdac1d358f1dd66b33e49f4440e986922",
"sha256": "0gkazzg8771g3pc90fb99wmlk99rjimcryrmzz6zab742m4dbina"
},
"jar": {
"sha1": "0abe5e8068014ccb34cf075637a00b7ce37e4a8c",
"sha256": "0v5pxjl9p7wwfrrzkkqh6qbvnn0p8n342smxzcqk3qxl4ah3aqnk"
}
},
{
"path": "org/graalvm/js/js-scriptengine/20.1.0/js-scriptengine-20.1.0",
"host": "https://repo1.maven.org/maven2",
@@ -1104,6 +1156,19 @@
}
},
{
"path": "org/graalvm/js/js/20.1.0/js-20.1.0",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "95452a7fdac1d358f1dd66b33e49f4440e986922",
"sha256": "0gkazzg8771g3pc90fb99wmlk99rjimcryrmzz6zab742m4dbina"
},
"jar": {
"sha1": "0abe5e8068014ccb34cf075637a00b7ce37e4a8c",
"sha256": "0v5pxjl9p7wwfrrzkkqh6qbvnn0p8n342smxzcqk3qxl4ah3aqnk"
}
},
{
"path": "org/graalvm/regex/regex/20.1.0/regex-20.1.0",
"host": "https://repo1.maven.org/maven2",
@@ -1234,19 +1299,6 @@
}
},
{
"path": "org/ow2/asm/asm/7.1/asm-7.1",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "7e40eb6619fd20bd7d98bf775bfdd810aec87ac7",
"sha256": "101i3pyrq082kjyz413hfqwkjjsyfnk9kx3rqr38ln56mlp78a8g"
},
"jar": {
"sha1": "fa29aa438674ff19d5e1386d2c3527a0267f291e",
"sha256": "1pnlb1ick32bihpzc599xl9ppd07qhls6pm0xaqwrj9cdlmzmcja"
}
},
{
"path": "org/ow2/asm/asm-analysis/7.1/asm-analysis-7.1",
"host": "https://repo1.maven.org/maven2",
@@ -1299,6 +1351,19 @@
}
},
{
"path": "org/ow2/asm/asm/7.1/asm-7.1",
"host": "https://repo1.maven.org/maven2",
"pom": {
"sha1": "7e40eb6619fd20bd7d98bf775bfdd810aec87ac7",
"sha256": "101i3pyrq082kjyz413hfqwkjjsyfnk9kx3rqr38ln56mlp78a8g"
},
"jar": {
"sha1": "fa29aa438674ff19d5e1386d2c3527a0267f291e",
"sha256": "1pnlb1ick32bihpzc599xl9ppd07qhls6pm0xaqwrj9cdlmzmcja"
}
},
{
"path": "org/wildfly/client/wildfly-client-config/1.0.1.Final/wildfly-client-config-1.0.1.Final",
"host": "https://repo1.maven.org/maven2",
@@ -1351,19 +1416,6 @@
}
},
{
"path": "reagent/reagent/1.0.0/reagent-1.0.0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "93ad5ccb0101108fb0843a3f2c50da28f8fd8336",
"sha256": "1l4xzgc4wbd8b29mhj5j336cf8w1zccaia0w413zf3bnj6jf5m38"
},
"jar": {
"sha1": "a1dd4d40425bb2e1afad0fe72780b43ff394ccfa",
"sha256": "1g607s1ymns85923bvhwrsj0y5czyqqq1jmxx0a58fnsm1b318fa"
}
},
{
"path": "re-com/re-com/2.8.0/re-com-2.8.0",
"host": "https://repo.clojars.org",
@@ -1377,19 +1429,6 @@
}
},
{
"path": "refactor-nrepl/refactor-nrepl/2.5.0/refactor-nrepl-2.5.0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "0bce30b420249ba7e4b90cbb3e046b4bb5416389",
"sha256": "0zmg5qc8d55pry7832isiwd2q237znfjqjpxchd2hvlpalh5qnva"
},
"jar": {
"sha1": "6bc3441afc94f7ca024e41a864ca75e05df7e207",
"sha256": "0w8hax99y98l53mixxzx2ja0vcnhjv8dnsaz1zj3vqk775ns5w6i"
}
},
{
"path": "re-frame/re-frame/0.12.0/re-frame-0.12.0",
"host": "https://repo.clojars.org",
@@ -1429,6 +1468,32 @@
}
},
{
"path": "reagent/reagent/1.0.0/reagent-1.0.0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "93ad5ccb0101108fb0843a3f2c50da28f8fd8336",
"sha256": "1l4xzgc4wbd8b29mhj5j336cf8w1zccaia0w413zf3bnj6jf5m38"
},
"jar": {
"sha1": "a1dd4d40425bb2e1afad0fe72780b43ff394ccfa",
"sha256": "1g607s1ymns85923bvhwrsj0y5czyqqq1jmxx0a58fnsm1b318fa"
}
},
{
"path": "refactor-nrepl/refactor-nrepl/2.5.0/refactor-nrepl-2.5.0",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "0bce30b420249ba7e4b90cbb3e046b4bb5416389",
"sha256": "0zmg5qc8d55pry7832isiwd2q237znfjqjpxchd2hvlpalh5qnva"
},
"jar": {
"sha1": "6bc3441afc94f7ca024e41a864ca75e05df7e207",
"sha256": "0w8hax99y98l53mixxzx2ja0vcnhjv8dnsaz1zj3vqk775ns5w6i"
}
},
{
"path": "rewrite-clj/rewrite-clj/0.6.1/rewrite-clj-0.6.1",
"host": "https://repo.clojars.org",
@@ -1443,15 +1508,15 @@
},
{
"path": "rewrite-cljs/rewrite-cljs/0.4.4/rewrite-cljs-0.4.4",
"path": "rewrite-cljs/rewrite-cljs/0.4.5/rewrite-cljs-0.4.5",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "4e7a2542517a5b0231631305461603605bea1592",
"sha256": "050imgkzw5q7200klwrkd4v32xxy1f4aghs8g4ma5dbg4rl4pgcd"
"sha1": "378cd53218027b9a93640dcf64c040665f6c9c6b",
"sha256": "1qrhrgzhqdyqizh0ngnr4zgj9xkfzq0qhsws4pxxra3qc9ikl9cq"
},
"jar": {
"sha1": "dd14a371d0d09eedccb39f01e3edabefb2d1e64f",
"sha256": "0hb07wg71i2bjn8wzs8q6w1nb3jb2s36nhr9kv9mc0gyrr6im244"
"sha1": "c35be115c39dadc71a4de3f584aa8ca295e11257",
"sha256": "1dnw0jhr1hhqz80w3z5d8qdbaqdvgzg4fyhv6lffa51c9ca1dsr1"
}
},
@@ -1583,5 +1648,18 @@
"sha1": "09af0b348e6253dcf9fd567d0d22ffebdea46176",
"sha256": "1qg2iyblykfkzmplc2c46916b9m0h5ad6lxmvrk5qn3pdxqr8vw0"
}
},
{
"path": "zprint/zprint/1.1.1/zprint-1.1.1",
"host": "https://repo.clojars.org",
"pom": {
"sha1": "d7225bdc4978d3a8eac8613187cddd2efb9e39d2",
"sha256": "0yyy31h88zww238c2v4zi9va3pjp7ii76zjggglakd3wm1fdbnck"
},
"jar": {
"sha1": "3bd9bbedb188a66ccf72c1e22819e8e423a6757a",
"sha256": "1bvrarxw0dqvxlhj6gdwrv6mklzh4p79537g293fqlm07f2knfph"
}
}
]
+23 -17
View File
@@ -2,13 +2,16 @@ args4j/args4j/2.0.26/args4j-2.0.26.jar
bidi/bidi/2.1.6/bidi-2.1.6.jar
binaryage/env-config/0.2.2/env-config-0.2.2.jar
binaryage/oops/0.7.0/oops-0.7.0.jar
borkdude/edamame/0.0.11-alpha.28/edamame-0.0.11-alpha.28.jar
borkdude/sci.impl.reflector/0.0.1/sci.impl.reflector-0.0.1.jar
borkdude/sci/0.2.1-alpha.1/sci-0.2.1-alpha.1.jar
cider/cider-nrepl/0.25.3/cider-nrepl-0.25.3.jar
cider/piggieback/0.4.1/piggieback-0.4.1.jar
cljfmt/cljfmt/0.6.7/cljfmt-0.6.7.jar
clj-stacktrace/clj-stacktrace/0.2.8/clj-stacktrace-0.2.8.jar
cljs-bean/cljs-bean/1.3.0/cljs-bean-1.3.0.jar
cljsjs/react/17.0.1-0/react-17.0.1-0.jar
cljsjs/react-dom/17.0.1-0/react-dom-17.0.1-0.jar
cljsjs/react-dom-server/17.0.1-0/react-dom-server-17.0.1-0.jar
cljsjs/react-dom/17.0.1-0/react-dom-17.0.1-0.jar
cljsjs/react/17.0.1-0/react-17.0.1-0.jar
clout/clout/2.1.2/clout-2.1.2.jar
com/andrewmcveigh/cljs-time/0.5.2/cljs-time-0.5.2.jar
com/bhauman/cljs-test-display/0.1.1/cljs-test-display-0.1.1.jar
@@ -19,8 +22,6 @@ com/cognitect/transit-js/0.8.846/transit-js-0.8.846.jar
com/fasterxml/jackson/core/jackson-core/2.8.7/jackson-core-2.8.7.jar
com/google/code/findbugs/jsr305/3.0.1/jsr305-3.0.1.jar
com/google/code/gson/gson/2.7/gson-2.7.jar
com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0.jar
com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar
com/google/elemental2/elemental2-core/1.0.0-RC1/elemental2-core-1.0.0-RC1.jar
com/google/errorprone/error_prone_annotations/2.3.1/error_prone_annotations-2.3.1.jar
com/google/guava/guava/25.1-jre/guava-25.1-jre.jar
@@ -31,23 +32,25 @@ com/google/jsinterop/base/1.0.0/base-1.0.0.jar
com/google/jsinterop/jsinterop-annotations/1.0.2/jsinterop-annotations-1.0.2.jar
com/google/protobuf/protobuf-java/3.11.1/protobuf-java-3.11.1.jar
com/google/re2j/re2j/1.3/re2j-1.3.jar
com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar
com/ibm/icu/icu4j/66.1/icu4j-66.1.jar
commons-codec/commons-codec/1.10/commons-codec-1.10.jar
commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4.jar
commons-io/commons-io/2.6/commons-io-2.6.jar
compojure/compojure/1.5.2/compojure-1.5.2.jar
com/taoensso/encore/2.105.0/encore-2.105.0.jar
com/taoensso/timbre/4.10.0/timbre-4.10.0.jar
com/taoensso/truss/1.5.0/truss-1.5.0.jar
com/taoensso/tufte/2.1.0/tufte-2.1.0.jar
com/wsscode/pathom/2.2.31/pathom-2.2.31.jar
com/wsscode/spec-inspec/1.0.0-alpha2/spec-inspec-1.0.0-alpha2.jar
commons-codec/commons-codec/1.10/commons-codec-1.10.jar
commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4.jar
commons-io/commons-io/2.6/commons-io-2.6.jar
compojure/compojure/1.5.2/compojure-1.5.2.jar
crypto-equality/crypto-equality/1.0.0/crypto-equality-1.0.0.jar
crypto-random/crypto-random/1.2.0/crypto-random-1.2.0.jar
day8/re-frame/test/0.1.5/test-0.1.5.jar
edn-query-language/eql/0.0.9/eql-0.0.9.jar
expound/expound/0.8.5/expound-0.8.5.jar
fipp/fipp/0.6.23/fipp-0.6.23.jar
hashp/hashp/0.2.1/hashp-0.2.1.jar
hiccup/hiccup/1.0.5/hiccup-1.0.5.jar
hickory/hickory/0.7.1/hickory-0.7.1.jar
http-kit/http-kit/2.2.0/http-kit-2.2.0.jar
@@ -58,6 +61,8 @@ javax/servlet/servlet-api/2.5/servlet-api-2.5.jar
javax/xml/bind/jaxb-api/2.3.0/jaxb-api-2.3.0.jar
medley/medley/0.8.2/medley-0.8.2.jar
mvxcvi/alphabase/1.0.0/alphabase-1.0.0.jar
mvxcvi/arrangement/1.2.0/arrangement-1.2.0.jar
mvxcvi/puget/1.3.1/puget-1.3.1.jar
net/cgrand/macrovich/0.2.1/macrovich-0.2.1.jar
nrepl/nrepl/0.7.0/nrepl-0.7.0.jar
org/checkerframework/checker-qual/2.0.0/checker-qual-2.0.0.jar
@@ -66,23 +71,23 @@ org/clojure/clojurescript/1.10.773/clojurescript-1.10.773.jar
org/clojure/core.async/1.3.610/core.async-1.3.610.jar
org/clojure/core.cache/1.0.207/core.cache-1.0.207.jar
org/clojure/core.memoize/1.0.236/core.memoize-1.0.236.jar
org/clojure/core.rrb-vector/0.1.1/core.rrb-vector-0.1.1.jar
org/clojure/core.rrb-vector/0.1.2/core.rrb-vector-0.1.2.jar
org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar
org/clojure/data.json/1.0.0/data.json-1.0.0.jar
org/clojure/data.priority-map/1.0.0/data.priority-map-1.0.0.jar
org/clojure/google-closure-library/0.0-20191016-6ae1f72f/google-closure-library-0.0-20191016-6ae1f72f.jar
org/clojure/google-closure-library-third-party/0.0-20191016-6ae1f72f/google-closure-library-third-party-0.0-20191016-6ae1f72f.jar
org/clojure/google-closure-library/0.0-20191016-6ae1f72f/google-closure-library-0.0-20191016-6ae1f72f.jar
org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar
org/clojure/test.check/1.1.0/test.check-1.1.0.jar
org/clojure/tools.analyzer/1.0.0/tools.analyzer-1.0.0.jar
org/clojure/tools.analyzer.jvm/1.1.0/tools.analyzer.jvm-1.1.0.jar
org/clojure/tools.analyzer/1.0.0/tools.analyzer-1.0.0.jar
org/clojure/tools.cli/1.0.194/tools.cli-1.0.194.jar
org/clojure/tools.logging/0.4.1/tools.logging-0.4.1.jar
org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.jar
org/clojure/tools.reader/1.3.3/tools.reader-1.3.3.jar
org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar
org/graalvm/js/js/20.1.0/js-20.1.0.jar
org/graalvm/js/js-scriptengine/20.1.0/js-scriptengine-20.1.0.jar
org/graalvm/js/js/20.1.0/js-20.1.0.jar
org/graalvm/regex/regex/20.1.0/regex-20.1.0.jar
org/graalvm/sdk/graal-sdk/20.1.0/graal-sdk-20.1.0.jar
org/graalvm/truffle/truffle-api/20.1.0/truffle-api-20.1.0.jar
@@ -93,23 +98,23 @@ org/jboss/xnio/xnio-api/3.8.0.Final/xnio-api-3.8.0.Final.jar
org/jboss/xnio/xnio-nio/3.8.0.Final/xnio-nio-3.8.0.Final.jar
org/jsoup/jsoup/1.9.2/jsoup-1.9.2.jar
org/msgpack/msgpack/0.6.12/msgpack-0.6.12.jar
org/ow2/asm/asm/7.1/asm-7.1.jar
org/ow2/asm/asm-analysis/7.1/asm-analysis-7.1.jar
org/ow2/asm/asm-commons/7.1/asm-commons-7.1.jar
org/ow2/asm/asm-tree/7.1/asm-tree-7.1.jar
org/ow2/asm/asm-util/7.1/asm-util-7.1.jar
org/ow2/asm/asm/7.1/asm-7.1.jar
org/wildfly/client/wildfly-client-config/1.0.1.Final/wildfly-client-config-1.0.1.Final.jar
org/wildfly/common/wildfly-common/1.5.2.Final/wildfly-common-1.5.2.Final.jar
prismatic/schema/1.1.7/schema-1.1.7.jar
quoin/quoin/0.1.2/quoin-0.1.2.jar
reagent/reagent/1.0.0/reagent-1.0.0.jar
re-com/re-com/2.8.0/re-com-2.8.0.jar
refactor-nrepl/refactor-nrepl/2.5.0/refactor-nrepl-2.5.0.jar
re-frame/re-frame/0.12.0/re-frame-0.12.0.jar
re-frisk-remote/re-frisk-remote/1.6.0/re-frisk-remote-1.6.0.jar
re-frisk/sente/1.15.0/sente-1.15.0.jar
reagent/reagent/1.0.0/reagent-1.0.0.jar
refactor-nrepl/refactor-nrepl/2.5.0/refactor-nrepl-2.5.0.jar
rewrite-clj/rewrite-clj/0.6.1/rewrite-clj-0.6.1.jar
rewrite-cljs/rewrite-cljs/0.4.4/rewrite-cljs-0.4.4.jar
rewrite-cljs/rewrite-cljs/0.4.5/rewrite-cljs-0.4.5.jar
ring-cors/ring-cors/0.1.8/ring-cors-0.1.8.jar
ring/ring-codec/1.1.2/ring-codec-1.1.2.jar
ring/ring-core/1.8.1/ring-core-1.8.1.jar
@@ -120,3 +125,4 @@ thheller/shadow-cljs/2.11.16/shadow-cljs-2.11.16-aot.jar
thheller/shadow-cljsjs/0.0.21/shadow-cljsjs-0.0.21.jar
thheller/shadow-util/0.7.0/shadow-util-0.7.0.jar
viebel/codox-klipse-theme/0.0.1/codox-klipse-theme-0.0.1.jar
zprint/zprint/1.1.1/zprint-1.1.1.jar
+2
View File
@@ -17,6 +17,8 @@ in mkShell {
lsof # used in start-react-native.sh
# build specific utilities
clojure maven watchman
# lint specific utilities
clj-kondo zprint clojure-lsp
# other nice to have stuff
yarn nodejs python27
] # and some special cases
+1 -1
View File
@@ -23,7 +23,7 @@ let
# for calling clojure targets in CI or Makefile
clojure = mkShell {
buildInputs = with pkgs; [ clojure flock maven openjdk clj-kondo ];
buildInputs = with pkgs; [ clojure flock maven openjdk ];
inputsFrom = [ nodejs-sh ];
# CLASSPATH from clojure deps with 'src' appended to find local sources.
shellHook = with pkgs; ''
+1
View File
@@ -89,6 +89,7 @@
"@testing-library/jest-native": "^5.0.0",
"@testing-library/react-native": "^11.2.0",
"@types/jest": "^28.1.6",
"concurrently": "^7.6.0",
"detox": "^19.9.1",
"jest": "^25.1.0",
"jest-circus": "^26.0.0",
Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

+110 -106
View File
@@ -1,116 +1,120 @@
;; shadow-cljs configuration
{:source-paths ["src" "test/cljs"]
{:source-paths ["src" "test/cljs"]
:dependencies [[reagent "1.0.0"]
[re-frame "0.12.0"]
[binaryage/oops "0.7.0"]
[com.andrewmcveigh/cljs-time "0.5.2"]
[status-im/timbre "4.10.0-2-status"]
[com.taoensso/encore "2.105.0"]
[hickory "0.7.1"]
[cljs-bean "1.3.0"]
[com.cognitect/transit-cljs "0.8.248"]
[mvxcvi/alphabase "1.0.0"]
;; dev dependencies
[refactor-nrepl "2.5.0"]
[cider/cider-nrepl "0.25.3"]
[cider/piggieback "0.4.1"]
[re-frisk-remote "1.6.0"]
;; routing
[bidi "2.1.6"]
;; test dependencies
[day8.re-frame/test "0.1.5"]
[com.taoensso/tufte "2.1.0"]
;; linting
[cljfmt/cljfmt "0.6.7"]]
:dependencies [[reagent "1.0.0"]
[re-frame "0.12.0"]
[binaryage/oops "0.7.0"]
[com.andrewmcveigh/cljs-time "0.5.2"]
[status-im/timbre "4.10.0-2-status"]
[com.taoensso/encore "2.105.0"]
[hickory "0.7.1"]
[cljs-bean "1.3.0"]
[com.cognitect/transit-cljs "0.8.248"]
[mvxcvi/alphabase "1.0.0"]
;; dev dependencies
[refactor-nrepl "2.5.0"]
[cider/cider-nrepl "0.25.3"]
[cider/piggieback "0.4.1"]
[re-frisk-remote "1.6.0"]
;; routing
[bidi "2.1.6"]
;; test dependencies
[day8.re-frame/test "0.1.5"]
[com.taoensso/tufte "2.1.0"]]
;; port and middleware for repl in development
:nrepl {:port 7888
:middleware [cider.piggieback/wrap-cljs-repl
refactor-nrepl.middleware/wrap-refactor]}
:nrepl {:port 7888
:middleware [cider.piggieback/wrap-cljs-repl
refactor-nrepl.middleware/wrap-refactor]}
;; shadow-cljs web interface
:http {:port 3449
:host "0.0.0.0"}
:http {:port 3449
:host "0.0.0.0"}
:cache-blockers #{status-im.utils.js-resources status-im.ui.components.icons.icons}
:builds {:mobile
{:target :react-native
:output-dir "app"
:init-fn status-im2.setup.core/init
;; When false, the Shadow-CLJS watcher won't automatically refresh
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
:devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]}
:dev {:devtools {:after-load status-im2.setup.hot-reload/reload
:build-notify status-im2.setup.hot-reload/build-notify
:preloads [re-frisk-remote.preload]}
:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {:output-feature-set :es5
:closure-defines
{re-frame.trace/trace-enabled? true}
:source-map false
:infer-externs true}
;; if you want to use a real device, set your local ip
;; in the SHADOW_HOST env variable to make sure that
;; it will use the right interface
:local-ip #shadow/env "SHADOW_HOST"}
:chunks {:fleets status-im.fleet.default-fleet/default-fleets
:chats status-im.chat.default-chats/default-chats}
:release
{:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
:warnings-as-errors false
:infer-externs :auto
:static-fns true
:fn-invoke-direct true
:optimizations :advanced
:js-options {:js-provider :closure}}}}
;; the tests are ran with node, react-native dependencies are mocked
;; by using node --require override.js, which uses the node-library
;; produced by the target :mocks below and redefines node require
;; function to use the mocks instead of the rn libraries
:test
{:output-to "target/test/test.js"
:output-dir "target/test"
:optimizations :simple
:target :node-test
:main status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl
:ui-driven true
:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {;; needed because we override require and it
;; messes with source-map which reports callstack
;; exceeded exceptions instead of real issues
:source-map false
;; needed because we use deref in tests
:static-fns false
:optimizations :simple
:infer-externs true}}
:builds
{:mobile
{:target :react-native
:output-dir "app"
:init-fn status-im2.setup.core/init
;; When false, the Shadow-CLJS watcher won't automatically refresh
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
:devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]}
:dev {:devtools {:after-load status-im2.setup.hot-reload/reload
:build-notify status-im2.setup.hot-reload/build-notify
:preloads [re-frisk-remote.preload]}
:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {:output-feature-set :es5
:closure-defines
{re-frame.trace/trace-enabled? true}
:source-map false
:infer-externs true}
;; if you want to use a real device, set your local ip
;; in the SHADOW_HOST env variable to make sure that
;; it will use the right interface
:local-ip #shadow/env "SHADOW_HOST"}
:chunks {:fleets status-im.fleet.default-fleet/default-fleets
:chats status-im.chat.default-chats/default-chats}
:release
{:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options {:output-feature-set :es6
;;disable for android build as there
;;is an intermittent warning with deftype
:warnings-as-errors false
:infer-externs :auto
:static-fns true
:fn-invoke-direct true
:optimizations :advanced
:js-options {:js-provider :closure}}}}
;; the tests are ran with node, react-native dependencies are mocked
;; by using node --require override.js, which uses the node-library
;; produced by the target :mocks below and redefines node require
;; function to use the mocks instead of the rn libraries
:test
{:output-to "target/test/test.js"
:output-dir "target/test"
:optimizations :simple
:target :node-test
;; When running tests without a REPL you can uncomment below line to `make test-watch` a specific file
;; :ns-regexp "status-im.chat.models-test$"
:main
status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl
:ui-driven
true
:closure-defines
{status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.utils.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"}
:compiler-options
{;; needed because we override require and it
;; messes with source-map which reports callstack
;; exceeded exceptions instead of real issues
:source-map false
;; needed because we use deref in tests
:static-fns false
:optimizations :simple
:infer-externs true}}
;; mock.js-dependencies is mocking the react-native libraries
;; we build it as a node library so that it can be required by
;; override.js
:mocks
{:target :node-library
:exports {:mocks mocks.js-dependencies/mock}
:output-to "target/mocks/mocks.js"
:output-dir "target/mocks"
:compiler-options {:optimizations :simple
:source-map false}}
:component-test {:target :npm-module
:entries [quo2.core-spec]
:ns-regexp "-component-spec$"
:output-dir "component-spec"
:compiler-options {:warnings-as-errors false
:static-fns false
:infer-externs true}}}}
;; mock.js-dependencies is mocking the react-native libraries
;; we build it as a node library so that it can be required by
;; override.js
:mocks
{:target :node-library
:exports {:mocks mocks.js-dependencies/mock}
:output-to "target/mocks/mocks.js"
:output-dir "target/mocks"
:compiler-options {:optimizations :simple
:source-map false}}
:component-test {:target :npm-module
:entries [quo2.core-spec]
:ns-regexp "-component-spec$"
:output-dir "component-spec"
:compiler-options {:warnings-as-errors false
:static-fns false
:infer-externs true}}}}
+18
View File
@@ -0,0 +1,18 @@
import { useDerivedValue } from 'react-native-reanimated';
const MAX_SCALE = 1.8;
export function ringScale(scale, subtract) {
return useDerivedValue(
function () {
'worklet'
const value = scale.value;
const maxDelta = MAX_SCALE - 1;
const maxDeltaDiff = 1 - maxDelta;
const maxVirtualScale = MAX_SCALE + maxDelta;
const decimals = value - Math.floor(value);
const normalizedValue = value >= maxVirtualScale ? (decimals + ((parseInt(value) - 1) * maxDeltaDiff) + 1) : value;
return (((normalizedValue - subtract) > MAX_SCALE ? normalizedValue - maxDelta : normalizedValue) - subtract);
}
);
}
+11
View File
@@ -1,3 +1,5 @@
import { useDerivedValue, interpolate } from 'react-native-reanimated';
// Generic Worklets
export function applyAnimationsToStyle(animations, style) {
@@ -27,3 +29,12 @@ export function applyAnimationsToStyle(animations, style) {
return Object.assign(animatedStyle, style);
};
};
export function interpolateValue(sharedValue, inputRange, outputRange) {
return useDerivedValue(
function () {
'worklet'
return interpolate(sharedValue.value, inputRange, outputRange);
}
);
}
+24 -2
View File
@@ -4,6 +4,20 @@
(:require [status-im.utils.test :as utils.test])
(:require [status-im.chat.default-chats :refer (default-chats)]))
;; to generate a js Proxy at js/__STATUS_MOBILE_JS_IDENTITY_PROXY__ that accept any (.xxx) call and return itself
;; For the convenience to mock eg.
;; (-> reanimated/slide-out-up-animation .springify (.damping 20) (.stiffness 300))
;; (-> reanimated/slide-out-up-animation (.damping 20) .springify (.stiffness 300))
(js/eval "
var globalThis
if (typeof window === \"undefined\") {
globalThis = global
} else {
globalThis = window
}
globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return () => globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__}})
")
(def action-button #js {:default #js {:Item #js {}}})
(def config #js {:default #js {}})
(def camera #js {:RNCamera #js {:Constants #js {}}})
@@ -111,7 +125,9 @@
(def react-native-shake #js {})
(def react-native-share #js {:default {}})
(def react-native-svg #js {:SvgUri #js {:render identity}
:SvgXml #js {:render identity}})
:SvgXml #js {:render identity}
:default #js {:render identity}
:Path #js {:render identity}})
(def react-native-webview #js {:default {}})
(def react-native-audio-toolkit #js {:MediaStates {}})
(def net-info #js {})
@@ -207,7 +223,10 @@
:withTiming (fn [])
:withDelay (fn [])
:Easing #js {:bezier identity}
:Keyframe (fn [])})
:Keyframe (fn [])
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
(def react-native-gesture-handler #js {:default #js {}
:State #js {:BEGAN nil
:ACTIVE nil
@@ -284,6 +303,8 @@
(def shell-worklets #js {})
(def record-audio-worklets #js {})
;; Update i18n_resources.cljs
(defn mock [module]
(case module
@@ -331,6 +352,7 @@
"react-native-svg" react-native-svg
"../src/js/worklet_factory.js" worklet-factory
"../src/js/shell_worklets.js" shell-worklets
"../src/js/record_audio_worklets.js" record-audio-worklets
"./fleets.js" default-fleets
"./chats.js" default-chats
"@walletconnect/client" wallet-connect-client
@@ -0,0 +1,106 @@
(ns quo2.components.notifications.count-down-circle
(:require
[goog.string :as gstring]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[react-native.svg :as svg]
[reagent.core :as reagent]))
(defn- get-path-props
[size stroke-width rotation]
(let [half-size (/ size 2)
half-stroke-width (/ stroke-width 2)
arc-radius (- half-size half-stroke-width)
arc-diameter (* arc-radius 2)
rotation-indicator (if (= rotation :clockwise) "1,0" "0,1")
path-length (* js/Math.PI arc-diameter)
path (gstring/format
"m %s,%s a %s,%s 0 %s 0,%s a %s,%s 0 %s 0 ,-%s"
half-size
half-stroke-width
arc-radius
arc-radius
rotation-indicator
arc-diameter
arc-radius
arc-radius
rotation-indicator
arc-diameter)]
{:path path
:path-length path-length}))
(defn- linear-ease
[time start goal duration]
(if (zero? duration)
start
(-> time
(/ duration)
(* goal)
(+ start))))
(defn- get-start-at
[duration initial-remaining-time]
(cond (or (zero? duration) (= duration initial-remaining-time)) 0
(number? initial-remaining-time) (- duration initial-remaining-time)
:else 0))
(def ^:private themes
{:color {:light colors/neutral-80-opa-40
:dark colors/white-opa-40}})
(defn circle-timer
[{:keys [color duration size stroke-width trail-color rotation initial-remaining-time]}]
(let [rotation (or rotation :clockwise)
duration (or duration 4)
stroke-width (or stroke-width 1)
size (or size 9)
max-stroke-width (max stroke-width 0)
{:keys [path path-length]} (get-path-props size max-stroke-width rotation)
start-at (get-start-at duration initial-remaining-time)
elapsed-time (reagent/atom 0)
prev-frame-time (reagent/atom nil)
frame-request (reagent/atom nil)
display-time (reagent/atom start-at)
;; get elapsed frame time
swap-elapsed-time-each-frame (fn swap-elapsed-time-each-frame [frame-time]
(if (nil? @prev-frame-time)
(do (reset! prev-frame-time frame-time)
(reset! frame-request (js/requestAnimationFrame
swap-elapsed-time-each-frame)))
(let [delta (- (/ frame-time 1000)
(/ @prev-frame-time 1000))
current-elapsed (swap! elapsed-time + delta)
current-display-time (+ start-at current-elapsed)
completed? (>= current-display-time duration)]
(reset! display-time (if completed?
duration
current-display-time))
(when-not completed?
(reset! prev-frame-time frame-time)
(reset! frame-request (js/requestAnimationFrame
swap-elapsed-time-each-frame))))))]
(reagent/create-class
{:component-will-unmount #(js/cancelAnimationFrame @frame-request)
:reagent-render
(fn []
(reset! frame-request (js/requestAnimationFrame swap-elapsed-time-each-frame))
[rn/view
{:style {:position :relative
:width size
:height size}}
[svg/svg
{:view-box (str "0 0 " size " " size)
:width size
:height size}
[svg/path
{:d path :fill :none :stroke (or trail-color :transparent) :stroke-width stroke-width}]
(when-not (= @display-time duration)
[svg/path
{:d path
:fill :none
:stroke (or color (get-in themes [:color (theme/get-theme)]))
:stroke-linecap :square
:stroke-width stroke-width
:stroke-dasharray path-length
:stroke-dashoffset (linear-ease @display-time 0 path-length duration)}])]])})))
@@ -0,0 +1,82 @@
(ns quo2.components.notifications.toast
(:require
[i18n.i18n :as i18n]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.notifications.count-down-circle :as count-down-circle]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(def ^:private themes
{:container {:light {:background-color colors/white-opa-70}
:dark {:background-color colors/neutral-80-opa-70}}
:text {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:icon {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:action-container {:light {:background-color :colors/neutral-80-opa-5}
:dark {:background-color :colors/white-opa-5}}})
(defn- merge-theme-style
[component-key styles]
(merge (get-in themes [component-key (theme/get-theme)]) styles))
(defn toast-action-container
[{:keys [on-press style]} & children]
[rn/touchable-highlight {:on-press on-press}
[into
[rn/view
{:style (merge
{:flex-direction :row
:padding-vertical 3
:padding-horizontal 8
:align-items :center
:border-radius 8
:background-color (get-in themes
[:action-container (theme/get-theme)
:background-color])}
style)}]
children]])
(defn toast-undo-action
[duration on-press]
[toast-action-container {:on-press on-press}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
[i18n/label :undo]]])
(defn- toast-container
[{:keys [left middle right]}]
[rn/view {:style {:padding-left 12 :padding-right 12}}
[rn/view
{:style (merge-theme-style :container
{:flex-direction :row
:width "100%"
:margin :auto
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12})}
[rn/view {:style {:padding 2}} left]
[rn/view {:style {:padding 4 :flex 1}}
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
middle]]
(when right right)]])
(defn toast
[{:keys [icon icon-color text action undo-duration undo-on-press]}]
[toast-container
{:left (when icon
[icon/icon icon
{:container-style {:width 20 :height 20}
:color (or icon-color
(get-in themes [:icon (theme/get-theme) :color]))}])
:middle text
:right (if undo-duration
[toast-undo-action undo-duration undo-on-press]
action)}])
@@ -0,0 +1,212 @@
(ns quo2.components.record-audio.record-audio.style
(:require [quo2.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
(defn animated-circle [scale opacity color]
(reanimated/apply-animations-to-style
{:transform [{:scale scale}]
:opacity opacity}
{:width 56
:height 56
:border-width 1
:border-color color
:border-radius 28
:position :absolute
:justify-content :center
:align-items :center
:z-index 0}))
(defn record-button-big-container [translate-x translate-y opacity]
(reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}
{:translateX translate-x}]
:opacity opacity}
{:position :absolute
:bottom 0
:right 0
:width 96
:height 96
:align-items :center
:justify-content :center
:z-index 0}))
(defn record-button-big-body [button-color]
{:width 56
:height 56
:border-radius 28
:justify-content :center
:align-items :center
:background-color button-color
:overflow :hidden})
(defn record-button-big-red-overlay [red-overlay-opacity]
(reanimated/apply-animations-to-style
{:opacity red-overlay-opacity}
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0
:background-color colors/danger-50}))
(defn record-button-big-gray-overlay [gray-overlay-opacity]
(reanimated/apply-animations-to-style
{:opacity gray-overlay-opacity}
{:position :absolute
:top 0
:left 0
:right 0
:bottom 0
:background-color (colors/theme-colors colors/neutral-80-opa-5-opaque colors/neutral-80)}))
(defn record-button-big-icon-container [icon-opacity]
(reanimated/apply-animations-to-style
{:opacity icon-opacity}
{}))
(def stop-icon
{:width 13
:height 13
:border-radius 4
:background-color colors/white})
(defn send-button-container [opacity]
(reanimated/apply-animations-to-style
{:opacity opacity}
{:justify-content :center
:align-items :center
:position :absolute
:width 56
:height 56
:top 0
:right 20}))
(defn send-button-connector [opacity width height border-radius-first-half border-radius-second-half]
(reanimated/apply-animations-to-style
{:opacity opacity
:width width
:height height
:border-bottom-left-radius border-radius-second-half
:border-top-left-radius border-radius-first-half
:border-top-right-radius border-radius-first-half
:border-bottom-right-radius border-radius-second-half}
{:justify-content :center
:align-items :center
:align-self :center
:background-color colors/primary-50
:z-index 0}))
(defn send-button [translate-y opacity]
(reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]
:opacity opacity}
{:justify-content :center
:align-items :center
:background-color colors/primary-50
:width 32
:height 32
:border-radius 16
:position :absolute
:top 0
:right 32
:z-index 10}))
(def send-icon-container
{:z-index 10})
(defn lock-button-container [opacity]
(reanimated/apply-animations-to-style
{:opacity opacity}
{:transform [{:rotate "45deg"}]
:justify-content :center
:align-items :center
:position :absolute
:width 56
:height 56
:top 20
:left 20}))
(defn lock-button-connector [opacity width height border-radius-first-half border-radius-second-half]
(reanimated/apply-animations-to-style
{:opacity opacity
:width width
:height height
:border-bottom-left-radius border-radius-first-half
:border-top-left-radius border-radius-first-half
:border-top-right-radius border-radius-second-half
:border-bottom-right-radius border-radius-second-half}
{:justify-content :center
:align-items :center
:align-self :center
:background-color (colors/theme-colors colors/neutral-80-opa-5-opaque colors/neutral-80)
:overflow :hidden}))
(defn lock-button [translate-x-y opacity]
(reanimated/apply-animations-to-style
{:transform [{:translateX translate-x-y}
{:translateY translate-x-y}]
:opacity opacity}
{:width 32
:height 32
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/neutral-80-opa-5-opaque colors/neutral-80)
:border-radius 16
:position :absolute
:top 24
:left 24
:overflow :hidden
:z-index 12}))
(defn delete-button-container [opacity]
(reanimated/apply-animations-to-style
{:opacity opacity}
{:justify-content :center
:align-items :center
:position :absolute
:width 56
:height 56
:bottom 20
:left 0}))
(defn delete-button-connector [opacity width height border-radius-first-half border-radius-second-half]
(reanimated/apply-animations-to-style
{:opacity opacity
:width width
:height height
:border-bottom-left-radius border-radius-first-half
:border-top-left-radius border-radius-first-half
:border-top-right-radius border-radius-second-half
:border-bottom-right-radius border-radius-second-half}
{:justify-content :center
:align-items :center
:align-self :center
:background-color colors/danger-50
:z-index 0}))
(defn delete-button [translate-x opacity]
(reanimated/apply-animations-to-style
{:transform [{:translateX translate-x}]
:opacity opacity}
{:width 32
:height 32
:justify-content :center
:align-items :center
:background-color colors/danger-50
:border-radius 16
:position :absolute
:top 76
:left 0
:z-index 11}))
(defn record-button-container [opacity]
(reanimated/apply-animations-to-style
{:opacity opacity}
{:margin-bottom 32
:margin-right 32}))
(def input-container
{:width 140
:height 140
:align-items :flex-end
:justify-content :flex-end})
@@ -0,0 +1,553 @@
(ns quo2.components.record-audio.record-audio.view
(:require [quo.react :refer [memo effect!]]
[react-native.core :as rn]
[quo2.foundations.colors :as colors]
[quo2.components.icon :as icons]
[quo2.components.buttons.button :as button]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[cljs-bean.core :as bean]
[quo2.components.record-audio.record-audio.style :as style]
[status-im.utils.utils :as utils]
[oops.core :as oops]))
(def ^:private scale-to-each 1.8)
(def ^:private scale-to-total 2.6)
(def ^:private scale-padding 0.16)
(def ^:private opacity-from-lock 1)
(def ^:private opacity-from-default 0.5)
(def ^:private signal-anim-duration 3900)
(def ^:private signal-anim-duration-2 1950)
(def ^:private animated-ring
(reagent/adapt-react-class
(memo
(fn [props]
(let [{:keys [scale opacity color]} (bean/bean props)]
(reagent/as-element
[reanimated/view {:style (style/animated-circle scale opacity color)}]))))))
(def ^:private record-button-area-big
{:width 56
:height 56
:x 64
:y 64})
(def ^:private record-button-area
{:width 48
:height 48
:x 68
:y 68})
(defn- delete-button-area [active?]
{:width (if active? 72 82)
:height 56
:x (if active? -16 -32)
:y (if active? 64 70)})
(defn- lock-button-area [active?]
{:width (if active? 72 100)
:height (if active? 72 102)
:x -32
:y -32})
(defn- send-button-area [active?]
{:width 56
:height (if active? 72 92)
:x 68
:y (if active? -16 -32)})
(defn- touch-inside-area? [{:keys [location-x location-y ignore-min-y? ignore-max-y? ignore-min-x? ignore-max-x?]}
{:keys [width height x y]}]
(let [max-x (+ x width)
max-y (+ y height)]
(and
(and
(or ignore-min-x? (>= location-x x))
(or ignore-max-x? (<= location-x max-x)))
(and
(or ignore-min-y? (>= location-y y))
(or ignore-max-y? (<= location-y max-y))))))
(def record-audio-worklets (js/require "../src/js/record_audio_worklets.js"))
(defn- ring-scale [scale substract]
(.ringScale ^js record-audio-worklets
scale
substract))
(defn- record-button-big [recording? ready-to-send? ready-to-lock? ready-to-delete? record-button-is-animating? record-button-at-initial-position? locked? reviewing-audio? recording-timer recording-length-ms clear-timeout touch-active?]
[:f>
(fn []
(let [scale (reanimated/use-shared-value 1)
opacity (reanimated/use-shared-value 0)
opacity-from (if @ready-to-lock? opacity-from-lock opacity-from-default)
animations (map
(fn [index]
(let [ring-scale (ring-scale scale (* scale-padding index))]
{:scale ring-scale
:opacity (reanimated/interpolate ring-scale [1 scale-to-each] [opacity-from 0])}))
(range 0 5))
rings-color (cond
@ready-to-lock? (colors/theme-colors colors/neutral-80-opa-5-opaque colors/neutral-80)
@ready-to-delete? colors/danger-50
:else colors/primary-50)
translate-y (reanimated/use-shared-value 0)
translate-x (reanimated/use-shared-value 0)
button-color colors/primary-50
icon-color (if (and (not (colors/dark?)) @ready-to-lock?) colors/black colors/white)
icon-opacity (reanimated/use-shared-value 1)
red-overlay-opacity (reanimated/use-shared-value 0)
gray-overlay-opacity (reanimated/use-shared-value 0)
complete-animation (fn []
(cond
(and @ready-to-lock? (not @record-button-is-animating?))
(do
(reset! locked? true)
(reset! ready-to-lock? false))
(and (not @locked?) (not @reviewing-audio?))
(do
(reset! recording? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(reset! ready-to-lock? false)
(utils/clear-interval @recording-timer)
(reset! recording-length-ms 0))))
start-animation (fn []
(reanimated/set-shared-value opacity 1)
(reanimated/animate-shared-value-with-timing scale 2.6 signal-anim-duration :linear)
;; TODO: Research if we can implement this with withSequence method from Reanimated 2
;; GitHub issue [#14561]: https://github.com/status-im/status-mobile/issues/14561
(reset! clear-timeout (utils/set-timeout #(do (reanimated/set-shared-value scale scale-to-each)
(reanimated/animate-shared-value-with-delay-repeat scale scale-to-total signal-anim-duration-2 :linear 0 -1))
signal-anim-duration)))
stop-animation (fn []
(reanimated/set-shared-value opacity 0)
(reanimated/cancel-animation scale)
(reanimated/set-shared-value scale 1)
(when @clear-timeout (utils/clear-timeout @clear-timeout)))
start-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(reanimated/animate-shared-value-with-timing translate-y -64 250 :easing1)
(reanimated/animate-shared-value-with-delay icon-opacity 0 33.33 :linear 76.66)
(utils/set-timeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-y-animation (fn []
(reanimated/animate-shared-value-with-timing translate-y 0 300 :easing1)
(reanimated/animate-shared-value-with-timing icon-opacity 1 500 :linear)
(utils/set-timeout (fn [] (reset! record-button-at-initial-position? true)) 500))
start-x-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(reanimated/animate-shared-value-with-timing translate-x -64 250 :easing1)
(reanimated/animate-shared-value-with-delay icon-opacity 0 33.33 :linear 76.66)
(reanimated/animate-shared-value-with-timing red-overlay-opacity 1 33.33 :linear)
(utils/set-timeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
250))
reset-x-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x 0 300 :easing1)
(reanimated/animate-shared-value-with-timing icon-opacity 1 500 :linear)
(reanimated/animate-shared-value-with-timing red-overlay-opacity 0 100 :linear)
(utils/set-timeout (fn [] (reset! record-button-at-initial-position? true)) 500))
start-x-y-animation (fn []
(reset! record-button-at-initial-position? false)
(reset! record-button-is-animating? true)
(reanimated/animate-shared-value-with-timing translate-y -44 200 :easing1)
(reanimated/animate-shared-value-with-timing translate-x -44 200 :easing1)
(reanimated/animate-shared-value-with-delay icon-opacity 0 33.33 :linear 33.33)
(reanimated/animate-shared-value-with-timing gray-overlay-opacity 1 33.33 :linear)
(utils/set-timeout (fn []
(reset! record-button-is-animating? false)
(when-not @touch-active? (complete-animation)))
200))
reset-x-y-animation (fn []
(reanimated/animate-shared-value-with-timing translate-y 0 300 :easing1)
(reanimated/animate-shared-value-with-timing translate-x 0 300 :easing1)
(reanimated/animate-shared-value-with-timing icon-opacity 1 500 :linear)
(reanimated/animate-shared-value-with-timing gray-overlay-opacity 0 800 :linear)
(utils/set-timeout (fn [] (reset! record-button-at-initial-position? true)) 800))]
(effect! #(cond
@recording?
(start-animation)
(not @ready-to-lock?)
(stop-animation))
[@recording?])
(effect! #(if @ready-to-lock?
(start-x-y-animation)
(reset-x-y-animation))
[@ready-to-lock?])
(effect! #(if @ready-to-send?
(start-y-animation)
(reset-y-animation))
[@ready-to-send?])
(effect! #(if @ready-to-delete?
(start-x-animation)
(reset-x-animation))
[@ready-to-delete?])
[reanimated/view {:style (style/record-button-big-container translate-x translate-y opacity)
:pointer-events :none}
[:<>
(map-indexed
(fn [id animation]
^{:key id}
[animated-ring {:scale (:scale animation)
:opacity (:opacity animation)
:color rings-color}])
animations)]
[rn/view {:style (style/record-button-big-body button-color)}
[reanimated/view {:style (style/record-button-big-red-overlay red-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-gray-overlay gray-overlay-opacity)}]
[reanimated/view {:style (style/record-button-big-icon-container icon-opacity)}
(if @locked?
[rn/view {:style style/stop-icon}]
[icons/icon :i/audio {:color icon-color}])]]]))])
(defn- send-button [recording? ready-to-send? reviewing-audio?]
[:f>
(fn []
(let [opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value 20)
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 12)
height (reanimated/use-shared-value 24)
border-radius-first-half (reanimated/use-shared-value 16)
border-radius-second-half (reanimated/use-shared-value 8)
start-y-animation (fn []
(reanimated/animate-shared-value-with-delay translate-y 12 50 :linear 133.33)
(reanimated/animate-shared-value-with-delay connector-opacity 1 0 :easing1 93.33)
(reanimated/animate-shared-value-with-delay width 56 83.33 :easing1 80)
(reanimated/animate-shared-value-with-delay height 56 83.33 :easing1 80)
(reanimated/animate-shared-value-with-delay border-radius-first-half 28 83.33 :easing1 80)
(reanimated/animate-shared-value-with-delay border-radius-second-half 28 83.33 :easing1 80))
reset-y-animation (fn []
(reanimated/animate-shared-value-with-timing translate-y 0 100 :linear)
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 12)
(reanimated/set-shared-value height 24)
(reanimated/set-shared-value border-radius-first-half 16)
(reanimated/set-shared-value border-radius-second-half 8))
fade-in-animation (fn []
(reanimated/animate-shared-value-with-timing translate-y 0 200 :linear)
(reanimated/animate-shared-value-with-timing opacity 1 200 :linear))
fade-out-animation (fn []
(reanimated/animate-shared-value-with-timing translate-y (if @reviewing-audio? 76 20) 200 :linear)
(when-not @reviewing-audio? (reanimated/animate-shared-value-with-timing opacity 0 200 :linear))
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 24)
(reanimated/set-shared-value height 12)
(reanimated/set-shared-value border-radius-first-half 8)
(reanimated/set-shared-value border-radius-second-half 16))
fade-out-reset-animation (fn []
(reanimated/animate-shared-value-with-timing opacity 0 200 :linear)
(reanimated/animate-shared-value-with-delay translate-y 20 0 :linear 200)
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 24)
(reanimated/set-shared-value height 12)
(reanimated/set-shared-value border-radius-first-half 8)
(reanimated/set-shared-value border-radius-second-half 16))]
(effect! #(if @recording?
(fade-in-animation)
(fade-out-animation))
[@recording?])
(effect! #(when-not @reviewing-audio?
(fade-out-reset-animation))
[@reviewing-audio?])
(effect! #(cond
@ready-to-send?
(start-y-animation)
@recording? (reset-y-animation))
[@ready-to-send?])
[:<>
[reanimated/view {:style (style/send-button-container opacity)}
[reanimated/view {:style (style/send-button-connector connector-opacity width height border-radius-first-half border-radius-second-half)}]]
[reanimated/view {:style (style/send-button translate-y opacity)
:pointer-events :none}
[icons/icon :i/arrow-up {:color colors/white
:size 20
:container-style style/send-icon-container}]]]))])
(defn- lock-button [recording? ready-to-lock? locked?]
[:f>
(fn []
(let [translate-x-y (reanimated/use-shared-value 20)
opacity (reanimated/use-shared-value 0)
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 24)
height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-y-animation (fn []
(reanimated/animate-shared-value-with-delay translate-x-y 8 50 :linear 116.66)
(reanimated/animate-shared-value-with-delay connector-opacity 1 0 :easing1 80)
(reanimated/animate-shared-value-with-delay width 56 83.33 :easing1 63.33)
(reanimated/animate-shared-value-with-delay height 56 83.33 :easing1 63.33)
(reanimated/animate-shared-value-with-delay border-radius-first-half 28 83.33 :easing1 63.33)
(reanimated/animate-shared-value-with-delay border-radius-second-half 28 83.33 :easing1 63.33))
reset-x-y-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x-y 0 100 :linear)
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 24)
(reanimated/set-shared-value height 12)
(reanimated/set-shared-value border-radius-first-half 8)
(reanimated/set-shared-value border-radius-second-half 16))
fade-in-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x-y 0 220 :linear)
(reanimated/animate-shared-value-with-timing opacity 1 220 :linear))
fade-out-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x-y 20 200 :linear)
(reanimated/animate-shared-value-with-timing opacity 0 200 :linear)
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 24)
(reanimated/set-shared-value height 12)
(reanimated/set-shared-value border-radius-first-half 8)
(reanimated/set-shared-value border-radius-second-half 16))]
(effect! #(if @recording?
(fade-in-animation)
(fade-out-animation))
[@recording?])
(effect! #(cond
@ready-to-lock?
(start-x-y-animation)
(and @recording? (not @locked?))
(reset-x-y-animation))
[@ready-to-lock?])
(effect! #(if @locked?
(fade-out-animation)
(reset-x-y-animation))
[@locked?])
[:<>
[reanimated/view {:style (style/lock-button-container opacity)}
[reanimated/view {:style (style/lock-button-connector connector-opacity width height border-radius-first-half border-radius-second-half)}]]
[reanimated/view {:style (style/lock-button translate-x-y opacity)
:pointer-events :none}
[icons/icon (if @ready-to-lock? :i/locked :i/unlocked)
{:color (colors/theme-colors colors/black colors/white)
:size 20}]]]))])
(defn- delete-button [recording? ready-to-delete?]
[:f>
(fn []
(let [opacity (reanimated/use-shared-value 0)
translate-x (reanimated/use-shared-value 20)
connector-opacity (reanimated/use-shared-value 0)
width (reanimated/use-shared-value 24)
height (reanimated/use-shared-value 12)
border-radius-first-half (reanimated/use-shared-value 8)
border-radius-second-half (reanimated/use-shared-value 8)
start-x-animation (fn []
(reanimated/animate-shared-value-with-delay translate-x 12 50 :linear 133.33)
(reanimated/animate-shared-value-with-delay connector-opacity 1 0 :easing1 93.33)
(reanimated/animate-shared-value-with-delay width 56 83.33 :easing1 80)
(reanimated/animate-shared-value-with-delay height 56 83.33 :easing1 80)
(reanimated/animate-shared-value-with-delay border-radius-first-half 28 83.33 :easing1 80)
(reanimated/animate-shared-value-with-delay border-radius-second-half 28 83.33 :easing1 80))
reset-x-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x 0 100 :linear)
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 24)
(reanimated/set-shared-value height 12)
(reanimated/set-shared-value border-radius-first-half 8)
(reanimated/set-shared-value border-radius-second-half 16))
fade-in-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x 0 200 :linear)
(reanimated/animate-shared-value-with-timing opacity 1 200 :linear))
fade-out-animation (fn []
(reanimated/animate-shared-value-with-timing translate-x 20 200 :linear)
(reanimated/animate-shared-value-with-timing opacity 0 200 :linear)
(reanimated/set-shared-value connector-opacity 0)
(reanimated/set-shared-value width 24)
(reanimated/set-shared-value height 12)
(reanimated/set-shared-value border-radius-first-half 8)
(reanimated/set-shared-value border-radius-second-half 16))]
(effect! #(if @recording?
(fade-in-animation)
(fade-out-animation))
[@recording?])
(effect! #(cond
@ready-to-delete?
(start-x-animation)
@recording?
(reset-x-animation))
[@ready-to-delete?])
[:<>
[reanimated/view {:style (style/delete-button-container opacity)}
[reanimated/view {:style (style/delete-button-connector connector-opacity width height border-radius-first-half border-radius-second-half)}]]
[reanimated/view {:style (style/delete-button translate-x opacity)
:pointer-events :none}
[icons/icon :i/delete {:color colors/white
:size 20}]]]))])
(defn- record-button [recording? reviewing-audio?]
[:f>
(fn []
(let [opacity (reanimated/use-shared-value 1)
show-animation #(reanimated/set-shared-value opacity 1)
hide-animation #(reanimated/set-shared-value opacity 0)]
(effect! #(if (or @recording? @reviewing-audio?)
(hide-animation)
(show-animation))
[@recording? @reviewing-audio?])
[reanimated/view {:style (style/record-button-container opacity)}
[button/button {:type :outline
:size 32
:width 32
:accessibility-label :mic-button}
[icons/icon :i/audio {:color (colors/theme-colors colors/neutral-100 colors/white)}]]]))])
(defn input-view []
[:f>
(fn []
(let [recording? (reagent/atom false)
locked? (reagent/atom false)
ready-to-send? (reagent/atom false)
ready-to-lock? (reagent/atom false)
ready-to-delete? (reagent/atom false)
reviewing-audio? (reagent/atom false)
clear-timeout (atom nil)
record-button-at-initial-position? (atom true)
record-button-is-animating? (atom false)
touch-active? (atom false)
recording-timer (atom nil)
recording-length-ms (atom 0)
on-start-should-set-responder (fn [^js e]
(when-not @locked?
(let [pressed-record-button? (touch-inside-area?
{:location-x (oops/oget e "nativeEvent.locationX")
:location-y (oops/oget e "nativeEvent.locationY")
:ignore-min-y? false
:ignore-max-y? false
:ignore-min-x? false
:ignore-max-x? false}
record-button-area)]
(when-not @reviewing-audio?
(reset! recording? pressed-record-button?)
(when pressed-record-button?
;; TODO: By now we just track recording length, we need to add actual audio recording logic
;; GitHub issue [#14558]: https://github.com/status-im/status-mobile/issues/14558
(reset! recording-timer (utils/set-interval #(reset! recording-length-ms (+ @recording-length-ms 500)) 500))))
(reset! touch-active? true)))
true)
on-responder-move (fn [^js e]
(when-not @locked?
(let [location-x (oops/oget e "nativeEvent.locationX")
location-y (oops/oget e "nativeEvent.locationY")
page-x (oops/oget e "nativeEvent.pageX")
page-y (oops/oget e "nativeEvent.pageY")
moved-to-send-button? (touch-inside-area?
{:location-x location-x
:location-y location-y
:ignore-min-y? true
:ignore-max-y? false
:ignore-min-x? false
:ignore-max-x? true}
(send-button-area @ready-to-send?))
moved-to-delete-button? (touch-inside-area?
{:location-x location-x
:location-y location-y
:ignore-min-y? false
:ignore-max-y? true
:ignore-min-x? true
:ignore-max-x? false}
(delete-button-area @ready-to-delete?))
moved-to-lock-button? (touch-inside-area?
{:location-x location-x
:location-y location-y
:ignore-min-y? false
:ignore-max-y? false
:ignore-min-x? false
:ignore-max-x? false}
(lock-button-area @ready-to-lock?))
moved-to-record-button? (and
(touch-inside-area?
{:location-x location-x
:location-y location-y
:ignore-min-y? false
:ignore-max-y? false
:ignore-min-x? false
:ignore-max-x? false}
record-button-area-big)
(not= location-x page-x)
(not= location-y page-y))]
(cond
(and
(or
(and moved-to-record-button? @ready-to-lock?)
(and (not @locked?) moved-to-lock-button? @record-button-at-initial-position?))
(not @ready-to-delete?)
(not @ready-to-send?)
@recording?) (reset! ready-to-lock? moved-to-lock-button?)
(and
(or
(and moved-to-record-button? @ready-to-delete?)
(and moved-to-delete-button? @record-button-at-initial-position?))
(not @ready-to-lock?)
(not @ready-to-send?)
@recording?) (reset! ready-to-delete? moved-to-delete-button?)
(and
(or
(and moved-to-record-button? @ready-to-send?)
(and moved-to-send-button? @record-button-at-initial-position?))
(not @ready-to-lock?)
(not @ready-to-delete?)
@recording?) (reset! ready-to-send? moved-to-send-button?)))))
on-responder-release (fn [^js e]
(let [on-record-button? (touch-inside-area?
{:location-x (oops/oget e "nativeEvent.locationX")
:location-y (oops/oget e "nativeEvent.locationY")
:ignore-min-y? false
:ignore-max-y? false
:ignore-min-x? false
:ignore-max-x? false}
(if @reviewing-audio? record-button-area record-button-area-big))]
(cond
(and @reviewing-audio? on-record-button?)
(reset! reviewing-audio? false)
(and @ready-to-lock? (not @record-button-is-animating?))
(do
(reset! locked? true)
(reset! ready-to-lock? false))
(and (not @reviewing-audio?) on-record-button?)
(do
(when (>= @recording-length-ms 500) (reset! reviewing-audio? true))
(reset! locked? false)
(reset! recording? false)
(reset! ready-to-lock? false)
(utils/clear-interval @recording-timer)
(reset! recording-length-ms 0))
(and (not @locked?) (not @reviewing-audio?) (not @record-button-is-animating?))
(do
(reset! recording? false)
(reset! ready-to-send? false)
(reset! ready-to-delete? false)
(reset! ready-to-lock? false)
(utils/clear-interval @recording-timer)
(reset! recording-length-ms 0))))
(reset! touch-active? false))]
(fn []
[rn/view {:style style/input-container
:pointer-events :box-only
:on-start-should-set-responder on-start-should-set-responder
:on-responder-move on-responder-move
:on-responder-release on-responder-release}
[delete-button recording? ready-to-delete?]
[lock-button recording? ready-to-lock? locked?]
[send-button recording? ready-to-send? reviewing-audio?]
[record-button-big
recording?
ready-to-send?
ready-to-lock?
ready-to-delete?
record-button-is-animating?
record-button-at-initial-position?
locked?
reviewing-audio?
recording-timer
recording-length-ms
clear-timeout
touch-active?]
[record-button recording? reviewing-audio?]])))])
@@ -0,0 +1,63 @@
(ns quo2.components.settings.privacy-option
(:require [react-native.core :as rn]
[quo2.components.icon :as icons]
[quo2.components.selectors.selectors :as selectors]
[quo2.components.settings.style :as style]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]))
(defn- bullet
[]
[rn/view {:style style/bullet-container}
[rn/view {:style (style/bullet)}]])
(defn- unordered-list
[container-style list-items]
[rn/view {:style (merge style/list-container container-style)}
(for [item list-items]
^{:key (hash item)}
[rn/view {:style style/list-item}
[bullet]
[text/text {:size :paragraph-2} item]])])
(defn- card-footer
[{:keys [active? label on-toggle]}]
[rn/touchable-without-feedback
[rn/view {:style (style/card-footer)}
[rn/view {:style style/card-footer-label-container}
[text/text {:size :paragraph-2} label]]
[rn/view {:style style/card-footer-toggle-container}
[selectors/toggle {:disabled? (not active?)
:on-change on-toggle}]]]])
(defn- selection-indicator
[active?]
[rn/view {:style (style/selection-indicator-container active?)}
[rn/view {:style (style/selection-indicator active?)}]])
(defn- card-header
[{:keys [icon label active?]}]
[rn/view {:style style/card-header-container}
[icons/icon icon {:size 20
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]
[rn/view {:style style/card-header-label-container}
[text/text {:weight :semi-bold} label]]
[selection-indicator active?]])
(defn card
[{:keys [active? header footer list-items icon on-select on-toggle]
:or {icon :i/world
active? false}}]
[rn/touchable-without-feedback
{:on-press on-select
:accessibility-label :privacy-option-card
:testID :privacy-option-card}
[rn/view (style/privacy-option-card active?)
[card-header {:active? active?
:icon icon
:label header}]
[unordered-list (when-not footer {:margin-bottom 8}) list-items]
(when footer
[card-footer {:active? active?
:label footer
:on-toggle on-toggle}])]])
+93
View File
@@ -0,0 +1,93 @@
(ns quo2.components.settings.style
(:require [quo2.foundations.colors :as colors]))
(def bullet-container
{:width 20
:height 20
:margin-right 8
:align-self :flex-start})
(defn bullet
[]
{:background-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
:border-radius 100
:width 8
:height 8
:position :absolute
:left 6
:top 6})
(def list-container
{:margin-right 12})
(def list-item
{:flex 1
:flex-direction :row
:align-items :center
:padding-vertical 6
:padding-horizontal 12})
(defn selection-indicator-container
[active?]
{:height 20
:width 20
:border-radius 20
:border-width 1
:border-color (if active?
(colors/theme-colors colors/primary-50 colors/primary-60)
(colors/theme-colors colors/neutral-20 colors/neutral-80))})
(defn selection-indicator
[active?]
{:margin-left :auto
:height 14
:width 14
:background-color (if active?
(colors/theme-colors colors/primary-50 colors/primary-60)
(colors/theme-colors colors/white-opa-40 colors/neutral-80-opa-40))
:border-radius 20
:margin-right :auto
:margin-top :auto
:margin-bottom :auto})
(def card-footer-label-container
{:flex 0.9
:margin-left 16})
(def card-footer-toggle-container
{:flex 0.1
:margin-horizontal 12
:align-self :center})
(defn card-footer
[]
{:flex 1
:flex-direction :row
:justify-content :space-between
:margin-horizontal 12
:margin-top 8
:margin-bottom 12
:padding-vertical 12
:border-radius 12
:border-width 1
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80)})
(def card-header-container
{:flex-direction :row
:align-items :center
:padding-top 12
:padding-bottom 8
:padding-horizontal 12})
(def card-header-label-container
{:flex 1
:margin-left 4})
(defn privacy-option-card
[active?]
{:border-radius 16
:border-width 1
:border-color (if active?
(colors/theme-colors colors/primary-50 colors/primary-60)
(colors/theme-colors colors/neutral-10 colors/neutral-80))})
+9 -1
View File
@@ -36,14 +36,18 @@
quo2.components.tags.tags
quo2.components.tags.context-tags
quo2.components.tabs.tabs
quo2.components.notifications.toast
quo2.components.tabs.account-selector
quo2.components.navigation.floating-shell-button
quo2.components.tags.status-tags
quo2.components.navigation.page-nav
quo2.components.selectors.disclaimer
quo2.components.selectors.selectors
quo2.components.loaders.skeleton))
quo2.components.settings.privacy-option
quo2.components.loaders.skeleton
quo2.components.notifications.count-down-circle))
(def toast quo2.components.notifications.toast/toast)
(def button quo2.components.buttons.button/button)
(def dynamic-button quo2.components.buttons.dynamic-button/dynamic-button)
(def text quo2.components.markdown.text/text)
@@ -106,3 +110,7 @@
(def activity-log quo2.components.notifications.activity-log.view/view)
(def info-count quo2.components.notifications.info-count/info-count)
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
(def count-down-circle quo2.components.notifications.count-down-circle/circle-timer)
;;;; SETTINGS
(def privacy-option quo2.components.settings.privacy-option/card)
+25
View File
@@ -13,6 +13,20 @@
(let [rgb (string/split value #",")]
(str (string/join "," (butlast rgb)) "," opacity ")")))))
(defn- alpha-opaque [value opacity]
(when value
(if (string/starts-with? value "#")
(let [hex (string/replace value #"#" "")
r (- 255 (* opacity (- 255 (js/parseInt (subs hex 0 2) 16))))
g (- 255 (* opacity (- 255 (js/parseInt (subs hex 2 4) 16))))
b (- 255 (* opacity (- 255 (js/parseInt (subs hex 4 6) 16))))]
(str "rgb(" r "," g "," b ")"))
(let [rgb (string/split value #",")
r (- 255 (* opacity (- 255 (get rgb 0))))
g (- 255 (* opacity (- 255 (get rgb 1))))
b (- 255 (* opacity (- 255 (get rgb 2))))]
(str "rgb(" r "," g "," b ")")))))
(def theme-alpha
(memoize
(fn
@@ -49,6 +63,7 @@
;;80 with transparency
(def neutral-80-opa-5 (alpha neutral-80 0.05))
(def neutral-80-opa-10 (alpha neutral-80 0.1))
(def neutral-80-opa-15 (alpha neutral-80 0.15))
(def neutral-80-opa-20 (alpha neutral-80 0.2))
(def neutral-80-opa-30 (alpha neutral-80 0.3))
(def neutral-80-opa-40 (alpha neutral-80 0.4))
@@ -67,11 +82,16 @@
(def neutral-95-opa-95 (alpha neutral-95 0.95))
;;100 with transparency
(def neutral-100-opa-0 (alpha neutral-100 0))
(def neutral-100-opa-60 (alpha neutral-100 0.6))
(def neutral-100-opa-70 (alpha neutral-100 0.7))
(def neutral-100-opa-80 (alpha neutral-100 0.8))
(def neutral-100-opa-90 (alpha neutral-100 0.9))
(def neutral-100-opa-95 (alpha neutral-100 0.95))
(def neutral-100-opa-100 (alpha neutral-100 1))
;;80 with transparency opaque
(def neutral-80-opa-5-opaque (alpha-opaque neutral-80 0.05))
;;;;White
@@ -91,6 +111,11 @@
(def white-opa-90 (alpha white 0.9))
(def white-opa-95 (alpha white 0.95))
;;;;Black
;;Solid
(def black "#000000")
;;;;Primary
;;Solid
+19 -1
View File
@@ -1,9 +1,12 @@
(ns react-native.core
(:require [reagent.core :as reagent]
(:require ["react" :as react]
["react-native" :as react-native]
[cljs-bean.core :as bean]
["@react-native-community/blur" :as blur]
[oops.core :as oops]
[react-native.flat-list :as flat-list]
[react-native.section-list :as section-list]
[reagent.core :as reagent]
[react-native.platform :as platform]))
(def app-state ^js (.-AppState ^js react-native))
@@ -57,6 +60,9 @@
(def status-bar (.-StatusBar ^js react-native))
(defn status-bar-height []
(.-currentHeight ^js status-bar))
(defn hw-back-add-listener [callback]
(.addEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
@@ -70,3 +76,15 @@
(merge (when platform/ios? {:behavior :padding})
props)]
children))
(defn use-effect
([effect] (use-effect effect []))
([effect deps]
(react/useEffect effect (bean/->js deps))))
(def use-ref react/useRef)
(defn use-effect-once [effect] (use-effect effect))
(defn use-unmount [f]
(let [fn-ref (use-ref f)]
(oops/oset! fn-ref "current" f)
(use-effect-once (fn [] #((oops/oget fn-ref "current"))))))
+33 -4
View File
@@ -1,10 +1,15 @@
(ns react-native.reanimated
(:require ["react-native" :as rn]
[reagent.core :as reagent]
[clojure.string :as string]
["react-native-linear-gradient" :default LinearGradient]
["react-native-reanimated" :default reanimated
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe)]))
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe cancelAnimation SlideInUp SlideOutUp LinearTransition)]
[clojure.string :as string]
[reagent.core :as reagent]))
;; Animations
(def slide-in-up-animation SlideInUp)
(def slide-out-up-animation SlideOutUp)
(def linear-transition LinearTransition)
;; Animated Components
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
@@ -25,6 +30,7 @@
(def with-spring withSpring)
(def key-frame Keyframe)
(def with-repeat withRepeat)
(def cancel-animation cancelAnimation)
;; Easings
(def bezier (.-bezier ^js Easing))
@@ -54,6 +60,12 @@
;; Worklets
(def worklet-factory (js/require "../src/js/worklet_factory.js"))
(defn interpolate [shared-value input-range output-range]
(.interpolateValue ^js worklet-factory
shared-value
(clj->js input-range)
(clj->js output-range)))
;;;; Component Animations
;; kebab-case styles are not working for worklets
@@ -75,4 +87,21 @@
(defn animate-shared-value-with-repeat [anim val duration easing number-of-repetitions reverse?]
(set-shared-value anim (with-repeat (with-timing val (js-obj "duration" duration
"easing" (get easings easing))) number-of-repetitions reverse?)))
"easing" (get easings easing))) number-of-repetitions reverse?)))
(defn animate-shared-value-with-delay-repeat
([anim val duration easing delay number-of-repetitions]
(animate-shared-value-with-delay-repeat anim val duration easing delay number-of-repetitions false))
([anim val duration easing delay number-of-repetitions reverse?]
(set-shared-value anim
(with-delay delay
(with-repeat
(with-timing val
#js {:duration duration
:easing (get easings easing)})
number-of-repetitions reverse?)))))
(defn animate-shared-value-with-spring [anim val {:keys [mass stiffness damping]}]
(set-shared-value anim (with-spring val (js-obj "mass" mass
"damping" damping
"stiffness" stiffness))))
+1 -1
View File
@@ -7,7 +7,7 @@
(defn consumer [component]
[consumer-raw
(fn [insets]
(fn [^js insets]
(reagent/as-element
[component (js->clj insets :keywordize-keys true)]))])
View File
+7
View File
@@ -0,0 +1,7 @@
(ns react-native.svg
(:require
["react-native-svg" :as Svg]
[reagent.core :as reagent]))
(def svg (reagent/adapt-react-class Svg/default))
(def path (reagent/adapt-react-class Svg/Path))
+27 -25
View File
@@ -1,19 +1,19 @@
(ns status-im.add-new.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im.chat.models :as chat]
[status-im.contact.core :as contact]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.add-new.db :as db]
[status-im.ethereum.stateofus :as stateofus]
[status-im.i18n.i18n :as i18n]
[status-im.router.core :as router]
[status-im.utils.db :as utils.db]
[status-im.utils.random :as random]
[status-im.utils.utils :as utils]
[status-im.utils.fx :as fx]
[status-im.chat.models :as chat]
[status-im.i18n.i18n :as i18n]
[status-im.contact.core :as contact]
[status-im.router.core :as router]
[status-im2.navigation.events :as navigation]
[status-im.ethereum.stateofus :as stateofus]
[status-im.utils.db :as utils.db]))
[utils.re-frame :as rf]))
(re-frame/reg-fx
:resolve-public-key
@@ -24,19 +24,19 @@
;;NOTE we want to handle only last resolve
(def resolve-last-id (atom nil))
(fx/defn new-chat-set-new-identity
(rf/defn new-chat-set-new-identity
{:events [:new-chat/set-new-identity]}
[{db :db} new-identity-raw new-ens-name id]
(let [ens-error (and (= new-identity-raw "0x") (not (string/blank? new-ens-name)))]
(when (or (not id) (= id @resolve-last-id))
(if ens-error
{:db (assoc-in db [:contacts/new-identity :state] :error)}
(let [new-identity (utils/safe-trim new-identity-raw)
(let [new-identity (utils/safe-trim new-identity-raw)
is-public-key? (and (string? new-identity)
(utils.db/valid-public-key? new-identity))
is-ens? (and (not is-public-key?)
(ens/valid-eth-name-prefix? new-identity))
error (db/validate-pub-key db new-identity)]
is-ens? (and (not is-public-key?)
(ens/valid-eth-name-prefix? new-identity))
error (db/validate-pub-key db new-identity)]
(reset! resolve-last-id nil)
(merge {:db (assoc db
:contacts/new-identity
@@ -61,25 +61,27 @@
new-identity
@resolve-last-id])}})))))))
(fx/defn clear-new-identity
(rf/defn clear-new-identity
{:events [::clear-new-identity ::new-chat-focus]}
[{:keys [db]}]
{:db (dissoc db :contacts/new-identity)})
(fx/defn qr-code-handled
(rf/defn qr-code-handled
{:events [::qr-code-handled]}
[{:keys [db] :as cofx} {:keys [type public-key chat-id data ens-name]} {:keys [new-contact? nickname] :as opts}]
(let [public-key? (and (string? data)
(string/starts-with? data "0x"))
chat-key (cond
(= type :private-chat) chat-id
(= type :contact) public-key
(and (= type :undefined)
public-key?) data)
[{:keys [db] :as cofx} {:keys [type public-key chat-id data ens-name]}
{:keys [new-contact? nickname] :as opts}]
(let [public-key? (and (string? data)
(string/starts-with? data "0x"))
chat-key (cond
(= type :private-chat) chat-id
(= type :contact) public-key
(and (= type :undefined)
public-key?)
data)
validation-result (db/validate-pub-key db chat-key)]
(if-not validation-result
(if new-contact?
(fx/merge cofx
(rf/merge cofx
(contact/add-contact chat-key nickname ens-name)
(navigation/navigate-to-cofx :contacts-list {}))
(chat/start-chat cofx chat-key ens-name))
@@ -91,7 +93,7 @@
(i18n/label :t/can-not-add-yourself))
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :chat-stack])}})))
(fx/defn qr-code-scanned
(rf/defn qr-code-scanned
{:events [:contact/qr-code-scanned]}
[{:keys [db]} data opts]
{::router/handle-uri {:chain (ethereum/chain-keyword db)
+6 -6
View File
@@ -1,23 +1,23 @@
(ns status-im.backup.core
(:require [re-frame.core :as re-frame]
[taoensso.timbre :as log]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn handle-backup-failed
(rf/defn handle-backup-failed
{:events [::backup-failed]}
[{:keys [db]}]
{:db (dissoc db :backup/performing-backup)})
(fx/defn handle-backup-perfomed
(rf/defn handle-backup-perfomed
{:events [::backup-performed]}
[{:keys [db]}]
{:db (dissoc db :backup/performing-backup)})
(fx/defn handle-perform-backup-pressed
(rf/defn handle-perform-backup-pressed
{:events [:multiaccounts.ui/perform-backup-pressed]}
[{:keys [db]}]
{:db (assoc db :backup/performing-backup true)
{:db (assoc db :backup/performing-backup true)
::json-rpc/call [{:method "wakuext_backupData"
:params []
:on-error #(do
+52 -41
View File
@@ -4,24 +4,27 @@
[status-im.i18n.i18n :as i18n]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]))
[utils.re-frame :as rf]))
(def address-regex #"enode://[a-zA-Z0-9]+:?(.*)\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
(defn valid-address? [address]
(defn valid-address?
[address]
(re-matches address-regex address))
(defn- build [id bootnode-name address chain]
(defn- build
[id bootnode-name address chain]
{:address address
:chain chain
:id (string/replace id "-" "")
:name bootnode-name})
(fx/defn fetch [cofx id]
(rf/defn fetch
[cofx id]
(let [network (get-in cofx [:db :networks/current-network])]
(get-in cofx [:db :multiaccount :custom-bootnodes network id])))
(fx/defn set-input
(rf/defn set-input
{:events [:bootnodes.ui/input-changed]}
[{:keys [db]} input-key value]
{:db (update
@@ -35,16 +38,17 @@
:name (string/blank? value)
:url (not (valid-address? value)))})})
(fx/defn edit
(rf/defn edit
{:events [:bootnodes.ui/add-bootnode-pressed]}
[{:keys [db] :as cofx} id]
(let [{:keys [id
address
name]} (fetch cofx id)
fxs (fx/merge cofx
(set-input :id id)
(set-input :url (str address))
(set-input :name (str name)))]
name]}
(fetch cofx id)
fxs (rf/merge cofx
(set-input :id id)
(set-input :url (str address))
(set-input :name (str name)))]
(assoc fxs :dispatch [:navigate-to :edit-bootnode])))
(defn custom-bootnodes-in-use?
@@ -52,68 +56,75 @@
(let [network (:networks/current-network db)]
(get-in db [:multiaccount :custom-bootnodes-enabled? network])))
(fx/defn delete [{{:keys [multiaccount] :as db} :db :as cofx} id]
(let [network (:networks/current-network db)
(rf/defn delete
[{{:keys [multiaccount] :as db} :db :as cofx} id]
(let [network (:networks/current-network db)
new-multiaccount (update-in multiaccount [:custom-bootnodes network] dissoc id)]
(fx/merge cofx
(rf/merge cofx
{:db (assoc db :multiaccount new-multiaccount)}
(multiaccounts.update/multiaccount-update
:custom-bootnodes (:custom-bootnodes new-multiaccount)
:custom-bootnodes
(:custom-bootnodes new-multiaccount)
{:success-event (when (custom-bootnodes-in-use? cofx)
[:multiaccounts.update.callback/save-settings-success])}))))
(fx/defn upsert
{:events [:bootnodes.ui/save-pressed]
(rf/defn upsert
{:events [:bootnodes.ui/save-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:bootnodes/keys [manage] :keys [multiaccount] :as db} :db
random-id-generator :random-id-generator :as cofx}]
random-id-generator :random-id-generator
:as cofx}]
(let [{:keys [name id url]} manage
network (:networks/current-network db)
bootnode (build
(or (:value id) (random-id-generator))
(:value name)
(:value url)
network)
new-bootnodes (assoc-in
(:custom-bootnodes multiaccount)
[network (:id bootnode)]
bootnode)]
network (:networks/current-network db)
bootnode (build
(or (:value id) (random-id-generator))
(:value name)
(:value url)
network)
new-bootnodes (assoc-in
(:custom-bootnodes multiaccount)
[network (:id bootnode)]
bootnode)]
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :bootnodes/manage)
:dispatch [:navigate-back]}
(multiaccounts.update/multiaccount-update
:custom-bootnodes new-bootnodes
:custom-bootnodes
new-bootnodes
{:success-event (when (custom-bootnodes-in-use? cofx)
[:multiaccounts.update.callback/save-settings-success])}))))
(fx/defn toggle-custom-bootnodes
(rf/defn toggle-custom-bootnodes
{:events [:bootnodes.ui/custom-bootnodes-switch-toggled]}
[{:keys [db] :as cofx} value]
(let [current-network (:networks/current-network db)
(let [current-network (:networks/current-network db)
bootnodes-settings (get-in db [:multiaccount :custom-bootnodes-enabled?])]
(multiaccounts.update/multiaccount-update
cofx
:custom-bootnodes-enabled? (assoc bootnodes-settings current-network value)
:custom-bootnodes-enabled?
(assoc bootnodes-settings current-network value)
{:success-event [:multiaccounts.update.callback/save-settings-success]})))
(fx/defn set-bootnodes-from-qr
(rf/defn set-bootnodes-from-qr
{:events [:bootnodes.callback/qr-code-scanned]}
[cofx url]
(assoc (set-input cofx :url (string/trim url))
:dispatch [:navigate-back]))
:dispatch
[:navigate-back]))
(fx/defn show-delete-bootnode-confirmation
(rf/defn show-delete-bootnode-confirmation
{:events [:bootnodes.ui/delete-pressed]}
[_ bootnode-id]
{:ui/show-confirmation {:title (i18n/label :t/delete-bootnode-title)
:content (i18n/label :t/delete-bootnode-are-you-sure)
{:ui/show-confirmation {:title (i18n/label :t/delete-bootnode-title)
:content (i18n/label :t/delete-bootnode-are-you-sure)
:confirm-button-text (i18n/label :t/delete-bootnode)
:on-accept #(re-frame/dispatch [:bootnodes.ui/delete-confirmed bootnode-id])}})
:on-accept #(re-frame/dispatch [:bootnodes.ui/delete-confirmed
bootnode-id])}})
(fx/defn delete-bootnode
(rf/defn delete-bootnode
{:events [:bootnodes.ui/delete-confirmed]}
[cofx bootnode-id]
(fx/merge cofx
(rf/merge cofx
(delete bootnode-id)
(navigation/navigate-back)))
+9 -9
View File
@@ -1,15 +1,15 @@
(ns status-im.bottom-sheet.core
(:require [status-im.utils.fx :as fx]))
(:require [utils.re-frame :as rf]))
(fx/defn show-bottom-sheet
(rf/defn show-bottom-sheet
[{:keys [db]} {:keys [view options]}]
{:show-bottom-sheet nil
:db (assoc db
:bottom-sheet/show? true
:bottom-sheet/view view
:bottom-sheet/options options)})
:db (assoc db
:bottom-sheet/show? true
:bottom-sheet/view view
:bottom-sheet/options options)})
(fx/defn show-bottom-sheet-event
(rf/defn show-bottom-sheet-event
{:events [:bottom-sheet/show-sheet]}
[cofx view options]
(show-bottom-sheet
@@ -17,8 +17,8 @@
{:view view
:options options}))
(fx/defn hide-bottom-sheet
(rf/defn hide-bottom-sheet
{:events [:bottom-sheet/hide]}
[{:keys [db]}]
{:hide-bottom-sheet nil
:db (assoc db :bottom-sheet/show? false)})
:db (assoc db :bottom-sheet/show? false)})
+195 -152
View File
@@ -1,62 +1,65 @@
(ns status-im.browser.core
(:require [clojure.string :as string]
(:require ["eth-phishing-detect" :as eth-phishing-detect]
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.browser.eip3085 :as eip3085]
[status-im.browser.eip3326 :as eip3326]
[status-im.browser.permissions :as browser.permissions]
[status-im.browser.webview-ref :as webview-ref]
[status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.native-module.core :as status]
[status-im.signing.core :as signing]
[status-im.ui.components.list-selection :as list-selection]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.utils.http :as http]
[status-im.utils.platform :as platform]
[status-im.utils.random :as random]
[status-im.utils.types :as types]
[status-im.utils.universal-links.utils :as links]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[status-im.signing.core :as signing]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.browser.webview-ref :as webview-ref]
["eth-phishing-detect" :as eth-phishing-detect]
[utils.debounce :as debounce]
[status-im.browser.eip3085 :as eip3085]
[status-im.browser.eip3326 :as eip3326]))
[utils.re-frame :as rf]))
(fx/defn update-browser-option
(rf/defn update-browser-option
[{:keys [db]} option-key option-value]
{:db (assoc-in db [:browser/options option-key] option-value)})
(fx/defn update-browser-options
(rf/defn update-browser-options
[{:keys [db]} options]
{:db (update db :browser/options merge options)})
(defn get-current-browser [db]
(defn get-current-browser
[db]
(get-in db [:browser/browsers (get-in db [:browser/options :browser-id])]))
(defn get-current-url [{:keys [history history-index]
:or {history-index 0}}]
(defn get-current-url
[{:keys [history history-index]
:or {history-index 0}}]
(when history
(nth history history-index)))
(defn secure? [{:keys [error? dapp?]} {:keys [url]}]
(defn secure?
[{:keys [error? dapp?]} {:keys [url]}]
(or dapp?
(and (not error?)
(when url
(string/starts-with? url "https://")))))
(fx/defn remove-browser
(rf/defn remove-browser
{:events [:browser.ui/remove-browser-pressed]}
[{:keys [db]} browser-id]
{:db (update-in db [:browser/browsers] dissoc browser-id)
::json-rpc/call [{:method "wakuext_deleteBrowser"
:params [browser-id]
{:db (update-in db [:browser/browsers] dissoc browser-id)
::json-rpc/call [{:method "wakuext_deleteBrowser"
:params [browser-id]
:on-success #()}]})
(fx/defn clear-all-browsers
(rf/defn clear-all-browsers
{:events [:browser.ui/clear-all-browsers-pressed]}
[{:keys [db]}]
{:db (dissoc db :browser/browsers)
@@ -65,106 +68,116 @@
:params [browser-id]
:on-success #()})})
(defn update-dapp-name [{:keys [name] :as browser}]
(defn update-dapp-name
[{:keys [name] :as browser}]
(assoc browser :dapp? false :name (or name (i18n/label :t/browser))))
(defn check-if-phishing-url [{:keys [history history-index] :as browser}]
(defn check-if-phishing-url
[{:keys [history history-index] :as browser}]
(let [history-host (http/url-host (try (nth history history-index) (catch js/Error _)))]
(cond-> browser history-host (assoc :unsafe? (eth-phishing-detect history-host)))))
(defn resolve-ens-contenthash-callback [url]
(defn resolve-ens-contenthash-callback
[url]
(if (not (string/blank? url))
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-success url])
(re-frame/dispatch [:browser.callback/resolve-ens-multihash-error])))
(fx/defn resolve-url
(rf/defn resolve-url
[{:keys [db]} {:keys [error? resolved-url]}]
(when (not error?)
(let [current-url (get-current-url (get-current-browser db))
host (http/url-host current-url)]
host (http/url-host current-url)]
(if (and (not resolved-url) (ens/is-valid-eth-name? host))
{:db (update db :browser/options assoc :resolving? true)
{:db (update db :browser/options assoc :resolving? true)
:browser/resolve-ens-contenthash {:chain-id (ethereum/chain-id db)
:ens-name host
:cb resolve-ens-contenthash-callback}}
{:db (update db :browser/options assoc :url (or resolved-url current-url) :resolving? false)}))))
(fx/defn update-browser
(rf/defn update-browser
[{:keys [db]}
{:keys [browser-id] :as browser}]
(let [updated-browser (-> browser
(update-dapp-name)
(check-if-phishing-url))]
{:db (update-in db
[:browser/browsers browser-id]
merge updated-browser)
::json-rpc/call [{:method "wakuext_addBrowser"
:params [(select-keys updated-browser [:browser-id :timestamp :name :dapp? :history :history-index])]
{:db (update-in db
[:browser/browsers browser-id]
merge
updated-browser)
::json-rpc/call [{:method "wakuext_addBrowser"
:params [(select-keys updated-browser
[:browser-id :timestamp :name :dapp? :history
:history-index])]
:on-success #()}]}))
(fx/defn store-bookmark
(rf/defn store-bookmark
{:events [:browser/store-bookmark]}
[{:keys [db]}
{:keys [url] :as bookmark}]
{:db (assoc-in db [:bookmarks/bookmarks url] bookmark)
::json-rpc/call [{:method "wakuext_addBookmark"
:params [bookmark]
{:db (assoc-in db [:bookmarks/bookmarks url] bookmark)
::json-rpc/call [{:method "wakuext_addBookmark"
:params [bookmark]
:on-success #()}]})
(fx/defn update-bookmark
(rf/defn update-bookmark
{:events [:browser/update-bookmark]}
[{:keys [db] :as cofx}
{:keys [url] :as bookmark}]
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
new-bookmark (merge old-bookmark bookmark)]
(fx/merge cofx {:db (assoc-in db [:bookmarks/bookmarks url] new-bookmark)
::json-rpc/call [{:method "wakuext_updateBookmark"
:params [url bookmark]
:on-success #()}]})))
(rf/merge cofx
{:db (assoc-in db [:bookmarks/bookmarks url] new-bookmark)
::json-rpc/call [{:method "wakuext_updateBookmark"
:params [url bookmark]
:on-success #()}]})))
(fx/defn delete-bookmark
(rf/defn delete-bookmark
{:events [:browser/delete-bookmark]}
[{:keys [db] :as cofx}
url]
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
(let [old-bookmark (get-in db [:bookmarks/bookmarks url])
removed-bookmark (merge old-bookmark {:removed true})]
(fx/merge cofx {:db (update db :bookmarks/bookmarks dissoc url)
::json-rpc/call [{:method "wakuext_removeBookmark"
:params [url]
:on-success #()}]})))
(rf/merge cofx
{:db (update db :bookmarks/bookmarks dissoc url)
::json-rpc/call [{:method "wakuext_removeBookmark"
:params [url]
:on-success #()}]})))
(defn can-go-back? [{:keys [history-index]}]
(defn can-go-back?
[{:keys [history-index]}]
(pos? history-index))
(fx/defn navigate-to-previous-page
(rf/defn navigate-to-previous-page
{:events [:browser.ui/previous-page-button-pressed]}
[cofx]
(let [{:keys [history-index] :as browser} (get-current-browser (:db cofx))]
(when (can-go-back? browser)
(fx/merge cofx
(rf/merge cofx
(update-browser (assoc browser :history-index (dec history-index)))
(resolve-url nil)))))
(fx/defn ignore-unsafe
(rf/defn ignore-unsafe
{:events [:browser/ignore-unsafe]}
[cofx]
(let [browser (get-current-browser (:db cofx))
host (http/url-host (get-current-url browser))]
host (http/url-host (get-current-url browser))]
(update-browser cofx (assoc browser :ignore-unsafe host))))
(defn can-go-forward? [{:keys [history-index history]}]
(defn can-go-forward?
[{:keys [history-index history]}]
(< history-index (dec (count history))))
(fx/defn navigate-to-next-page
(rf/defn navigate-to-next-page
{:events [:browser.ui/next-page-button-pressed]}
[cofx]
(let [{:keys [history-index] :as browser} (get-current-browser (:db cofx))]
(when (can-go-forward? browser)
(fx/merge cofx
(rf/merge cofx
(update-browser (assoc browser :history-index (inc history-index)))
(resolve-url nil)))))
(fx/defn update-browser-history
(rf/defn update-browser-history
[cofx browser url]
(let [history-index (:history-index browser)
history (:history browser)]
@@ -173,73 +186,81 @@
new-index (dec (count new-history))]
(update-browser cofx
(assoc browser
:history new-history
:history new-history
:history-index new-index))))))
(fx/defn resolve-ens-multihash-success
(rf/defn resolve-ens-multihash-success
{:events [:browser.callback/resolve-ens-multihash-success]}
[{:keys [db] :as cofx} url]
(let [current-url (get-current-url (get-current-browser db))
host (http/url-host current-url)
path (subs current-url (+ (.indexOf ^js current-url host) (count host)))
gateway url]
(fx/merge cofx
{:db (-> (update db :browser/options
(rf/merge cofx
{:db (-> (update db
:browser/options
assoc
:url (str gateway path)
:resolving? false)
:url (str gateway path)
:resolving? false)
(assoc-in [:browser/options :resolved-ens host] gateway))})))
(fx/defn resolve-ens-multihash-error
(rf/defn resolve-ens-multihash-error
{:events [:browser.callback/resolve-ens-multihash-error]}
[{:keys [db] :as cofx}]
(update-browser-options cofx {:url (get-current-url (get-current-browser db))
:resolving? false
:error? true}))
(update-browser-options cofx
{:url (get-current-url (get-current-browser db))
:resolving? false
:error? true}))
(fx/defn handle-browser-error
(rf/defn handle-browser-error
{:events [:browser/error-occured]}
[cofx]
(fx/merge cofx
(rf/merge cofx
(update-browser-option :error? true)
(update-browser-option :loading? false)))
(fx/defn handle-pdf
(rf/defn handle-pdf
[_ url]
(when (and platform/android? (string/ends-with? url ".pdf"))
{:browser/show-web-browser-selection url}))
(fx/defn handle-message-link
(rf/defn handle-message-link
{:events [:browser.ui/message-link-pressed]}
[_ link]
(if (links/universal-link? link)
{:dispatch [:universal-links/handle-url link]}
{:browser/show-browser-selection link}))
(fx/defn update-browser-on-nav-change
(rf/defn update-browser-on-nav-change
[cofx url error?]
(let [browser (get-current-browser (:db cofx))
options (get-in cofx [:db :browser/options])
(let [browser (get-current-browser (:db cofx))
options (get-in cofx [:db :browser/options])
current-url (:url options)]
(when (and browser (not (string/blank? url)) (not= "about:blank" url) (not= current-url url) (not= (str current-url "/") url))
(when (and browser
(not (string/blank? url))
(not= "about:blank" url)
(not= current-url url)
(not= (str current-url "/") url))
(let [resolved-ens (first (filter (fn [v]
(not= (.indexOf ^js url (second v)) -1))
(:resolved-ens options)))
resolved-url (if resolved-ens
(http/normalize-url (string/replace url (second resolved-ens) (first resolved-ens)))
(http/normalize-url (string/replace url
(second resolved-ens)
(first resolved-ens)))
url)]
(fx/merge cofx
(rf/merge cofx
(update-browser-history browser resolved-url)
(handle-pdf url)
(resolve-url {:error? error? :resolved-url (when resolved-ens url)}))))))
(fx/defn update-browser-name
(rf/defn update-browser-name
[cofx title]
(let [browser (get-current-browser (:db cofx))]
(when (and browser (not (:dapp? browser)) title (not (string/blank? title)))
(update-browser cofx (assoc browser :name title)))))
(fx/defn navigation-state-changed
(rf/defn navigation-state-changed
{:events [:browser/navigation-state-changed]}
[cofx event error?]
(let [{:strs [url loading title]} (js->clj event)
@@ -247,59 +268,61 @@
(if (links/universal-link? url)
(when-not (and deep-link? platform/ios?) ;; ios webview handles this
{:dispatch [:universal-links/handle-url url]})
(fx/merge cofx
(rf/merge cofx
(update-browser-option :loading? loading)
(update-browser-name title)
(update-browser-on-nav-change url error?)))))
(fx/defn open-url-in-current-browser
(rf/defn open-url-in-current-browser
"Opens a url in the current browser, which mean no new entry is added to the home page
and history of the current browser is updated so that the user can navigate back to the
origin url"
{:events [:browser.ui/url-submitted]}
[cofx url]
(let [browser (get-current-browser (:db cofx))
(let [browser (get-current-browser (:db cofx))
normalized-url (http/normalize-and-decode-url url)]
(if (links/universal-link? normalized-url)
{:dispatch [:universal-links/handle-url normalized-url]}
(fx/merge cofx
(rf/merge cofx
(update-browser-option :url-editing? false)
(update-browser-history browser normalized-url)
(resolve-url nil)))))
(fx/defn open-url
(rf/defn open-url
"Opens a url in the browser. If a host can be extracted from the url and
there is already a browser for this host, this browser is reused
If the browser is reused, the history is flushed"
{:events [:browser.ui/open-url]}
[{:keys [db] :as cofx} url]
(let [normalized-url (http/normalize-and-decode-url url)
browser {:browser-id (random/id)
:history-index 0
:history [normalized-url]}]
browser {:browser-id (random/id)
:history-index 0
:history [normalized-url]}]
(if (links/universal-link? normalized-url)
{:dispatch [:universal-links/handle-url normalized-url]}
(fx/merge cofx
{:db (assoc db :browser/options
(rf/merge cofx
{:db (assoc db
:browser/options
{:browser-id (:browser-id browser)})}
(navigation/change-tab :browser)
(navigation/set-stack-root :browser-stack :browser)
(update-browser browser)
(resolve-url nil)))))
(fx/defn open-existing-browser
(rf/defn open-existing-browser
"Opens an existing browser with it's history"
{:events [:browser.ui/browser-item-selected]}
[{:keys [db] :as cofx} browser-id]
(let [browser (get-in db [:browser/browsers browser-id])]
(fx/merge cofx
{:db (assoc db :browser/options
(rf/merge cofx
{:db (assoc db
:browser/options
{:browser-id browser-id})}
(update-browser browser)
(navigation/set-stack-root :browser-stack :browser)
(resolve-url nil))))
(fx/defn web3-error-callback
(rf/defn web3-error-callback
{:events [:browser.dapp/transaction-on-error]}
[_ message-id message]
{:browser/send-to-bridge
@@ -307,7 +330,7 @@
:messageId message-id
:error message}})
(fx/defn dapp-complete-transaction
(rf/defn dapp-complete-transaction
{:events [:browser.dapp/transaction-on-result]}
[_ message-id id result]
;;TODO check and test id
@@ -336,21 +359,24 @@
(ethereum/address? second-param)
[second-param (if typed? first-param (normalize-message first-param))]))))
(fx/defn send-to-bridge
(rf/defn send-to-bridge
{:events [:browser.callback/call-rpc]}
[_ message]
{:browser/send-to-bridge message})
(defn web3-sign-message? [method]
(defn web3-sign-message?
[method]
(#{constants/web3-sign-typed-data constants/web3-sign-typed-data-v3 constants/web3-sign-typed-data-v4
constants/web3-personal-sign
constants/web3-eth-sign constants/web3-keycard-sign-typed-data} method))
constants/web3-eth-sign constants/web3-keycard-sign-typed-data}
method))
(fx/defn web3-send-async
(rf/defn web3-send-async
[cofx dapp-name {:keys [method params id] :as payload} message-id]
(let [message? (web3-sign-message? method)
dapps-address (get-in cofx [:db :multiaccount :dapps-address])
typed? (and (not= constants/web3-personal-sign method) (not= constants/web3-eth-sign method))]
typed? (and (not= constants/web3-personal-sign method)
(not= constants/web3-eth-sign method))]
(if (or message? (= constants/web3-send-transaction method))
(let [[address data] (cond (and (= method constants/web3-keycard-sign-typed-data)
(not (vector? params)))
@@ -359,34 +385,38 @@
message? (normalize-sign-message-params params typed?)
:else [nil nil])]
(when (or (not message?) (and address data))
(signing/sign cofx (merge
(if message?
{:message {:address address
:data data
:v4 (= constants/web3-sign-typed-data-v4 method)
:typed? typed?
:pinless? (= method constants/web3-keycard-sign-typed-data)
:from dapps-address}}
{:tx-obj (-> params
first
(update :from #(or % dapps-address))
(dissoc :gasPrice))})
{:on-result [:browser.dapp/transaction-on-result message-id id]
:on-error [:browser.dapp/transaction-on-error message-id]}))))
(signing/sign cofx
(merge
(if message?
{:message {:address address
:data data
:v4 (= constants/web3-sign-typed-data-v4 method)
:typed? typed?
:pinless? (= method constants/web3-keycard-sign-typed-data)
:from dapps-address}}
{:tx-obj (-> params
first
(update :from #(or % dapps-address))
(dissoc :gasPrice))})
{:on-result [:browser.dapp/transaction-on-result message-id id]
:on-error [:browser.dapp/transaction-on-error message-id]}))))
(cond
(#{"eth_accounts" "eth_coinbase"} method)
(send-to-bridge cofx {:type constants/web3-send-async-callback
:messageId message-id
:result {:jsonrpc "2.0"
:id (int id)
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
(send-to-bridge
cofx
{:type constants/web3-send-async-callback
:messageId message-id
:result {:jsonrpc "2.0"
:id (int id)
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
(= method "personal_ecRecover")
{:signing.fx/recover-message {:params {:message (first params)
{:signing.fx/recover-message {:params {:message (first params)
:signature (second params)}
:on-completed #(re-frame/dispatch [:browser.callback/call-rpc
{:type constants/web3-send-async-callback
:messageId message-id
:result (types/json->clj %)}])}}
:on-completed #(re-frame/dispatch
[:browser.callback/call-rpc
{:type constants/web3-send-async-callback
:messageId message-id
:result (types/json->clj %)}])}}
(= method "wallet_switchEthereumChain")
(eip3326/handle-switch-ethereum-chain cofx dapp-name id message-id (first params))
@@ -401,7 +431,8 @@
:error %1
:result %2}])]}))))
(fx/defn handle-no-permissions [cofx {:keys [method id]} message-id]
(rf/defn handle-no-permissions
[cofx {:keys [method id]} message-id]
(if (= method "eth_accounts")
;; eth_accounts returns empty array for compatibility with meta-mask
(send-to-bridge cofx
@@ -420,41 +451,48 @@
"keycard_signTypedData"
"eth_signTypedData" "personal_sign" "personal_ecRecover"})
(defn has-permissions? [{:dapps/keys [permissions]} dapp-name method]
(defn has-permissions?
[{:dapps/keys [permissions]} dapp-name method]
(boolean
(and (permissioned-method method)
(not (some #{constants/dapp-permission-web3} (get-in permissions [dapp-name :permissions]))))))
(fx/defn web3-send-async-read-only
(rf/defn web3-send-async-read-only
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
(if (has-permissions? db dapp-name method)
(handle-no-permissions cofx payload message-id)
(web3-send-async cofx dapp-name payload message-id)))
(fx/defn handle-scanned-qr-code
(rf/defn handle-scanned-qr-code
{:events [:browser.bridge.callback/qr-code-scanned]}
[cofx data {{:keys [dapp-name permission message-id]} :data}]
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
(rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
(browser.permissions/send-response-to-bridge permission message-id true data)
(browser.permissions/process-next-permission dapp-name)
(navigation/navigate-back)))
(fx/defn handle-canceled-qr-code
(rf/defn handle-canceled-qr-code
{:events [:browser.bridge.callback/qr-code-canceled]}
[cofx {{:keys [dapp-name permission message-id]} :data}]
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
(rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] false)
(browser.permissions/send-response-to-bridge permission message-id true nil)
(browser.permissions/process-next-permission dapp-name)))
(fx/defn process-bridge-message
(rf/defn process-bridge-message
{:events [:browser/bridge-message-received]}
[{:keys [db] :as cofx} message]
(let [browser (get-current-browser db)
url-original (get-current-url browser)
data (types/json->clj message)
(let [browser (get-current-browser
db)
url-original (get-current-url
browser)
data (types/json->clj
message)
{{:keys [url]} :navState :keys [type permission payload messageId params]} data
{:keys [dapp? name]} browser
dapp-name (if dapp? name (http/url-host url-original))]
{:keys [dapp? name]} browser
dapp-name (if dapp?
name
(http/url-host
url-original))]
(cond
(and (= type constants/history-state-changed)
(not= "about:blank" url))
@@ -474,10 +512,13 @@
(re-frame/reg-fx
:browser/send-to-bridge
(fn [message]
(let [^js webview @webview-ref/webview-ref
msg (str "(function() { var __send = function() { if (ReactNativeWebView.onMessage) { ReactNativeWebView.onMessage('"
(types/clj->json message)
"');} else {setTimeout(__send, 0)}}; __send();})();")]
(let
[^js webview @webview-ref/webview-ref
msg
(str
"(function() { var __send = function() { if (ReactNativeWebView.onMessage) { ReactNativeWebView.onMessage('"
(types/clj->json message)
"');} else {setTimeout(__send, 0)}}; __send();})();")]
(when (and message webview)
(.injectJavaScript webview msg)))))
@@ -508,59 +549,61 @@
(fn []
(status/clear-web-data)))
(defn share-link [url]
(defn share-link
[url]
(let [link (links/generate-link :browse :external url)
message (i18n/label :t/share-dapp-text {:link link})]
(list-selection/open-share {:message message})))
(fx/defn dapps-account-selected
(rf/defn dapps-account-selected
{:events [:dapps-account-selected]}
[{:keys [db] :as cofx} address]
(fx/merge cofx
(rf/merge cofx
{:browser/clear-web-data nil}
(bottom-sheet/hide-bottom-sheet)
(browser.permissions/clear-dapps-permissions)
(multiaccounts.update/multiaccount-update :dapps-address address {})
#(when (= (:view-id db) :browser)
(merge (navigation/navigate-back %)
{:dispatch [:browser.ui/browser-item-selected (get-in db [:browser/options :browser-id])]}))))
{:dispatch [:browser.ui/browser-item-selected
(get-in db [:browser/options :browser-id])]}))))
(fx/defn open-empty-tab
(rf/defn open-empty-tab
{:events [:browser.ui/open-empty-tab]}
[cofx]
(debounce/clear :browser/navigation-state-changed)
(navigation/set-stack-root cofx :browser-stack :empty-tab))
(fx/defn url-input-pressed
(rf/defn url-input-pressed
{:events [:browser.ui/url-input-pressed]}
[cofx _]
(update-browser-option cofx :url-editing? true))
(fx/defn url-input-blured
(rf/defn url-input-blured
{:events [:browser.ui/url-input-blured]}
[cofx]
(update-browser-option cofx :url-editing? false))
(fx/defn lock-pressed
(rf/defn lock-pressed
{:events [:browser.ui/lock-pressed]}
[cofx secure?]
(update-browser-option cofx :show-tooltip (if secure? :secure :not-secure)))
(fx/defn close-tooltip-pressed
(rf/defn close-tooltip-pressed
{:events [:browser.ui/close-tooltip-pressed]}
[cofx]
(update-browser-option cofx :show-tooltip nil))
(fx/defn loading-started
(rf/defn loading-started
{:events [:browser/loading-started]}
[cofx]
(update-browser-options cofx {:error? false :loading? true}))
(fx/defn handle-bookmarks
(rf/defn handle-bookmarks
[{:keys [db]} bookmarks]
(let [changed-bookmarks (reduce (fn [acc {:keys [url] :as bookmark}]
(assoc acc url bookmark))
{}
bookmarks)
stored-bookmarks (get-in db [:bookmarks/bookmarks])]
stored-bookmarks (get-in db [:bookmarks/bookmarks])]
{:db (assoc-in db [:bookmarks/bookmarks] (merge stored-bookmarks changed-bookmarks))}))
+51 -44
View File
@@ -1,69 +1,76 @@
;reference https://eips.ethereum.org/EIPS/eip-3085 EIP-3085: Wallet Add Ethereum Chain RPC Method (`wallet_addEthereumChain`)
;reference https://eips.ethereum.org/EIPS/eip-3085 EIP-3085: Wallet Add Ethereum Chain RPC Method
;(`wallet_addEthereumChain`)
(ns status-im.browser.eip3085
(:require [status-im.constants :as constants]
[clojure.string :as string]
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.utils.fx :as fx]
[status-im.network.core :as network]
[taoensso.timbre :as log]
[status-im.utils.random :as random]
[status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ui.screens.browser.eip3085.sheet :as sheet]))
[status-im.network.core :as network]
[status-im.ui.screens.browser.eip3085.sheet :as sheet]
[status-im.utils.random :as random]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn send-success-call-to-bridge
(rf/defn send-success-call-to-bridge
{:events [:eip3085/send-success-call-to-bridge]}
[_ id messageId]
{:browser/send-to-bridge {:type constants/web3-send-async-callback
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId messageId
:result {:jsonrpc "2.0"
:id (int id)
:result nil}}})
:result {:jsonrpc "2.0"
:id (int id)
:result nil}}})
(fx/defn allow-permission
(rf/defn allow-permission
{:events [:eip3085.ui/dapp-permission-allowed]}
[{:keys [db] :as cofx} message-id {:keys [new-networks id]}]
{:db (assoc db :networks/networks new-networks)
::json-rpc/call [{:method "settings_saveSetting"
:params [:networks/networks (vals new-networks)]
:on-success #(re-frame/dispatch [:eip3085/send-success-call-to-bridge cofx id message-id])
{:db (assoc db :networks/networks new-networks)
::json-rpc/call [{:method "settings_saveSetting"
:params [:networks/networks (vals new-networks)]
:on-success #(re-frame/dispatch [:eip3085/send-success-call-to-bridge cofx id
message-id])
:on-error #(log/error "failed to perform settings_saveSetting" %)}]
:dispatch [:bottom-sheet/hide]})
:dispatch [:bottom-sheet/hide]})
(fx/defn deny-permission
(rf/defn deny-permission
{:events [:eip3085.ui/dapp-permission-denied]}
[_ message-id _]
{:browser/send-to-bridge {:type constants/web3-send-async-callback
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId message-id
:error {:code 4001
:message "User rejected the request."}}
:dispatch [:bottom-sheet/hide]})
:error {:code 4001
:message "User rejected the request."}}
:dispatch [:bottom-sheet/hide]})
(fx/defn handle-add-ethereum-chain
(rf/defn handle-add-ethereum-chain
{:events [:eip3085/handle-add-ethereum-chain]}
[{{:networks/keys [networks] :as db} :db :as cofx}
dapp-name id message-id {:keys [chainId blockExplorerUrls chainName iconUrls nativeCurrency rpcUrls] :as params}]
(let [manage {:name {:value chainName}
:symbol {:value (:symbol nativeCurrency)}
:url {:value (first rpcUrls)}
dapp-name id message-id
{:keys [chainId blockExplorerUrls chainName iconUrls nativeCurrency rpcUrls] :as params}]
(let [manage {:name {:value chainName}
:symbol {:value (:symbol nativeCurrency)}
:url {:value (first rpcUrls)}
:network-id {:value chainId}
:chain {:value :custom}}]
:chain {:value :custom}}]
(if (network/valid-manage? manage)
(let [{:keys [name url chain network-id symbol]} manage
random-id (string/replace (random/id) "-" "")
network (network/new-network random-id
(:value name)
(:value symbol)
(:value url)
(:value chain)
(:value network-id))
new-networks (assoc networks random-id network)
params (assoc params :new-networks new-networks :id id :new-network network)]
random-id (string/replace (random/id) "-" "")
network (network/new-network random-id
(:value name)
(:value symbol)
(:value url)
(:value chain)
(:value network-id))
new-networks (assoc networks random-id network)
params (assoc params
:new-networks new-networks
:id id
:new-network network)]
(if (network/chain-id-available? networks network)
{:dispatch [:bottom-sheet/show-sheet {:content (fn []
[sheet/permissions-panel dapp-name message-id params])}]}
{:dispatch [:bottom-sheet/show-sheet
{:content (fn []
[sheet/permissions-panel dapp-name message-id params])}]}
(send-success-call-to-bridge cofx id message-id)))
{:browser/send-to-bridge {:type constants/web3-send-async-callback
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId message-id
:error {:code -32602
:message "invalid network parameters"}}})))
:error {:code -32602
:message "invalid network parameters"}}})))
+37 -26
View File
@@ -1,43 +1,54 @@
;reference https://eips.ethereum.org/EIPS/eip-3326 EIP-3326: Wallet Switch Ethereum Chain RPC Method (`wallet_switchEthereumChain`)
;reference https://eips.ethereum.org/EIPS/eip-3326 EIP-3326: Wallet Switch Ethereum Chain RPC Method
;(`wallet_switchEthereumChain`)
(ns status-im.browser.eip3326
(:require [status-im.constants :as constants]
[status-im.utils.fx :as fx]
[status-im.ethereum.core :as ethereum]
[status-im.ui.screens.browser.eip3326.sheet :as sheet]))
[status-im.ui.screens.browser.eip3326.sheet :as sheet]
[utils.re-frame :as rf]))
(fx/defn deny-permission
(rf/defn deny-permission
{:events [:eip3326.ui/dapp-permission-denied]}
[{:keys [db] :as cofx} message-id _]
{:browser/send-to-bridge {:type constants/web3-send-async-callback
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId message-id
:error {:code 4001
:message "User rejected the request."}}
:dispatch [:bottom-sheet/hide]})
:error {:code 4001
:message "User rejected the request."}}
:dispatch [:bottom-sheet/hide]})
(fx/defn handle-switch-ethereum-chain
(rf/defn handle-switch-ethereum-chain
{:events [:eip3326/handle-switch-ethereum-chain]}
[{:keys [db] :as cofx} dapp-name id message-id {:keys [chainId] :as params}]
(let [target-chain-id (js/parseInt chainId 16)
networks (vals (get-in db [:networks/networks]))
exist-chain-ids (set (map ethereum/network->chain-id networks))
(let [target-chain-id (js/parseInt chainId 16)
networks (vals (get-in db [:networks/networks]))
exist-chain-ids (set (map ethereum/network->chain-id networks))
current-chain-id (ethereum/chain-id db)]
(if (exist-chain-ids target-chain-id)
(if (= current-chain-id target-chain-id)
{:browser/send-to-bridge {:type constants/web3-send-async-callback
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId message-id
:result {:jsonrpc "2.0"
:id (int id)
:result nil}}}
(let [target-network (first (filter #(= (ethereum/network->chain-id %1) target-chain-id) networks))
:result {:jsonrpc "2.0"
:id (int id)
:result nil}}}
(let [target-network (first (filter #(= (ethereum/network->chain-id %1) target-chain-id)
networks))
target-network-id (:id target-network)
current-network (ethereum/current-network db)
network-from (:name current-network)
network-to (:name target-network)
params (assoc params :target-network-id target-network-id :network-from network-from :network-to network-to)]
{:dispatch [:bottom-sheet/show-sheet {:content (fn []
[sheet/permissions-panel dapp-name message-id params])}]}))
{:browser/send-to-bridge {:type constants/web3-send-async-callback
current-network (ethereum/current-network db)
network-from (:name current-network)
network-to (:name target-network)
params (assoc params
:target-network-id target-network-id
:network-from network-from
:network-to network-to)]
{:dispatch [:bottom-sheet/show-sheet
{:content (fn []
[sheet/permissions-panel dapp-name message-id params])}]}))
{:browser/send-to-bridge {:type constants/web3-send-async-callback
:messageId message-id
:error {:code 4902
:message (str "Unrecognized chain ID: " target-chain-id ". Try adding the chain using wallet_addEthereumChain first.")}}})))
:error
{:code 4902
:message
(str
"Unrecognized chain ID: "
target-chain-id
". Try adding the chain using wallet_addEthereumChain first.")}}})))
+57 -51
View File
@@ -2,51 +2,53 @@
(:require [status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[status-im2.navigation.events :as navigation]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.utils.fx :as fx]))
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(declare process-next-permission)
(declare send-response-to-bridge)
(def supported-permissions
{constants/dapp-permission-qr-code {:yield-control? true
:allowed? true}
constants/dapp-permission-contact-code {:type :profile
:title (i18n/label :t/wants-to-access-profile)
:description (i18n/label :t/your-contact-code)
:icon :main-icons/profile}
constants/dapp-permission-web3 {:type :wallet
:title (i18n/label :t/dapp-would-like-to-connect-wallet)
:description (i18n/label :t/allowing-authorizes-this-dapp)
:icon :main-icons/wallet}})
{constants/dapp-permission-qr-code {:yield-control? true
:allowed? true}
constants/dapp-permission-contact-code {:type :profile
:title (i18n/label :t/wants-to-access-profile)
:description (i18n/label :t/your-contact-code)
:icon :main-icons/profile}
constants/dapp-permission-web3 {:type :wallet
:title (i18n/label :t/dapp-would-like-to-connect-wallet)
:description (i18n/label :t/allowing-authorizes-this-dapp)
:icon :main-icons/wallet}})
(fx/defn permission-yield-control
(rf/defn permission-yield-control
[{:keys [db] :as cofx} dapp-name permission message-id params]
(cond
(= permission constants/dapp-permission-qr-code)
(fx/merge (assoc-in cofx [:db :browser/options :yielding-control?] true)
(rf/merge (assoc-in cofx [:db :browser/options :yielding-control?] true)
(qr-scanner/scan-qr-code {:handler :browser.bridge.callback/qr-code-scanned
:cancel-handler :browser.bridge.callback/qr-code-canceled
:data {:dapp-name dapp-name
:permission permission
:message-id message-id}}))))
(fx/defn permission-show-permission
(rf/defn permission-show-permission
[{:keys [db] :as cofx} dapp-name permission message-id yield-control?]
{:db (assoc-in db [:browser/options :show-permission]
{:requested-permission permission
:message-id message-id
:dapp-name dapp-name
:yield-control? yield-control?})})
{:db (assoc-in db
[:browser/options :show-permission]
{:requested-permission permission
:message-id message-id
:dapp-name dapp-name
:yield-control? yield-control?})})
(defn get-permission-data [cofx allowed-permission]
(defn get-permission-data
[cofx allowed-permission]
(let [multiaccount (get-in cofx [:db :multiaccount])]
(get {constants/dapp-permission-contact-code (:public-key multiaccount)
constants/dapp-permission-web3 [(:dapps-address multiaccount)]}
allowed-permission)))
(fx/defn send-response-to-bridge
(rf/defn send-response-to-bridge
"Send response to the bridge. If the permission is allowed, send data associated
with the permission"
[{:keys [db] :as cofx} permission message-id allowed? data]
@@ -57,7 +59,7 @@
allowed?
(assoc :data data))})
(fx/defn update-dapp-permissions
(rf/defn update-dapp-permissions
[{:keys [db]} dapp-name permission allowed?]
(let [dapp-permissions-set (set (get-in db [:dapps/permissions dapp-name :permissions]))
allowed-permissions-set (if allowed?
@@ -65,28 +67,28 @@
(disj dapp-permissions-set permission))
allowed-permissions {:dapp dapp-name
:permissions (vec allowed-permissions-set)}]
{:db (assoc-in db [:dapps/permissions dapp-name] allowed-permissions)
::json-rpc/call [{:method "permissions_addDappPermissions"
:params [allowed-permissions]
{:db (assoc-in db [:dapps/permissions dapp-name] allowed-permissions)
::json-rpc/call [{:method "permissions_addDappPermissions"
:params [allowed-permissions]
:on-success #()}]}))
(fx/defn revoke-permissions
(rf/defn revoke-permissions
{:events [:browser/revoke-dapp-permissions]}
[{:keys [db] :as cofx} dapp]
(fx/merge cofx
(rf/merge cofx
{:db (update-in db [:dapps/permissions] dissoc dapp)
::json-rpc/call [{:method "permissions_deleteDappPermissions"
:params [dapp]
::json-rpc/call [{:method "permissions_deleteDappPermissions"
:params [dapp]
:on-success #()}]}))
(fx/defn revoke-dapp-permissions
(rf/defn revoke-dapp-permissions
{:events [:dapps/revoke-access]}
[cofx dapp]
(fx/merge cofx
(rf/merge cofx
(revoke-permissions dapp)
(navigation/navigate-back)))
(fx/defn clear-dapps-permissions
(rf/defn clear-dapps-permissions
[{:keys [db]}]
(let [dapp-permissions (keys (:dapps/permissions db))]
{:db (dissoc db :dapps/permissions)
@@ -95,7 +97,7 @@
:params [dapp]
:on-success #()})}))
(fx/defn process-next-permission
(rf/defn process-next-permission
"Process next permission by removing it from pending permissions and prompting user
if there is no pending permissions left, save all granted permissions
and return the result to the bridge"
@@ -105,46 +107,47 @@
{:db db}
(let [pending-permissions (get-in db [:browser/options :pending-permissions])
next-permission (last pending-permissions)
new-cofx (update-in cofx [:db :browser/options :pending-permissions] butlast)]
new-cofx (update-in cofx [:db :browser/options :pending-permissions] butlast)]
(when-let [{:keys [yield-control? permission message-id allowed? params]} next-permission]
(if (and yield-control? allowed?)
(permission-yield-control new-cofx dapp-name permission message-id params)
(permission-show-permission new-cofx dapp-name permission message-id yield-control?)))))))
(fx/defn send-response-and-process-next-permission
(rf/defn send-response-and-process-next-permission
[{:keys [db] :as cofx} dapp-name requested-permission message-id]
(fx/merge cofx
(rf/merge cofx
(send-response-to-bridge requested-permission
message-id
true
(get-permission-data cofx requested-permission))
(process-next-permission dapp-name)))
(fx/defn allow-permission
(rf/defn allow-permission
"Add permission to set of allowed permission and process next permission"
{:events [:browser.permissions.ui/dapp-permission-allowed]}
[{:keys [db] :as cofx}]
(let [{:keys [requested-permission message-id dapp-name yield-control? params]}
(get-in db [:browser/options :show-permission])]
(fx/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
(rf/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
(update-dapp-permissions dapp-name requested-permission true)
(if yield-control?
(permission-yield-control dapp-name requested-permission message-id params)
(send-response-and-process-next-permission dapp-name requested-permission message-id)))))
(fx/defn deny-permission
(rf/defn deny-permission
"Add permission to set of allowed permission and process next permission"
{:events [:browser.permissions.ui/dapp-permission-denied]}
[{:keys [db] :as cofx}]
(let [{:keys [requested-permission message-id dapp-name]} (get-in db [:browser/options :show-permission])]
(fx/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
(let [{:keys [requested-permission message-id dapp-name]} (get-in db
[:browser/options :show-permission])]
(rf/merge (assoc-in cofx [:db :browser/options :show-permission] nil)
(send-response-to-bridge requested-permission
message-id
false
(get-permission-data cofx requested-permission))
(process-next-permission dapp-name))))
(fx/defn process-permission
(rf/defn process-permission
"Process the permission requested by a dapp
If supported permission is already granted, return the result immediatly to the bridge
Otherwise process the first permission which will prompt user"
@@ -156,15 +159,18 @@
(not supported-permission)
(send-response-to-bridge cofx permission message-id false nil)
(and (or permission-allowed? (:allowed? supported-permission)) (not (:yield-control? supported-permission)))
(and (or permission-allowed? (:allowed? supported-permission))
(not (:yield-control? supported-permission)))
(send-response-to-bridge cofx permission message-id true (get-permission-data cofx permission))
:else
(process-next-permission (update-in cofx [:db :browser/options :pending-permissions]
conj {:permission permission
:allowed? (or permission-allowed?
(:allowed? supported-permission))
:yield-control? (:yield-control? supported-permission)
:params params
:message-id message-id})
(process-next-permission (update-in cofx
[:db :browser/options :pending-permissions]
conj
{:permission permission
:allowed? (or permission-allowed?
(:allowed? supported-permission))
:yield-control? (:yield-control? supported-permission)
:params params
:message-id message-id})
dapp-name))))
+164 -150
View File
@@ -1,31 +1,33 @@
(ns status-im.chat.models
(:require [re-frame.core :as re-frame]
[taoensso.timbre :as log]
[status-im.multiaccounts.model :as multiaccounts.model]
(:require [clojure.set :as set]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.add-new.db :as new-public-chat.db]
[status-im.chat.models.loading :as loading]
[status-im.chat.models.message-list :as message-list]
[status-im.chat.models.delete-message :as delete-message]
[status-im.chat.models.delete-message-for-me :as delete-for-me]
[status-im.constants :as constants]
[status-im.data-store.chats :as chats-store]
[status-im.mailserver.core :as mailserver]
[status-im.data-store.contacts :as contacts-store]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[quo.design-system.colors :as colors]
[status-im.constants :as constants]
[status-im.utils.clocks :as utils.clocks]
[status-im.utils.fx :as fx]
[status-im.utils.utils :as utils]
[status-im.utils.types :as types]
[status-im.add-new.db :as new-public-chat.db]
[status-im.chat.models.loading :as loading]
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.ui.screens.chat.state :as chat.state]
[clojure.set :as set]
[status-im2.navigation.events :as navigation]))
[status-im.utils.clocks :as utils.clocks]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[status-im2.contexts.chat.messages.message.delete-message-for-me.events :as delete-for-me]
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn chats []
(defn chats
[]
(:chats (types/json->clj (js/require "./chats.js"))))
(defn- get-chat [cofx chat-id]
(defn- get-chat
[cofx chat-id]
(get-in cofx [:db :chats chat-id]))
(defn multi-user-chat?
@@ -49,7 +51,8 @@
([cofx chat-id]
(community-chat? (get-chat cofx chat-id))))
(defn active-chat? [cofx chat-id]
(defn active-chat?
[cofx chat-id]
(let [chat (get-chat cofx chat-id)]
(:active chat)))
@@ -85,52 +88,56 @@
(defn- create-new-chat
[chat-id {:keys [db now]}]
(let [name (get-in db [:contacts/contacts chat-id :name])]
{:chat-id chat-id
:name (or name "")
:color (rand-nth colors/chat-colors)
:chat-type constants/one-to-one-chat-type
:group-chat false
:timestamp now
:contacts #{chat-id}
:last-clock-value 0}))
{:chat-id chat-id
:name (or name "")
:color (rand-nth colors/chat-colors)
:chat-type constants/one-to-one-chat-type
:group-chat false
:timestamp now
:contacts #{chat-id}
:last-clock-value 0}))
(defn map-chats [{:keys [db] :as cofx}]
(defn map-chats
[{:keys [db] :as cofx}]
(fn [val]
(assoc
(merge
(or (get (:chats db) (:chat-id val))
(create-new-chat (:chat-id val) cofx))
val)
:invitation-admin (:invitation-admin val))))
:invitation-admin
(:invitation-admin val))))
(defn filter-chats [db]
(defn filter-chats
[db]
(fn [val]
(and (not (get-in db [:chats (:chat-id val)])) (:public? val))))
(fx/defn leave-removed-chat
(rf/defn leave-removed-chat
[{{:keys [view-id current-chat-id chats]} :db
:as cofx}]
:as cofx}]
(when (and (= view-id :chat)
(not (contains? chats current-chat-id)))
(navigation/navigate-back cofx)))
(fx/defn ensure-chats
(rf/defn ensure-chats
"Add chats to db and update"
[{:keys [db] :as cofx} chats]
(let [{:keys [all-chats chats-home-list removed-chats]}
(reduce (fn [acc {:keys [chat-id profile-public-key timeline? community-id active muted] :as chat}]
(if (not (or active muted))
(update acc :removed-chats conj chat-id)
(cond-> acc
(and (not profile-public-key) (not timeline?) (not community-id) active)
(update :chats-home-list conj chat-id)
:always
(assoc-in [:all-chats chat-id] chat))))
{:all-chats {}
:chats-home-list #{}
:removed-chats #{}}
(map (map-chats cofx) chats))]
(fx/merge
(reduce
(fn [acc {:keys [chat-id profile-public-key timeline? community-id active muted] :as chat}]
(if (not (or active muted))
(update acc :removed-chats conj chat-id)
(cond-> acc
(and (not profile-public-key) (not timeline?) (not community-id) active)
(update :chats-home-list conj chat-id)
:always
(assoc-in [:all-chats chat-id] chat))))
{:all-chats {}
:chats-home-list #{}
:removed-chats #{}}
(map (map-chats cofx) chats))]
(rf/merge
cofx
(merge {:db (-> db
(update :chats merge all-chats)
@@ -143,62 +150,66 @@
(get-in db [:multiaccount :remote-push-notifications-enabled?])]}))
leave-removed-chat)))
(fx/defn clear-history
(rf/defn clear-history
"Clears history of the particular chat"
[{:keys [db] :as cofx} chat-id remove-chat?]
(let [{:keys [last-message public?
deleted-at-clock-value]} (get-in db [:chats chat-id])
deleted-at-clock-value]}
(get-in db [:chats chat-id])
last-message-clock-value (if (and public? remove-chat?)
0
(or (:clock-value last-message)
deleted-at-clock-value
(utils.clocks/send 0)))]
{:db (-> db
(assoc-in [:messages chat-id] {})
(update-in [:message-lists] dissoc chat-id)
(update :chats (fn [chats]
(if (contains? chats chat-id)
(update chats chat-id merge
{:last-message nil
:unviewed-messages-count 0
:unviewed-mentions-count 0
:deleted-at-clock-value last-message-clock-value})
chats))))}))
{:db (-> db
(assoc-in [:messages chat-id] {})
(update-in [:message-lists] dissoc chat-id)
(update :chats
(fn [chats]
(if (contains? chats chat-id)
(update chats
chat-id
merge
{:last-message nil
:unviewed-messages-count 0
:unviewed-mentions-count 0
:deleted-at-clock-value last-message-clock-value})
chats))))}))
(fx/defn clear-history-handler
(rf/defn clear-history-handler
"Clears history of the particular chat"
{:events [:chat.ui/clear-history]}
[{:keys [db] :as cofx} chat-id remove-chat?]
(fx/merge cofx
{:db db
::json-rpc/call [{:method "wakuext_clearHistory"
:params [{:id chat-id}]
(rf/merge cofx
{:db db
::json-rpc/call [{:method "wakuext_clearHistory"
:params [{:id chat-id}]
:on-success #(re-frame/dispatch [::history-cleared chat-id %])
:on-error #(log/error "failed to clear history " chat-id %)}]}
:on-error #(log/error "failed to clear history " chat-id %)}]}
(clear-history chat-id remove-chat?)))
(fx/defn chat-deactivated
(rf/defn chat-deactivated
{:events [::chat-deactivated]}
[_ chat-id]
(log/debug "chat deactivated" chat-id))
(fx/defn deactivate-chat
(rf/defn deactivate-chat
"Deactivate chat in db, no side effects"
[{:keys [db now] :as cofx} chat-id]
(fx/merge
(rf/merge
cofx
{:db (-> (if (get-in db [:chats chat-id :muted])
(assoc-in db [:chats chat-id :active] false)
(update db :chats dissoc chat-id))
(update :chats-home-list disj chat-id)
(assoc :current-chat-id nil))
::json-rpc/call [{:method "wakuext_deactivateChat"
:params [{:id chat-id}]
{:db (-> (if (get-in db [:chats chat-id :muted])
(assoc-in db [:chats chat-id :active] false)
(update db :chats dissoc chat-id))
(update :chats-home-list disj chat-id)
(assoc :current-chat-id nil))
::json-rpc/call [{:method "wakuext_deactivateChat"
:params [{:id chat-id}]
:on-success #(re-frame/dispatch [::chat-deactivated chat-id])
:on-error #(log/error "failed to create public chat" chat-id %)}]}
:on-error #(log/error "failed to create public chat" chat-id %)}]}
(clear-history chat-id true)))
(fx/defn offload-messages
(rf/defn offload-messages
{:events [:offload-messages]}
[{:keys [db]} chat-id]
(merge {:db (-> db
@@ -208,52 +219,52 @@
(when (and (= chat-id constants/timeline-chat-id) (= (:view-id db) :status))
{:dispatch [:init-timeline-chat]})))
(fx/defn close-chat
(rf/defn close-chat
{:events [:close-chat]}
[{:keys [db] :as cofx}]
(when-let [chat-id (:current-chat-id db)]
(chat.state/reset-visible-item)
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :current-chat-id)}
(delete-for-me/sync-all)
(delete-message/send-all)
(offload-messages chat-id))))
(fx/defn force-close-chat
(rf/defn force-close-chat
[{:keys [db] :as cofx} chat-id]
(do
(chat.state/reset-visible-item)
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :current-chat-id)}
(offload-messages chat-id))))
(fx/defn remove-chat
(rf/defn remove-chat
"Removes chat completely from app, producing all necessary effects for that"
{:events [:chat.ui/remove-chat]}
[{:keys [db now] :as cofx} chat-id]
(fx/merge cofx
(rf/merge cofx
{:clear-message-notifications
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
(deactivate-chat chat-id)
(offload-messages chat-id)))
(fx/defn show-more-chats
(rf/defn show-more-chats
{:events [:chat.ui/show-more-chats]}
[{:keys [db]}]
(when (< (:home-items-show-number db) (count (:chats db)))
{:db (update db :home-items-show-number + 40)}))
(fx/defn preload-chat-data
(rf/defn preload-chat-data
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
{:events [:chat.ui/preload-chat-data]}
[cofx chat-id]
(loading/load-messages cofx chat-id))
(fx/defn navigate-to-chat
(rf/defn navigate-to-chat
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
{:events [:chat.ui/navigate-to-chat]}
[{db :db :as cofx} chat-id]
(fx/merge cofx
(rf/merge cofx
{:dispatch [:navigate-to :chat]}
(navigation/change-tab :chat)
(when-not (= (:view-id db) :community)
@@ -266,11 +277,11 @@
#(when (group-chat? cofx chat-id)
(loading/load-chat % chat-id))))
(fx/defn navigate-to-chat-nav2
(rf/defn navigate-to-chat-nav2
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
{:events [:chat.ui/navigate-to-chat-nav2]}
[{db :db :as cofx} chat-id from-shell?]
(fx/merge cofx
(rf/merge cofx
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
(when-not (= (:view-id db) :community)
(navigation/pop-to-root-tab :shell-stack))
@@ -282,65 +293,68 @@
#(when (group-chat? cofx chat-id)
(loading/load-chat % chat-id))))
(fx/defn handle-clear-history-response
(rf/defn handle-clear-history-response
{:events [::history-cleared]}
[{:keys [db]} chat-id response]
(let [chat (chats-store/<-rpc (first (:chats response)))]
{:db (assoc-in db [:chats chat-id] chat)}))
(fx/defn handle-one-to-one-chat-created
(rf/defn handle-one-to-one-chat-created
{:events [::one-to-one-chat-created]}
[{:keys [db]} chat-id response]
(let [chat (chats-store/<-rpc (first (:chats response)))
(let [chat (chats-store/<-rpc (first (:chats response)))
contact-rpc (first (:contacts response))
contact (when contact-rpc (contacts-store/<-rpc contact-rpc))]
{:db (cond-> db
contact
(assoc-in [:contacts/contacts chat-id] contact)
:always
(assoc-in [:chats chat-id] chat)
:always
(update :chats-home-list conj chat-id))
contact (when contact-rpc (contacts-store/<-rpc contact-rpc))]
{:db (cond-> db
contact
(assoc-in [:contacts/contacts chat-id] contact)
:always
(assoc-in [:chats chat-id] chat)
:always
(update :chats-home-list conj chat-id))
:dispatch [:chat.ui/navigate-to-chat chat-id]}))
(fx/defn navigate-to-user-pinned-messages
(rf/defn navigate-to-user-pinned-messages
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
{:events [:chat.ui/navigate-to-pinned-messages]}
[cofx chat-id]
(navigation/navigate-to cofx :chat-pinned-messages {:chat-id chat-id}))
(fx/defn start-chat
(rf/defn start-chat
"Start a chat, making sure it exists"
{:events [:chat.ui/start-chat]}
[{:keys [db] :as cofx} chat-id ens-name]
;; don't allow to open chat with yourself
(when (not= (multiaccounts.model/current-public-key cofx) chat-id)
{::json-rpc/call [{:method "wakuext_createOneToOneChat"
:params [{:id chat-id :ensName ens-name}]
{::json-rpc/call [{:method "wakuext_createOneToOneChat"
:params [{:id chat-id :ensName ens-name}]
:on-success #(re-frame/dispatch [::one-to-one-chat-created chat-id %])
:on-error #(log/error "failed to create one-to-on chat" chat-id %)}]}))
:on-error #(log/error "failed to create one-to-on chat" chat-id %)}]}))
(defn profile-chat-topic [public-key]
(defn profile-chat-topic
[public-key]
(str "@" public-key))
(defn my-profile-chat-topic [db]
(defn my-profile-chat-topic
[db]
(profile-chat-topic (get-in db [:multiaccount :public-key])))
(fx/defn handle-public-chat-created
(rf/defn handle-public-chat-created
{:events [::public-chat-created]}
[{:keys [db]} chat-id response]
{:db (-> db
(assoc-in [:chats chat-id] (chats-store/<-rpc (first (:chats response))))
(update :chats-home-list conj chat-id))
{:db (-> db
(assoc-in [:chats chat-id] (chats-store/<-rpc (first (:chats response))))
(update :chats-home-list conj chat-id))
:dispatch [:chat.ui/navigate-to-chat chat-id]})
(fx/defn create-public-chat-go [_ chat-id]
{::json-rpc/call [{:method "wakuext_createPublicChat"
:params [{:id chat-id}]
(rf/defn create-public-chat-go
[_ chat-id]
{::json-rpc/call [{:method "wakuext_createPublicChat"
:params [{:id chat-id}]
:on-success #(re-frame/dispatch [::public-chat-created chat-id %])
:on-error #(log/error "failed to create public chat" chat-id %)}]})
:on-error #(log/error "failed to create public chat" chat-id %)}]})
(fx/defn start-public-chat
(rf/defn start-public-chat
"Starts a new public chat"
{:events [:chat.ui/start-public-chat]}
[cofx topic]
@@ -353,10 +367,10 @@
{:utils/show-popup {:title (i18n/label :t/cant-open-public-chat)
:content (i18n/label :t/invalid-public-chat-topic)}}))
(fx/defn profile-chat-created
(rf/defn profile-chat-created
{:events [::profile-chat-created]}
[{:keys [db] :as cofx} chat-id response navigate-to?]
(fx/merge
(rf/merge
cofx
{:db db}
#(when response
@@ -366,19 +380,19 @@
{:dispatch-n [[:chat.ui/preload-chat-data chat-id]
[:open-modal :profile]]})))
(fx/defn start-profile-chat
(rf/defn start-profile-chat
"Starts a new profile chat"
{:events [:start-profile-chat]}
[cofx profile-public-key navigate-to?]
(let [chat-id (profile-chat-topic profile-public-key)]
(if (active-chat? cofx chat-id)
{:dispatch [::profile-chat-created chat-id nil navigate-to?]}
{::json-rpc/call [{:method "wakuext_createProfileChat"
:params [{:id profile-public-key}]
{::json-rpc/call [{:method "wakuext_createProfileChat"
:params [{:id profile-public-key}]
:on-success #(re-frame/dispatch [::profile-chat-created chat-id % navigate-to?])
:on-error #(log/error "failed to create profile chat" chat-id %)}]})))
:on-error #(log/error "failed to create profile chat" chat-id %)}]})))
(fx/defn disable-chat-cooldown
(rf/defn disable-chat-cooldown
"Turns off chat cooldown (protection against message spamming)"
{:events [:chat/disable-cooldown]}
[{:keys [db]}]
@@ -392,40 +406,40 @@
(i18n/label :cooldown/warning-message)
#())))
(fx/defn mute-chat-failed
(rf/defn mute-chat-failed
{:events [::mute-chat-failed]}
[{:keys [db] :as cofx} chat-id muted? error]
(log/error "mute chat failed" chat-id error)
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
(fx/defn mute-chat-toggled-successfully
(rf/defn mute-chat-toggled-successfully
{:events [::mute-chat-toggled-successfully]}
[_ chat-id]
(log/debug "muted chat successfully" chat-id))
(fx/defn mute-chat
(rf/defn mute-chat
{:events [::mute-chat-toggled]}
[{:keys [db] :as cofx} chat-id muted?]
(let [method (if muted? "wakuext_muteChat" "wakuext_unmuteChat")]
{:db (assoc-in db [:chats chat-id :muted] muted?)
::json-rpc/call [{:method method
:params [chat-id]
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
{:db (assoc-in db [:chats chat-id :muted] muted?)
::json-rpc/call [{:method method
:params [chat-id]
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
:on-success #(re-frame/dispatch [::mute-chat-toggled-successfully chat-id])}]}))
(fx/defn show-profile
(rf/defn show-profile
{:events [:chat.ui/show-profile]}
[{:keys [db] :as cofx} identity ens-name]
(let [my-public-key (get-in db [:multiaccount :public-key])]
(when (not= my-public-key identity)
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc :contacts/identity identity)
(assoc :contacts/ens-name ens-name))}
(start-profile-chat identity true)))))
(fx/defn clear-history-pressed
(rf/defn clear-history-pressed
{:events [:chat.ui/clear-history-pressed]}
[_ chat-id]
{:ui/show-confirmation
@@ -436,19 +450,19 @@
(re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
(fx/defn gaps-failed
(rf/defn gaps-failed
{:events [::gaps-failed]}
[{:keys [db]} chat-id gap-ids error]
(log/error "failed to fetch gaps" chat-id gap-ids error)
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
(fx/defn sync-chat-from-sync-from-failed
(rf/defn sync-chat-from-sync-from-failed
{:events [::sync-chat-from-sync-from-failed]}
[{:keys [db]} chat-id error]
(log/error "failed to sync chat" chat-id error)
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
(fx/defn sync-chat-from-sync-from-success
(rf/defn sync-chat-from-sync-from-success
{:events [::sync-chat-from-sync-from-success]}
[{:keys [db] :as cofx} chat-id synced-from]
(log/debug "synced success" chat-id synced-from)
@@ -457,44 +471,44 @@
(assoc-in [:chats chat-id :synced-from] synced-from)
(dissoc :mailserver/fetching-gaps-in-progress))})
(fx/defn gaps-filled
(rf/defn gaps-filled
{:events [::gaps-filled]}
[{:keys [db] :as cofx} chat-id message-ids]
(fx/merge
(rf/merge
cofx
{:db (-> db
(update-in [:messages chat-id] (fn [messages] (apply dissoc messages message-ids)))
(dissoc :mailserver/fetching-gaps-in-progress))}
(message-list/rebuild-message-list chat-id)))
(fx/defn fill-gaps
(rf/defn fill-gaps
[cofx chat-id gap-ids]
{::json-rpc/call [{:method "wakuext_fillGaps"
:params [chat-id gap-ids]
{::json-rpc/call [{:method "wakuext_fillGaps"
:params [chat-id gap-ids]
:on-success #(re-frame/dispatch [::gaps-filled chat-id gap-ids %])
:on-error #(re-frame/dispatch [::gaps-failed chat-id gap-ids %])}]})
:on-error #(re-frame/dispatch [::gaps-failed chat-id gap-ids %])}]})
(fx/defn sync-chat-from-sync-from
(rf/defn sync-chat-from-sync-from
[cofx chat-id]
(log/debug "syncing chat from sync from")
{::json-rpc/call [{:method "wakuext_syncChatFromSyncedFrom"
:params [chat-id]
{::json-rpc/call [{:method "wakuext_syncChatFromSyncedFrom"
:params [chat-id]
:on-success #(re-frame/dispatch [::sync-chat-from-sync-from-success chat-id %])
:on-error #(re-frame/dispatch [::sync-chat-from-sync-from-failed chat-id %])}]})
:on-error #(re-frame/dispatch [::sync-chat-from-sync-from-failed chat-id %])}]})
(fx/defn chat-ui-fill-gaps
(rf/defn chat-ui-fill-gaps
{:events [:chat.ui/fill-gaps]}
[{:keys [db] :as cofx} chat-id gap-ids]
(let [use-status-nodes? (mailserver/fetch-use-mailservers? {:db db})]
(log/info "filling gaps if use-status-nodes = true" chat-id gap-ids)
(when use-status-nodes?
(fx/merge cofx
(rf/merge cofx
{:db (assoc db :mailserver/fetching-gaps-in-progress gap-ids)}
(if (= gap-ids #{:first-gap})
(sync-chat-from-sync-from chat-id)
(fill-gaps chat-id gap-ids))))))
(fx/defn chat-ui-remove-chat-pressed
(rf/defn chat-ui-remove-chat-pressed
{:events [:chat.ui/remove-chat-pressed]}
[_ chat-id]
{:ui/show-confirmation
@@ -505,7 +519,7 @@
(re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch [:chat.ui/remove-chat chat-id]))}})
(fx/defn decrease-unviewed-count
(rf/defn decrease-unviewed-count
{:events [:chat/decrease-unviewed-count]}
[{:keys [db]} chat-id {:keys [count countWithMentions]}]
{:db (-> db
+70 -41
View File
@@ -1,24 +1,25 @@
(ns status-im.chat.models.images
(:require [re-frame.core :as re-frame]
[status-im.utils.fx :as fx]
["@react-native-community/cameraroll" :as CameraRoll]
(:require ["@react-native-community/cameraroll" :as CameraRoll]
["react-native-blob-util" :default ReactNativeBlobUtil]
[status-im.utils.types :as types]
[status-im.utils.config :as config]
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.chat.models :as chat]
[status-im.i18n.i18n :as i18n]
[status-im.ui.components.permissions :as permissions]
[status-im.ui.components.react :as react]
[status-im.utils.image-processing :as image-processing]
[taoensso.timbre :as log]
[clojure.string :as string]
[status-im.i18n.i18n :as i18n]
[status-im.utils.utils :as utils]
[status-im.utils.platform :as platform]
[status-im.utils.config :as config]
[status-im.utils.fs :as fs]
[status-im.chat.models :as chat]))
[status-im.utils.image-processing :as image-processing]
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(def maximum-image-size-px 2000)
(defn- resize-and-call [uri cb]
(defn- resize-and-call
[uri cb]
(react/image-get-size
uri
(fn [width height]
@@ -34,16 +35,19 @@
(cb path)))
#(log/error "could not resize image" %))))))
(defn result->id [^js result]
(defn result->id
[^js result]
(if platform/ios?
(.-localIdentifier result)
(.-path result)))
(def temp-image-url (str (fs/cache-dir) "/StatusIm_Image.jpeg"))
(defn download-image-http [base64-uri on-success]
(-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?
:path temp-image-url}))
(defn download-image-http
[base64-uri on-success]
(-> (.config ReactNativeBlobUtil
(clj->js {:trusty platform/ios?
:path temp-image-url}))
(.fetch "GET" base64-uri)
(.then #(on-success (.path %)))
(.catch #(log/error "could not save image"))))
@@ -70,7 +74,8 @@
::chat-open-image-picker-camera
(fn [current-chat-id]
(react/show-image-picker-camera
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)]) {})))
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)])
{})))
(re-frame/reg-fx
::chat-open-image-picker
@@ -100,15 +105,22 @@
(re-frame/reg-fx
::camera-roll-get-photos
(fn [num]
(fn [[num end-cursor]]
(permissions/request-permissions
{:permissions [:read-external-storage]
:on-allowed (fn []
(-> (.getPhotos CameraRoll #js {:first num :assetType "Photos" :groupTypes "All"})
(.then #(re-frame/dispatch [:on-camera-roll-get-photos (:edges (types/js->clj %))]))
(.catch #(log/warn "could not get cameraroll photos"))))})))
(-> (if end-cursor
(.getPhotos
CameraRoll
#js {:first num :after end-cursor :assetType "Photos" :groupTypes "All"})
(.getPhotos CameraRoll
#js {:first num :assetType "Photos" :groupTypes "All"}))
(.then #(let [response (types/js->clj %)]
(re-frame/dispatch [:on-camera-roll-get-photos (:edges response)
(:page_info response) end-cursor])))
(.catch #(log/warn "could not get camera roll photos"))))})))
(fx/defn image-captured
(rf/defn image-captured
{:events [:chat.ui/image-captured]}
[{:keys [db]} chat-id uri]
(let [current-chat-id (or chat-id (:current-chat-id db))
@@ -117,44 +129,61 @@
(not (get images uri)))
{::image-selected [uri current-chat-id]})))
(fx/defn camera-roll-get-photos
(rf/defn on-end-reached
{:events [:camera-roll/on-end-reached]}
[_ end-cursor loading? has-next-page?]
(when (and (not loading?) has-next-page?)
(re-frame/dispatch [:chat.ui/camera-roll-loading-more true])
(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20 end-cursor])))
(rf/defn camera-roll-get-photos
{:events [:chat.ui/camera-roll-get-photos]}
[_ num]
{::camera-roll-get-photos num})
[_ num end-cursor]
{::camera-roll-get-photos [num end-cursor]})
(fx/defn on-camera-roll-get-photos
(rf/defn camera-roll-loading-more
{:events [:chat.ui/camera-roll-loading-more]}
[{:keys [db]} is-loading]
{:db (assoc db :camera-roll/loading-more is-loading)})
(rf/defn on-camera-roll-get-photos
{:events [:on-camera-roll-get-photos]}
[{db :db} photos]
{:db (assoc db :camera-roll-photos (mapv #(get-in % [:node :image :uri]) photos))})
[{:keys [db] :as cofx} photos page-info end-cursor]
(let [photos_x (when end-cursor (:camera-roll/photos db))]
{:db (-> db
(assoc :camera-roll/photos (concat photos_x (map #(get-in % [:node :image :uri]) photos)))
(assoc :camera-roll/end-cursor (:end_cursor page-info))
(assoc :camera-roll/has-next-page (:has_next_page page-info))
(assoc :camera-roll/loading-more false))}))
(fx/defn clear-sending-images
(rf/defn clear-sending-images
{:events [:chat.ui/clear-sending-images]}
[{:keys [db]} current-chat-id]
{:db (update-in db [:chat/inputs current-chat-id :metadata] assoc :sending-image {})})
(fx/defn cancel-sending-image
(rf/defn cancel-sending-image
{:events [:chat.ui/cancel-sending-image]}
[{:keys [db] :as cofx} chat-id]
(let [current-chat-id (or chat-id (:current-chat-id db))]
(clear-sending-images cofx current-chat-id)))
(fx/defn cancel-sending-image-timeline
(rf/defn cancel-sending-image-timeline
{:events [:chat.ui/cancel-sending-image-timeline]}
[{:keys [db] :as cofx}]
(cancel-sending-image cofx (chat/my-profile-chat-topic db)))
(fx/defn image-selected
(rf/defn image-selected
{:events [:chat.ui/image-selected]}
[{:keys [db]} current-chat-id original uri]
{:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image original] merge {:uri uri})})
(fx/defn image-unselected
(rf/defn image-unselected
{:events [:chat.ui/image-unselected]}
[{:keys [db]} original]
(let [current-chat-id (:current-chat-id db)]
{:db (update-in db [:chat/inputs current-chat-id :metadata :sending-image] dissoc original)}))
(fx/defn chat-open-image-picker
(rf/defn chat-open-image-picker
{:events [:chat.ui/open-image-picker]}
[{:keys [db]} chat-id]
(let [current-chat-id (or chat-id (:current-chat-id db))
@@ -162,12 +191,12 @@
(when (< (count images) config/max-images-batch)
{::chat-open-image-picker current-chat-id})))
(fx/defn chat-open-image-picker-timeline
(rf/defn chat-open-image-picker-timeline
{:events [:chat.ui/open-image-picker-timeline]}
[{:keys [db] :as cofx}]
(chat-open-image-picker cofx (chat/my-profile-chat-topic db)))
(fx/defn chat-show-image-picker-camera
(rf/defn chat-show-image-picker-camera
{:events [:chat.ui/show-image-picker-camera]}
[{:keys [db]} chat-id]
(let [current-chat-id (or chat-id (:current-chat-id db))
@@ -175,12 +204,12 @@
(when (< (count images) config/max-images-batch)
{::chat-open-image-picker-camera current-chat-id})))
(fx/defn chat-show-image-picker-camera-timeline
(rf/defn chat-show-image-picker-camera-timeline
{:events [:chat.ui/show-image-picker-camera-timeline]}
[{:keys [db] :as cofx}]
(chat-show-image-picker-camera cofx (chat/my-profile-chat-topic db)))
(fx/defn camera-roll-pick
(rf/defn camera-roll-pick
{:events [:chat.ui/camera-roll-pick]}
[{:keys [db]} uri chat-id]
(let [current-chat-id (or chat-id (:current-chat-id db))
@@ -192,12 +221,12 @@
(not (get images uri)))
{::image-selected [uri current-chat-id]}))))
(fx/defn camera-roll-pick-timeline
(rf/defn camera-roll-pick-timeline
{:events [:chat.ui/camera-roll-pick-timeline]}
[{:keys [db] :as cofx} uri]
(camera-roll-pick cofx uri (chat/my-profile-chat-topic db)))
(fx/defn save-image-to-gallery
(rf/defn save-image-to-gallery
{:events [:chat.ui/save-image-to-gallery]}
[_ base64-uri]
{::save-image-to-gallery base64-uri})
+117 -98
View File
@@ -12,9 +12,9 @@
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[status-im.utils.datetime :as datetime]
[status-im.utils.fx :as fx]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn text->emoji
"Replaces emojis in a specified `text`"
@@ -26,7 +26,7 @@
(.-char ^js emoji-map)
original))))
(fx/defn set-chat-input-text
(rf/defn set-chat-input-text
"Set input text for current-chat. Takes db and input text and cofx
as arguments and returns new fx. Always clear all validation messages."
{:events [:chat.ui/set-chat-input-text]}
@@ -34,24 +34,25 @@
(let [current-chat-id (or chat-id (:current-chat-id db))]
{:db (assoc-in db [:chat/inputs current-chat-id :input-text] (text->emoji new-input))}))
(fx/defn set-timeline-input-text
(rf/defn set-timeline-input-text
{:events [:chat.ui/set-timeline-input-text]}
[{db :db} new-input]
{:db (assoc-in db [:chat/inputs (chat/my-profile-chat-topic db) :input-text]
(text->emoji new-input))})
{:db (assoc-in db
[:chat/inputs (chat/my-profile-chat-topic db) :input-text]
(text->emoji new-input))})
(fx/defn select-mention
(rf/defn select-mention
{:events [:chat.ui/select-mention]}
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
(let [chat-id (:current-chat-id db)
new-text (mentions/new-input-text-with-mention cofx user)
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
cursor (+ at-sign-idx (count name) 2)]
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc-in [:chats/cursor chat-id] cursor)
(assoc-in [:chats/mention-suggestions chat-id] nil))
{:db (-> db
(assoc-in [:chats/cursor chat-id] cursor)
(assoc-in [:chats/mention-suggestions chat-id] nil))
:set-text-input-value [chat-id new-text text-input-ref]}
(set-chat-input-text new-text chat-id)
;; NOTE(rasom): Some keyboards do not react on selection property passed to
@@ -74,67 +75,77 @@
:end end}))
(mentions/recheck-at-idxs {alias user}))))
(defn- start-cooldown [{:keys [db]} cooldowns]
(defn- start-cooldown
[{:keys [db]} cooldowns]
{:dispatch-later [{:dispatch [:chat/disable-cooldown]
:ms (chat.constants/cooldown-periods-ms
cooldowns
chat.constants/default-cooldown-period-ms)}]
:show-cooldown-warning nil
:db (assoc db
:chat/cooldowns (if (= chat.constants/cooldown-reset-threshold cooldowns)
0
cooldowns)
:chat/cooldowns (if
(=
chat.constants/cooldown-reset-threshold
cooldowns)
0
cooldowns)
:chat/spam-messages-frequency 0
:chat/cooldown-enabled? true)})
:chat/cooldown-enabled? true)})
(fx/defn process-cooldown
(rf/defn process-cooldown
"Process cooldown to protect against message spammers"
[{{:keys [chat/last-outgoing-message-sent-at
chat/cooldowns
chat/spam-messages-frequency
current-chat-id] :as db} :db :as cofx}]
current-chat-id]
:as db}
:db
:as cofx}]
(when (chat/public-chat? cofx current-chat-id)
(let [spamming-fast? (< (- (datetime/timestamp) last-outgoing-message-sent-at)
(+ chat.constants/spam-interval-ms (* 1000 cooldowns)))
spamming-frequently? (= chat.constants/spam-message-frequency-threshold spam-messages-frequency)]
(let [spamming-fast? (< (- (datetime/timestamp) last-outgoing-message-sent-at)
(+ chat.constants/spam-interval-ms (* 1000 cooldowns)))
spamming-frequently? (= chat.constants/spam-message-frequency-threshold
spam-messages-frequency)]
(cond-> {:db (assoc db
:chat/last-outgoing-message-sent-at (datetime/timestamp)
:chat/spam-messages-frequency (if spamming-fast?
(inc spam-messages-frequency)
0))}
:chat/spam-messages-frequency (if spamming-fast?
(inc spam-messages-frequency)
0))}
(and spamming-fast? spamming-frequently?)
(start-cooldown (inc cooldowns))))))
(fx/defn reply-to-message
(rf/defn reply-to-message
"Sets reference to previous chat message and focuses on input"
{:events [:chat.ui/reply-to-message]}
[{:keys [db] :as cofx} message]
(let [current-chat-id (:current-chat-id db)]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message]
message)
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message] nil)
(update-in [:chat/inputs current-chat-id :metadata]
dissoc :sending-image))})))
dissoc
:sending-image))})))
(fx/defn edit-message
(rf/defn edit-message
"Sets reference to previous chat message and focuses on input"
{:events [:chat.ui/edit-message]}
[{:keys [db] :as cofx} message]
(let [current-chat-id (:current-chat-id db)
text (get-in message [:content :text])]
text (get-in message [:content :text])]
{:dispatch [:chat.ui.input/set-chat-input-text text current-chat-id]
:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
message)
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
(update-in [:chat/inputs current-chat-id :metadata]
dissoc :sending-image))}))
:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message]
message)
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil)
(update-in [:chat/inputs current-chat-id :metadata]
dissoc
:sending-image))}))
(fx/defn show-contact-request-input
(rf/defn show-contact-request-input
"Sets reference to previous chat message and focuses on input"
{:events [:chat.ui/send-contact-request]}
[{:keys [db] :as cofx}]
@@ -146,9 +157,10 @@
nil)
(assoc-in [:chat/inputs current-chat-id :metadata :editing-message] nil)
(update-in [:chat/inputs current-chat-id :metadata]
dissoc :sending-image))}))
dissoc
:sending-image))}))
(fx/defn cancel-message-reply
(rf/defn cancel-message-reply
"Cancels stage message reply"
{:events [:chat.ui/cancel-message-reply]}
[{:keys [db]}]
@@ -160,16 +172,16 @@
(when-not (string/blank? input-text)
(let [{:keys [message-id]}
(get-in db [:chat/inputs current-chat-id :metadata :responding-to-message])
preferred-name (get-in db [:multiaccount :preferred-name])
emoji? (message-content/emoji-only-content? {:text input-text
:response-to message-id})]
preferred-name (get-in db [:multiaccount :preferred-name])
emoji? (message-content/emoji-only-content? {:text input-text
:response-to message-id})]
{:chat-id current-chat-id
:content-type (if emoji?
constants/content-type-emoji
constants/content-type-text)
:text input-text
:response-to message-id
:ens-name preferred-name})))
:text input-text
:response-to message-id
:ens-name preferred-name})))
(defn build-image-messages
[{db :db} chat-id]
@@ -181,8 +193,9 @@
:text (i18n/label :t/update-to-see-image {"locale" "en"})})
images)))
(fx/defn clean-input [{:keys [db] :as cofx} current-chat-id]
(fx/merge cofx
(rf/defn clean-input
[{:keys [db] :as cofx} current-chat-id]
(rf/merge cofx
{:db (-> db
(assoc-in [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)
(assoc-in [:chat/inputs current-chat-id :metadata :sending-image] nil)
@@ -190,131 +203,137 @@
(assoc-in [:chat/inputs current-chat-id :metadata :responding-to-message] nil))}
(set-chat-input-text nil current-chat-id)))
(fx/defn cancel-message-edit
(rf/defn cancel-message-edit
"Cancels stage message edit"
{:events [:chat.ui/cancel-message-edit]}
[{:keys [db] :as cofx}]
(let [current-chat-id (:current-chat-id db)]
(fx/merge cofx
(rf/merge cofx
{:set-text-input-value [current-chat-id ""]}
(clean-input current-chat-id)
(mentions/clear-mentions)
(mentions/clear-cursor))))
(fx/defn send-messages [{:keys [db] :as cofx} input-text current-chat-id]
(rf/defn send-messages
[{:keys [db] :as cofx} input-text current-chat-id]
(let [image-messages (build-image-messages cofx current-chat-id)
text-message (build-text-message cofx input-text current-chat-id)
messages (keep identity (conj image-messages text-message))]
text-message (build-text-message cofx input-text current-chat-id)
messages (keep identity (conj image-messages text-message))]
(when (seq messages)
(fx/merge cofx
(rf/merge cofx
(clean-input (:current-chat-id db))
(process-cooldown)
(chat.message/send-messages messages)))))
(fx/defn send-my-status-message
(rf/defn send-my-status-message
"when not empty, proceed by sending text message with public key topic"
{:events [:profile.ui/send-my-status-message]}
[{db :db :as cofx}]
(let [current-chat-id (chat/my-profile-chat-topic db)
(let [current-chat-id (chat/my-profile-chat-topic db)
{:keys [input-text]} (get-in db [:chat/inputs current-chat-id])
image-messages (build-image-messages cofx current-chat-id)
text-message (build-text-message cofx input-text current-chat-id)
messages (keep identity (conj image-messages text-message))]
image-messages (build-image-messages cofx current-chat-id)
text-message (build-text-message cofx input-text current-chat-id)
messages (keep identity (conj image-messages text-message))]
(when (seq messages)
(fx/merge cofx
(rf/merge cofx
(clean-input current-chat-id)
(chat.message/send-messages messages)))))
(fx/defn send-audio-message
(rf/defn send-audio-message
[cofx audio-path duration current-chat-id]
(when-not (string/blank? audio-path)
(chat.message/send-message cofx {:chat-id current-chat-id
:content-type constants/content-type-audio
:audio-path audio-path
:audio-duration-ms duration
:text (i18n/label :t/update-to-listen-audio {"locale" "en"})})))
(chat.message/send-message
cofx
{:chat-id current-chat-id
:content-type constants/content-type-audio
:audio-path audio-path
:audio-duration-ms duration
:text (i18n/label :t/update-to-listen-audio {"locale" "en"})})))
(fx/defn send-sticker-message
(rf/defn send-sticker-message
[cofx {:keys [hash packID pack]} current-chat-id]
(when-not (or (string/blank? hash) (and (string/blank? packID) (string/blank? pack)))
(chat.message/send-message cofx {:chat-id current-chat-id
:content-type constants/content-type-sticker
:sticker {:hash hash
(chat.message/send-message cofx
{:chat-id current-chat-id
:content-type constants/content-type-sticker
:sticker {:hash hash
:pack (int (if (string/blank? packID) pack packID))}
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})})))
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})})))
(fx/defn send-edited-message [{:keys [db] :as cofx} text {:keys [message-id quoted-message]}]
(fx/merge
(rf/defn send-edited-message
[{:keys [db] :as cofx} text {:keys [message-id quoted-message]}]
(rf/merge
cofx
{::json-rpc/call [{:method "wakuext_editMessage"
:params [{:id message-id
:text text
:content-type (if (message-content/emoji-only-content? {:text text :response-to quoted-message})
constants/content-type-emoji
constants/content-type-text)}]
{::json-rpc/call [{:method "wakuext_editMessage"
:params [{:id message-id
:text text
:content-type (if (message-content/emoji-only-content?
{:text text :response-to quoted-message})
constants/content-type-emoji
constants/content-type-text)}]
:js-response true
:on-error #(log/error "failed to edit message " %)
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}
:on-error #(log/error "failed to edit message " %)
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}
(cancel-message-edit)
(process-cooldown)))
(fx/defn send-current-message
(rf/defn send-current-message
"Sends message from current chat input"
{:events [:chat.ui/send-current-message]}
[{{:keys [current-chat-id] :as db} :db :as cofx}]
(let [{:keys [input-text metadata]} (get-in db [:chat/inputs current-chat-id])
editing-message (:editing-message metadata)
input-text-with-mentions (mentions/check-mentions cofx input-text)]
(fx/merge cofx
editing-message (:editing-message metadata)
input-text-with-mentions (mentions/check-mentions cofx input-text)]
(rf/merge cofx
(if editing-message
(send-edited-message input-text-with-mentions editing-message)
(send-messages input-text-with-mentions current-chat-id))
(mentions/clear-mentions)
(mentions/clear-cursor))))
(fx/defn send-contact-request
(rf/defn send-contact-request
{:events [:contacts/send-contact-request]}
[{:keys [db] :as cofx} public-key message]
(fx/merge cofx
(rf/merge cofx
{:chat.ui/clear-inputs nil
:chat.ui/clear-inputs-old nil
::json-rpc/call [{:method "wakuext_sendContactRequest"
::json-rpc/call [{:method "wakuext_sendContactRequest"
:js-response true
:params [{:id public-key :message message}]
:on-error #(log/warn "failed to send a contact request" %)
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
:params [{:id public-key :message message}]
:on-error #(log/warn "failed to send a contact request" %)
:on-success #(re-frame/dispatch [:transport/message-sent %])}]}
(mentions/clear-mentions)
(mentions/clear-cursor)
(clean-input (:current-chat-id db))
(process-cooldown)))
(fx/defn cancel-contact-request
(rf/defn cancel-contact-request
"Cancels contact request"
{:events [:chat.ui/cancel-contact-request]}
[{:keys [db] :as cofx}]
(let [current-chat-id (:current-chat-id db)]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :sending-contact-request] nil)}
(mentions/clear-mentions)
(mentions/clear-cursor)
(clean-input (:current-chat-id db))
(process-cooldown))))
(fx/defn chat-send-sticker
(rf/defn chat-send-sticker
{:events [:chat/send-sticker]}
[{{:keys [current-chat-id] :as db} :db :as cofx} {:keys [hash packID pack] :as sticker}]
(fx/merge
(rf/merge
cofx
{:db (update db
:stickers/recent-stickers
(fn [recent]
(conj (remove #(= hash (:hash %)) recent) sticker)))
{:db (update db
:stickers/recent-stickers
(fn [recent]
(conj (remove #(= hash (:hash %)) recent) sticker)))
::json-rpc/call [{:method "stickers_addRecent"
:params [(int (if (string/blank? packID) pack packID)) hash]
:on-success #()}]}
(send-sticker-message sticker current-chat-id)))
(fx/defn chat-send-audio
(rf/defn chat-send-audio
{:events [:chat/send-audio]}
[{{:keys [current-chat-id]} :db :as cofx} audio-path duration]
(send-audio-message cofx audio-path duration current-chat-id))
+37 -29
View File
@@ -1,15 +1,15 @@
(ns status-im.chat.models.link-preview
(:require [re-frame.core :as re-frame]
[status-im.utils.fx :as fx]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.communities.core :as models.communities]
[taoensso.timbre :as log]))
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn enable
(rf/defn enable
{:events [::enable]}
[{{:keys [multiaccount]} :db :as cofx} site enabled?]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:link-previews-enabled-sites
(if enabled?
@@ -17,10 +17,10 @@
(disj (get multiaccount :link-previews-enabled-sites #{}) site))
{})))
(fx/defn enable-all
(rf/defn enable-all
{:events [::enable-all]}
[{{:keys [multiaccount]} :db :as cofx} link-previews-whitelist enabled?]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:link-previews-enabled-sites
(if enabled?
@@ -28,37 +28,42 @@
#{})
{})))
(defn community-resolved [db community-id]
(defn community-resolved
[db community-id]
(update db :communities/resolve-community-info dissoc community-id))
(defn community-failed-to-resolve [db community-id]
(defn community-failed-to-resolve
[db community-id]
(update db :communities/resolve-community-info dissoc community-id))
(defn community-resolving [db community-id]
(defn community-resolving
[db community-id]
(assoc-in db [:communities/resolve-community-info community-id] true))
(fx/defn handle-community-failed-to-resolve
(rf/defn handle-community-failed-to-resolve
{:events [::community-failed-to-resolve]}
[{:keys [db]} community-id]
{:db (community-failed-to-resolve db community-id)})
(defn community-link [id]
(defn community-link
[id]
(str "https://join.status.im/c/" id))
(fx/defn handle-community-resolved
(rf/defn handle-community-resolved
{:events [::community-resolved]}
[{:keys [db] :as cofx} community-id community]
(fx/merge cofx
(rf/merge cofx
(cond-> {:db (community-resolved db community-id)}
(some? community)
(assoc :dispatch [::cache-link-preview-data
(community-link community-id) community]))
(assoc :dispatch
[::cache-link-preview-data
(community-link community-id) community]))
(models.communities/handle-community community)))
(fx/defn resolve-community-info
(rf/defn resolve-community-info
{:events [::resolve-community-info]}
[{:keys [db]} community-id]
{:db (community-resolving db community-id)
{:db (community-resolving db community-id)
::json-rpc/call [{:method "wakuext_requestCommunityInfoFromMailserver"
:params [community-id]
:on-success #(re-frame/dispatch [::community-resolved community-id %])
@@ -66,17 +71,18 @@
(re-frame/dispatch [::community-failed-to-resolve community-id])
(log/error "Failed to request community info from mailserver"))}]})
(fx/defn load-link-preview-data
(rf/defn load-link-preview-data
{:events [::load-link-preview-data]}
[cofx link]
{::json-rpc/call [{:method "wakuext_getLinkPreviewData"
:params [link]
:on-success #(re-frame/dispatch [::cache-link-preview-data link %])
:on-error #(re-frame/dispatch [::cache-link-preview-data
link
{:error (str "Can't get preview data for " link)}])}]})
:on-error #(re-frame/dispatch
[::cache-link-preview-data
link
{:error (str "Can't get preview data for " link)}])}]})
(fx/defn cache-link-preview-data
(rf/defn cache-link-preview-data
{:events [::cache-link-preview-data]}
[{{:keys [multiaccount]} :db :as cofx} site data]
(multiaccounts.update/optimistic
@@ -90,23 +96,25 @@
(community-link id)
community]))
(fx/defn should-suggest-link-preview
(rf/defn should-suggest-link-preview
{:events [::should-suggest-link-preview]}
[{:keys [db] :as cofx} enabled?]
(multiaccounts.update/multiaccount-update
cofx
:link-preview-request-enabled (boolean enabled?)
:link-preview-request-enabled
(boolean enabled?)
{}))
(fx/defn request-link-preview-whitelist
(rf/defn request-link-preview-whitelist
[_]
{::json-rpc/call [{:method "wakuext_getLinkPreviewWhitelist"
:params []
:on-success #(re-frame/dispatch [::link-preview-whitelist-received %])
:on-error #(log/error "Failed to get link preview whitelist")}]})
(fx/defn save-link-preview-whitelist
(rf/defn save-link-preview-whitelist
{:events [::link-preview-whitelist-received]}
[{:keys [db]} whitelist]
{:db (assoc db :link-previews-whitelist
{:db (assoc db
:link-previews-whitelist
whitelist)})
+53 -43
View File
@@ -1,24 +1,25 @@
(ns status-im.chat.models.loading
(:require [re-frame.core :as re-frame]
[status-im.chat.models.message-list :as message-list]
[status-im.constants :as constants]
[status-im.data-store.chats :as data-store.chats]
[status-im.data-store.messages :as data-store.messages]
[status-im.utils.fx :as fx]
[status-im.chat.models.message-list :as message-list]
[taoensso.timbre :as log]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.activity-center.core :as activity-center]))
[status-im2.contexts.activity-center.events :as activity-center]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn cursor->clock-value
[^js cursor]
(js/parseInt (.substring cursor 51 64)))
(defn clock-value->cursor [clock-value]
(defn clock-value->cursor
[clock-value]
(str "000000000000000000000000000000000000000000000000000"
clock-value
"0x0000000000000000000000000000000000000000000000000000000000000000"))
(fx/defn update-chats-in-app-db
(rf/defn update-chats-in-app-db
{:events [:chats-list/load-success]}
[{:keys [db]} ^js new-chats-js]
(let [{:keys [all-chats chats-home-list]}
@@ -30,27 +31,28 @@
(update :chats-home-list conj chat-id)
:always
(assoc-in [:all-chats chat-id] chat))))
{:all-chats {}
{:all-chats {}
:chats-home-list #{}}
new-chats-js)]
{:db (assoc db :chats all-chats
{:db (assoc db
:chats all-chats
:chats-home-list chats-home-list
:chats/loading? false)}))
:chats/loading? false)}))
(fx/defn load-chat-success
(rf/defn load-chat-success
{:events [:chats-list/load-chat-success]}
[{:keys [db]} ^js chat]
(let [{:keys [chat-id] :as chat} (data-store.chats/<-rpc chat)]
{:db (update-in db [:chats chat-id] merge chat)}))
(fx/defn load-chat
(rf/defn load-chat
[_ chat-id]
{::json-rpc/call [{:method "wakuext_chat"
:params [chat-id]
{::json-rpc/call [{:method "wakuext_chat"
:params [chat-id]
:on-success #(re-frame/dispatch [:chats-list/load-chat-success %])
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
(fx/defn handle-failed-loading-messages
(rf/defn handle-failed-loading-messages
{:events [::failed-loading-messages]}
[{:keys [db]} current-chat-id _ err]
(log/error "failed loading messages" current-chat-id err)
@@ -59,52 +61,55 @@
(defn mark-chat-all-read
[db chat-id]
(update-in db [:chats chat-id] assoc
(update-in db
[:chats chat-id]
assoc
:unviewed-messages-count 0
:unviewed-mentions-count 0
:highlight false))
:highlight false))
(fx/defn handle-mark-all-read-successful
(rf/defn handle-mark-all-read-successful
{:events [::mark-all-read-successful]}
[cofx]
(activity-center/notifications-fetch-unread-count cofx))
(fx/defn handle-mark-all-read-in-community-successful
(rf/defn handle-mark-all-read-in-community-successful
{:events [::mark-all-read-in-community-successful]}
[{:keys [db] :as cofx} chat-ids]
(fx/merge cofx
(rf/merge cofx
{:db (reduce mark-chat-all-read db chat-ids)}
(activity-center/notifications-fetch-unread-count)))
(fx/defn handle-mark-all-read
(rf/defn handle-mark-all-read
{:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]}
[{db :db} chat-id]
{:db (mark-chat-all-read db chat-id)
:clear-message-notifications [[chat-id]
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_markAllRead"
:params [chat-id]
:on-success #(re-frame/dispatch [::mark-all-read-successful])}]})
{:db (mark-chat-all-read db chat-id)
:clear-message-notifications [[chat-id]
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_markAllRead"
:params [chat-id]
:on-success #(re-frame/dispatch [::mark-all-read-successful])}]})
(fx/defn handle-mark-mark-all-read-in-community
(rf/defn handle-mark-mark-all-read-in-community
{:events [:chat.ui/mark-all-read-in-community-pressed]}
[{db :db} community-id]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_markAllReadInCommunity"
:params [community-id]
:on-success #(re-frame/dispatch [::mark-all-read-in-community-successful %])}]}))
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_markAllReadInCommunity"
:params [community-id]
:on-success #(re-frame/dispatch
[::mark-all-read-in-community-successful %])}]}))
(fx/defn messages-loaded
(rf/defn messages-loaded
"Loads more messages for current chat"
{:events [::messages-loaded]}
[{db :db} chat-id session-id {:keys [cursor messages]}]
(when-not (and (get-in db [:pagination-info chat-id :messages-initialized?])
(not= session-id
(get-in db [:pagination-info chat-id :messages-initialized?])))
(let [already-loaded-messages (get-in db [:messages chat-id])
(let [already-loaded-messages (get-in db [:messages chat-id])
;; We remove those messages that are already loaded, as we might get some duplicates
{:keys [all-messages new-messages senders contacts]}
(reduce (fn [{:keys [all-messages] :as acc}
@@ -124,8 +129,11 @@
:contacts {}
:new-messages []}
messages)
current-clock-value (get-in db [:pagination-info chat-id :cursor-clock-value])
clock-value (when cursor (cursor->clock-value cursor))]
current-clock-value (get-in db
[:pagination-info chat-id
:cursor-clock-value])
clock-value (when cursor
(cursor->clock-value cursor))]
{:dispatch [:chat/add-senders-to-chat-users (vals senders)]
:db (-> db
(update-in [:pagination-info chat-id :cursor-clock-value]
@@ -134,7 +142,9 @@
%))
(update-in [:pagination-info chat-id :cursor]
#(if (or (empty? cursor) (not current-clock-value) (< clock-value current-clock-value))
#(if (or (empty? cursor)
(not current-clock-value)
(< clock-value current-clock-value))
cursor
%))
(assoc-in [:pagination-info chat-id :loading-messages?] false)
@@ -144,7 +154,7 @@
(empty? cursor))
(update :contacts/contacts merge contacts))})))
(fx/defn load-more-messages
(rf/defn load-more-messages
{:events [:chat.ui/load-more-messages]}
[{:keys [db]} chat-id first-request]
(when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])]
@@ -163,16 +173,16 @@
#(re-frame/dispatch [::messages-loaded chat-id session-id %])
#(re-frame/dispatch [::failed-loading-messages chat-id session-id %]))))))))
(fx/defn load-more-messages-for-current-chat
(rf/defn load-more-messages-for-current-chat
{:events [:chat.ui/load-more-messages-for-current-chat]}
[{:keys [db] :as cofx}]
(load-more-messages cofx (:current-chat-id db) false))
(fx/defn load-messages
(rf/defn load-messages
[{:keys [db now] :as cofx} chat-id]
(when-not (get-in db [:pagination-info chat-id :messages-initialized?])
(fx/merge cofx
{:db (assoc-in db [:pagination-info chat-id :messages-initialized?] now)
(rf/merge cofx
{:db (assoc-in db [:pagination-info chat-id :messages-initialized?] now)
:utils/dispatch-later [{:ms 50 :dispatch [:chat.ui/mark-all-read-pressed chat-id]}
(when-not (get-in cofx [:db :chats chat-id :public?])
{:ms 100 :dispatch [:pin-message/load-pin-messages chat-id]})]}
+232 -186
View File
@@ -1,23 +1,26 @@
(ns status-im.chat.models.mentions
(:require [clojure.string :as string]
[quo.react :as react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.utils.fx :as fx]
[status-im.contact.db :as contact.db]
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]
[status-im.utils.utils :as utils]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.native-module.core :as status]
[quo.react-native :as rn]
[quo.react :as react]
[status-im.multiaccounts.core :as multiaccounts]))
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(def at-sign "@")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn re-pos [re s]
(loop [res [] s s last-idx 0]
(defn re-pos
[re s]
(loop [res []
s s
last-idx 0]
(if-let [m (.exec re s)]
(let [new-idx (.-index m)
idx (+ last-idx new-idx)
@@ -25,7 +28,8 @@
(recur (conj res [idx c]) (subs s (inc new-idx)) (inc idx)))
res)))
(defn check-style-tag [text idxs idx]
(defn check-style-tag
[text idxs idx]
(let [[pos c] (get idxs idx)
[pos2 c2] (get idxs (inc idx))
[pos3 c3] (get idxs (+ 2 idx))
@@ -63,7 +67,8 @@
(doall
((fnil concat []) checked new-idxs)))))))
(defn apply-style-tag [data idx pos c len start? end?]
(defn apply-style-tag
[data idx pos c len start? end?]
(let [was-started? (get data c)
tripple-tilde? (and (= "~" c) (= 3 len))]
(cond
@@ -87,8 +92,9 @@
start?
{:data (-> data
(assoc c {:len len
:idx pos})
(assoc c
{:len len
:idx pos})
(clear-pending-at-signs pos))
:next-idx (+ idx len)}
@@ -96,7 +102,8 @@
{:data data
:next-idx (+ idx len)})))
(defn code-tag-len [idxs idx]
(defn code-tag-len
[idxs idx]
(let [[pos c] (get idxs idx)
[pos2 c2] (get idxs (inc idx))
[pos3 c3] (get idxs (+ 2 idx))]
@@ -147,7 +154,8 @@
(string/blank? (subs text (first prev-newlines) (dec pos)))))
(recur (-> data
(dissoc :newline "*" "_" "~" "`")
(assoc ">" {:idx pos})) (inc idx))
(assoc ">" {:idx pos}))
(inc idx))
(recur data (inc idx))))
at-sign?
@@ -155,7 +163,7 @@
(inc idx))
code-tag?
(let [len (code-tag-len idxs idx)
(let [len (code-tag-len idxs idx)
{:keys [data next-idx]}
(apply-style-tag data idx pos c len true true)]
(recur data next-idx))
@@ -167,7 +175,7 @@
(apply-style-tag data idx pos c len can-be-start? can-be-end?)]
(recur data next-idx))
:else (recur data (inc idx)))))))))
:else (recur data (inc idx)))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -201,7 +209,8 @@
:ens-verified ens-verified
:public-key public-key})))
(defn mentionable-contacts [contacts]
(defn mentionable-contacts
[contacts]
(reduce
(fn [acc [key contact]]
(let [mentionable-contact (add-searchable-phrases-to-contact contact false)]
@@ -211,38 +220,49 @@
{}
contacts))
(defn mentionable-contacts-from-identites [contacts my-public-key identities]
(defn mentionable-contacts-from-identites
[contacts my-public-key identities]
(reduce (fn [acc identity]
(let [contact (multiaccounts/contact-by-identity
contacts identity)
contacts
identity)
contact (if (string/blank? (:alias contact))
(assoc contact :alias
(assoc contact
:alias
(get-in contact [:names :three-words-name]))
contact)
mentionable-contact (add-searchable-phrases-to-contact
contact true)]
(if (nil? mentionable-contact) acc
(assoc acc identity mentionable-contact))))
contact
true)]
(if (nil? mentionable-contact)
acc
(assoc acc identity mentionable-contact))))
{}
(remove #(= my-public-key %) identities)))
(defn get-mentionable-users [chat all-contacts current-multiaccount community-members]
(let [{:keys [name preferred-name public-key]} current-multiaccount
(defn get-mentionable-users
[chat all-contacts current-multiaccount community-members]
(let [{:keys [name preferred-name public-key]} current-multiaccount
{:keys [chat-id users contacts chat-type]} chat
mentionable-contacts (mentionable-contacts all-contacts)
mentionable-users (assoc users public-key {:alias name
:name (or preferred-name name)
:public-key public-key})]
mentionable-contacts (mentionable-contacts all-contacts)
mentionable-users (assoc users
public-key
{:alias name
:name (or preferred-name name)
:public-key public-key})]
(cond
(= chat-type constants/private-group-chat-type)
(merge mentionable-users
(mentionable-contacts-from-identites all-contacts public-key contacts))
(= chat-type constants/one-to-one-chat-type)
(assoc mentionable-users chat-id (get mentionable-contacts chat-id
(-> chat-id
contact.db/public-key->new-contact
contact.db/enrich-contact)))
(assoc mentionable-users
chat-id
(get mentionable-contacts
chat-id
(-> chat-id
contact.db/public-key->new-contact
contact.db/enrich-contact)))
(= chat-type constants/community-chat-type)
(mentionable-contacts-from-identites
@@ -253,13 +273,14 @@
(= chat-type constants/public-chat-type)
(merge mentionable-users (select-keys mentionable-contacts (keys mentionable-users)))
:else mentionable-users)))
:else mentionable-users)))
(def ending-chars "[\\s\\.,;:]")
(def ending-chars-regex (re-pattern ending-chars))
(def word-regex (re-pattern (str "^[\\w\\d]*" ending-chars "|^[\\S]*$")))
(defn mentioned? [{:keys [alias name]} text]
(defn mentioned?
[{:keys [alias name]} text]
(let [lcase-name (string/lower-case name)
lcase-alias (string/lower-case alias)
regex (re-pattern
@@ -272,7 +293,8 @@
lcase-text (string/lower-case text)]
(re-find regex lcase-text)))
(defn get-user-suggestions [users searched-text]
(defn get-user-suggestions
[users searched-text]
(reduce
(fn [acc [k {:keys [alias name nickname searchable-phrases] :as user}]]
(if-let [match
@@ -301,9 +323,11 @@
(string/lower-case name)
searched-text)
name))]
(assoc acc k (assoc user
:match match
:searched-text searched-text))
(assoc acc
k
(assoc user
:match match
:searched-text searched-text))
acc))
{}
users))
@@ -324,21 +348,25 @@
text))
user-suggestions (get-user-suggestions users searched-text)
user-suggestions-cnt (count user-suggestions)]
(cond (zero? user-suggestions-cnt)
nil
(cond
(zero? user-suggestions-cnt)
nil
(and (= 1 user-suggestions-cnt)
(mentioned? (second (first user-suggestions))
(subs text (inc mention-key-idx))))
(second (first user-suggestions))
(and (= 1 user-suggestions-cnt)
(mentioned? (second (first user-suggestions))
(subs text (inc mention-key-idx))))
(second (first user-suggestions))
(> user-suggestions-cnt 1)
(let [word-len (count word)
text-len (count text)
next-word-start (+ next-word-idx word-len)]
(when (> text-len next-word-start)
(match-mention text users mention-key-idx
next-word-start new-words))))))))
(> user-suggestions-cnt 1)
(let [word-len (count word)
text-len (count text)
next-word-start (+ next-word-idx word-len)]
(when (> text-len next-word-start)
(match-mention text
users
mention-key-idx
next-word-start
new-words))))))))
(defn replace-mentions
([text users]
@@ -360,18 +388,25 @@
(let [new-text (string/join
[(subs text 0 (inc mention-key-idx))
public-key
(subs text (+ (inc mention-key-idx)
(count match)))])]
(recur new-text users (rest idxs)
(subs text
(+ (inc mention-key-idx)
(count match)))])]
(recur new-text
users
(rest idxs)
(+ diff (- (count text) (count new-text)))))))))))))
(defn check-mentions [{:keys [db]} text]
(defn check-mentions
[{:keys [db]} text]
(let [current-chat-id (:current-chat-id db)
chat (get-in db [:chats current-chat-id])
all-contacts (:contacts/contacts db)
current-multiaccount (:multiaccount db)
community-members (get-in db [:communities (:community-id chat) :members])
mentionable-users (get-mentionable-users chat all-contacts current-multiaccount community-members)]
mentionable-users (get-mentionable-users chat
all-contacts
current-multiaccount
community-members)]
(replace-mentions text mentionable-users)))
(defn get-at-sign-idxs
@@ -396,7 +431,7 @@
{:from idx
:checked? false})
new-idxs)
(let [diff (- new-text-len old-text-len)
(let [diff (- new-text-len old-text-len)
{:keys [state added?]}
(->> at-idxs
(keep (fn [{:keys [from to] :as entry}]
@@ -406,7 +441,7 @@
(>= from old-end)
(assoc entry
:from (+ from diff)
:to (+ to diff))
:to (+ to diff))
;; starts and end before change
(and
@@ -431,20 +466,22 @@
(> from last-new-idx)
(not added?))
{:state (conj
(into state (map (fn [idx]
{:from idx
:checked? false})
new-idxs))
(into state
(map (fn [idx]
{:from idx
:checked? false})
new-idxs))
entry)
:added? true}
(update acc :state conj entry)))
{:state []}))]
(if added?
state
(into state (map (fn [idx]
{:from idx
:checked? false})
new-idxs)))))))
(into state
(map (fn [idx]
{:from idx
:checked? false})
new-idxs)))))))
(defn check-entry
[text {:keys [from checked?] :as entry} mentionable-users]
@@ -453,14 +490,14 @@
(let [{user-match :match}
(match-mention (str text "@") mentionable-users from)]
(if user-match
{:from from
:to (+ from (count user-match))
{:from from
:to (+ from (count user-match))
:checked? true
:mention? true}
{:from from
:to (count text)
{:from from
:to (count text)
:checked? true
:mention false}))))
:mention false}))))
(defn check-idx-for-mentions
[text idxs mentionable-users]
@@ -489,7 +526,7 @@
(assoc-in [last-idx :to] (dec (count text)))
(assoc-in [last-idx :checked?] false)))))))
(fx/defn on-text-input
(rf/defn on-text-input
{:events [::on-text-input]}
[{:keys [db]} {:keys [previous-text start end] :as args}]
(log/debug "[mentions] on-text-input args" args)
@@ -499,31 +536,34 @@
(if platform/android?
previous-text
(subs previous-text start end))
chat-id (:current-chat-id db)
previous-state (get-in db [:chats/mentions chat-id :mentions])
new-state (-> previous-state
(merge args)
(assoc :previous-text normalized-previous-text))
new-at-idxs (calc-at-idxs new-state)
new-state (assoc new-state :at-idxs new-at-idxs)]
chat-id (:current-chat-id db)
previous-state (get-in db [:chats/mentions chat-id :mentions])
new-state (-> previous-state
(merge args)
(assoc :previous-text normalized-previous-text))
new-at-idxs (calc-at-idxs new-state)
new-state (assoc new-state :at-idxs new-at-idxs)]
(log/debug "[mentions] on-text-input state" new-state)
{:db (assoc-in db [:chats/mentions chat-id :mentions] new-state)}))
(defn calculate-input [text [first-idx :as idxs]]
(defn calculate-input
[text [first-idx :as idxs]]
(if-not first-idx
[[:text text]]
(let [idx-cnt (count idxs)
(let [idx-cnt (count idxs)
last-from (get-in idxs [(dec idx-cnt) :from])]
(reduce
(fn [acc {:keys [from to next-at-idx mention?]}]
(cond
(and mention? next-at-idx)
(into acc [[:mention (subs text from (inc to))]
[:text (subs text (inc to) next-at-idx)]])
(into acc
[[:mention (subs text from (inc to))]
[:text (subs text (inc to) next-at-idx)]])
(and mention? (= last-from from))
(into acc [[:mention (subs text from (inc to))]
[:text (subs text (inc to))]])
(into acc
[[:mention (subs text from (inc to))]
[:text (subs text (inc to))]])
:else
(conj acc [:text (subs text from (inc to))])))
@@ -533,79 +573,82 @@
[[:text (subs text 0 first-from)]]))
idxs))))
(fx/defn recheck-at-idxs
(rf/defn recheck-at-idxs
[{:keys [db]} mentionable-users]
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
state (get-in db [:chats/mentions chat-id :mentions])
new-at-idxs (check-idx-for-mentions
text
(:at-idxs state)
mentionable-users)
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
state (get-in db [:chats/mentions chat-id :mentions])
new-at-idxs (check-idx-for-mentions
text
(:at-idxs state)
mentionable-users)
calculated-input (calculate-input text new-at-idxs)]
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
{:db (-> db
(update-in
[:chats/mentions chat-id :mentions]
assoc
:at-idxs new-at-idxs)
:at-idxs
new-at-idxs)
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input))}))
(fx/defn calculate-suggestions
(rf/defn calculate-suggestions
{:events [::calculate-suggestions]}
[{:keys [db]} mentionable-users]
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
{:keys [new-text at-idxs start end] :as state}
(get-in db [:chats/mentions chat-id :mentions])
new-text (or new-text text)]
new-text (or new-text text)]
(log/info "[mentions] calculate suggestions"
"state" state)
"state"
state)
(if-not (seq at-idxs)
{:db (-> db
(assoc-in [:chats/mention-suggestions chat-id] nil)
(assoc-in [:chats/mentions chat-id :mentions :at-idxs] nil)
(assoc-in [:chat/inputs-with-mentions chat-id] [[:text text]]))}
(let [new-at-idxs (check-idx-for-mentions
text
at-idxs
mentionable-users)
(let [new-at-idxs (check-idx-for-mentions
text
at-idxs
mentionable-users)
calculated-input (calculate-input text new-at-idxs)
addition? (<= start end)
end (if addition?
(+ start (count new-text))
start)
at-sign-idx (string/last-index-of text at-sign start)
searched-text (string/lower-case (subs text (inc at-sign-idx) end))
addition? (<= start end)
end (if addition?
(+ start (count new-text))
start)
at-sign-idx (string/last-index-of text at-sign start)
searched-text (string/lower-case (subs text (inc at-sign-idx) end))
mentions
(when (and (not (> at-sign-idx start))
(not (> (- end at-sign-idx) 100)))
(get-user-suggestions mentionable-users searched-text))]
(log/debug "[mentions] mention check"
"addition" addition?
"at-sign-idx" at-sign-idx
"start" start
"end" end
"addition" addition?
"at-sign-idx" at-sign-idx
"start" start
"end" end
"searched-text" (pr-str searched-text)
"mentions" (count mentions))
"mentions" (count mentions))
(log/debug "[mentions] new-at-idxs" new-at-idxs calculated-input)
{:db (-> db
(update-in [:chats/mentions chat-id :mentions]
assoc
:at-sign-idx at-sign-idx
:at-idxs new-at-idxs
:at-idxs new-at-idxs
:mention-end end)
(assoc-in [:chat/inputs-with-mentions chat-id] calculated-input)
(assoc-in [:chats/mention-suggestions chat-id] mentions))}))))
(defn new-input-text-with-mention
[{:keys [db]} {:keys [name]}]
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
{:keys [mention-end at-sign-idx]}
(get-in db [:chats/mentions chat-id :mentions])]
(log/debug "[mentions] clear suggestions"
"state" new-input-text-with-mention)
"state"
new-input-text-with-mention)
(string/join
[(subs text 0 (inc at-sign-idx))
name
@@ -616,36 +659,36 @@
" "))
(subs text mention-end)])))
(fx/defn clear-suggestions
(rf/defn clear-suggestions
[{:keys [db]}]
(log/debug "[mentions] clear suggestions")
(let [chat-id (:current-chat-id db)]
{:db (update db :chats/mention-suggestions dissoc chat-id)}))
(fx/defn clear-mentions
(rf/defn clear-mentions
[{:keys [db] :as cofx}]
(log/debug "[mentions] clear mentions")
(let [chat-id (:current-chat-id db)]
(fx/merge
(rf/merge
cofx
{:db (-> db
(update-in [:chats/mentions chat-id] dissoc :mentions)
(update :chat/inputs-with-mentions dissoc chat-id))}
(clear-suggestions))))
(fx/defn clear-cursor
(rf/defn clear-cursor
{:events [::clear-cursor]}
[{:keys [db]}]
(log/debug "[mentions] clear cursor")
{:db
(update db :chats/cursor dissoc (:current-chat-id db))})
(fx/defn check-selection
(rf/defn check-selection
{:events [::on-selection-change]}
[{:keys [db] :as cofx}
{:keys [start end] :as selection}
mentionable-users]
(let [chat-id (:current-chat-id db)
(let [chat-id (:current-chat-id db)
{:keys [mention-end at-idxs]}
(get-in db [:chats/mentions chat-id :mentions])]
(when (seq at-idxs)
@@ -655,12 +698,13 @@
(<= (dec end) to))
idx))
at-idxs)
(fx/merge
(rf/merge
cofx
{:db (update-in db [:chats/mentions chat-id :mentions]
{:db (update-in db
[:chats/mentions chat-id :mentions]
assoc
:start end
:end end
:start end
:end end
:new-text "")}
(calculate-suggestions mentionable-users))
(clear-suggestions cofx)))))
@@ -673,26 +717,28 @@
(rn/find-node-handle (react/current-ref ref))
cursor))))
(fx/defn reset-text-input-cursor
(rf/defn reset-text-input-cursor
[_ ref cursor]
{::reset-text-input-cursor [ref cursor]})
(defn is-valid-terminating-character? [c]
(defn is-valid-terminating-character?
[c]
(case c
"\t" true ; tab
"\t" true ; tab
"\n" true ; newline
"\f" true ; new page
"\r" true ; carriage return
" " true ; whitespace
"," true
"." true
":" true
";" true
" " true ; whitespace
"," true
"." true
":" true
";" true
false))
(def hex-reg #"[0-9a-f]")
(defn is-public-key-character? [c]
(defn is-public-key-character?
[c]
(.test hex-reg c))
(def mention-length 133)
@@ -710,7 +756,7 @@
current-text
current-mention
current-mention-length]} character]
(let [is-pk-character (is-public-key-character? character)
(let [is-pk-character (is-public-key-character? character)
is-termination-character (is-valid-terminating-character? character)]
(cond
;; It's a valid mention.
@@ -720,13 +766,13 @@
(and (= current-mention-length mention-length)
is-termination-character)
{:current-mention-length 0
:current-mention ""
:current-text character
:text (cond-> text
(seq current-text)
(conj [:text current-text])
:always
(conj [:mention current-mention]))}
:current-mention ""
:current-text character
:text (cond-> text
(seq current-text)
(conj [:text current-text])
:always
(conj [:mention current-mention]))}
;; It's either a pk character, or the `x` in the pk
@@ -739,9 +785,9 @@
(and (= 2 current-mention-length)
(= "x" character)))
{:current-mention-length (inc current-mention-length)
:current-text current-text
:current-mention (str current-mention character)
:text text}
:current-text current-text
:current-mention (str current-mention character)
:text text}
;; The beginning of a mention, discard the @ sign
@@ -750,29 +796,29 @@
(= "@" character)
{:current-mention-length 1
:current-mention ""
:current-text current-text
:text text}
:current-mention ""
:current-text current-text
:text text}
;; Not a mention character, but we were following a mention
;; discard everything up to know an count as text
(and (not is-pk-character)
(pos? current-mention-length))
{:current-mention-length 0
:current-text (str current-text "@" current-mention character)
:current-mention ""
:text text}
:current-text (str current-text "@" current-mention character)
:current-mention ""
:text text}
;; Just a normal text character
:else
{:current-mention-length 0
:current-mention ""
:current-text (str current-text character)
:text text})))
:current-mention ""
:current-text (str current-text character)
:text text})))
{:current-mention-length 0
:current-text ""
:current-mention ""
:text []}
:current-text ""
:current-mention ""
:text []}
text)]
;; Process any remaining mention/text
(cond-> text
@@ -788,32 +834,32 @@
[m]
(reduce (fn [{:keys [start end at-idxs at-sign-idx mention-end]} [t text]]
(if (= :mention t)
(let [new-mention {:checked? true
:mention? true
:from mention-end
:to (+ start (count text))}
(let [new-mention {:checked? true
:mention? true
:from mention-end
:to (+ start (count text))}
has-previous? (seq at-idxs)]
{:new-text (last text)
{:new-text (last text)
:previous-text ""
:start (+ start (count text))
:end (+ end (count text))
:at-idxs (cond-> at-idxs
has-previous?
(-> pop
(conj (assoc (peek at-idxs) :next-at-idx mention-end)))
:always
(conj new-mention))
:at-sign-idx mention-end
:mention-end (+ mention-end (count text))})
{:new-text (last text)
:start (+ start (count text))
:end (+ end (count text))
:at-idxs (cond-> at-idxs
has-previous?
(-> pop
(conj (assoc (peek at-idxs) :next-at-idx mention-end)))
:always
(conj new-mention))
:at-sign-idx mention-end
:mention-end (+ mention-end (count text))})
{:new-text (last text)
:previous-text ""
:start (+ start (count text))
:end (+ end (count text))
:at-idxs at-idxs
:at-sign-idx at-sign-idx
:mention-end (+ mention-end (count text))}))
{:start -1
:end -1
:at-idxs []
:start (+ start (count text))
:end (+ end (count text))
:at-idxs at-idxs
:at-sign-idx at-sign-idx
:mention-end (+ mention-end (count text))}))
{:start -1
:end -1
:at-idxs []
:mention-end 0}
m))
+80 -56
View File
@@ -2,7 +2,6 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.chat.models :as chat-model]
[status-im.chat.models.delete-message :as delete-message]
[status-im.chat.models.loading :as chat.loading]
[status-im.chat.models.mentions :as mentions]
[status-im.chat.models.message-list :as message-list]
@@ -11,11 +10,12 @@
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.transport.message.protocol :as protocol]
[status-im.ui.screens.chat.state :as view.state]
[status-im.utils.fx :as fx]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn- message-loaded?
[db chat-id message-id]
@@ -25,7 +25,8 @@
[db chat-id clock-value]
(>= (get-in db [:chats chat-id :deleted-at-clock-value]) clock-value))
(defn add-timeline-message [acc chat-id message-id message]
(defn add-timeline-message
[acc chat-id message-id message]
(-> acc
(update-in [:db :messages chat-id] assoc message-id message)
(update-in [:db :message-lists chat-id] message-list/add message)))
@@ -36,14 +37,16 @@
;; TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
(message-list/rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id))
(fx/defn add-senders-to-chat-users
(rf/defn add-senders-to-chat-users
{:events [:chat/add-senders-to-chat-users]}
[{:keys [db]} messages]
(reduce (fn [acc {:keys [chat-id alias name identicon from]}]
(let [alias (if (string/blank? alias)
(gfycat/generate-gfy from)
alias)]
(update-in acc [:db :chats chat-id :users] assoc
(update-in acc
[:db :chats chat-id :users]
assoc
from
(mentions/add-searchable-phrases
{:alias alias
@@ -54,7 +57,8 @@
{:db db}
messages))
(defn timeline-message? [db chat-id]
(defn timeline-message?
[db chat-id]
(and
(get-in db [:pagination-info constants/timeline-chat-id :messages-initialized?])
(or
@@ -62,11 +66,13 @@
(when-let [pub-key (get-in db [:chats chat-id :profile-public-key])]
(get-in db [:contacts/contacts pub-key :added])))))
(defn get-timeline-message [db chat-id message-js]
(defn get-timeline-message
[db chat-id message-js]
(when (timeline-message? db chat-id)
(data-store.messages/<-rpc (types/js->clj message-js))))
(defn add-message [{:keys [db] :as acc} message-js chat-id message-id cursor-clock-value]
(defn add-message
[{:keys [db] :as acc} message-js chat-id message-id cursor-clock-value]
(let [{:keys [replace from clock-value] :as message}
(data-store.messages/<-rpc (types/js->clj message-js))]
(if (message-loaded? db chat-id message-id)
@@ -82,8 +88,9 @@
(update-in [:db :message-lists chat-id] message-list/add message)
(or (not cursor-clock-value) (< clock-value cursor-clock-value))
(update-in [:db :pagination-info chat-id] assoc
:cursor (chat.loading/clock-value->cursor clock-value)
(update-in [:db :pagination-info chat-id]
assoc
:cursor (chat.loading/clock-value->cursor clock-value)
:cursor-clock-value clock-value)
;;conj sender for add-sender-to-chat-users
@@ -94,11 +101,12 @@
;;TODO this is expensive
(hide-message chat-id replace)))))
(defn reduce-js-messages [{:keys [db] :as acc} ^js message-js]
(let [chat-id (.-localChatId message-js)
clock-value (.-clock message-js)
message-id (.-id message-js)
current-chat-id (:current-chat-id db)
(defn reduce-js-messages
[{:keys [db] :as acc} ^js message-js]
(let [chat-id (.-localChatId message-js)
clock-value (.-clock message-js)
message-id (.-id message-js)
current-chat-id (:current-chat-id db)
cursor-clock-value (get-in db [:pagination-info current-chat-id :cursor-clock-value])]
;;ignore not opened chats and earlier clock
(if (and (get-in db [:pagination-info chat-id :messages-initialized?])
@@ -110,26 +118,30 @@
(add-message acc message-js chat-id message-id cursor-clock-value)
;; Not in the current view, set all-loaded to false
;; and offload to db and update cursor if necessary
;;TODO if we'll offload messages , it will conflict with end reached, so probably if we reached the end of visible area,
;; we need to drop other messages with (< clock-value cursor-clock-value) from response-js so we don't update
;;TODO if we'll offload messages , it will conflict with end reached, so probably if we reached
;;the end of visible area,
;; we need to drop other messages with (< clock-value cursor-clock-value) from response-js so we
;; don't update
;; :cursor-clock-value because it will be changed when we loadMore message
{:db (cond-> (assoc-in db [:pagination-info chat-id :all-loaded?] false)
(> clock-value cursor-clock-value)
;;TODO cut older messages from messages-list
(update-in [:pagination-info chat-id] assoc
:cursor (chat.loading/clock-value->cursor clock-value)
(update-in [:pagination-info chat-id]
assoc
:cursor (chat.loading/clock-value->cursor clock-value)
:cursor-clock-value clock-value))})
acc)))
(defn receive-many [{:keys [db]} ^js response-js]
(let [messages-js ^js (.splice (.-messages response-js) 0 (if platform/low-device? 3 10))
(defn receive-many
[{:keys [db]} ^js response-js]
(let [messages-js ^js (.splice (.-messages response-js) 0 (if platform/low-device? 3 10))
{:keys [db senders]}
(reduce reduce-js-messages
{:db db :chats #{} :senders {} :transactions #{}}
messages-js)]
;;we want to render new messages as soon as possible
;;so we dispatch later all other events which can be handled async
{:db db
{:db db
:utils/dispatch-later
(concat [{:ms 20 :dispatch [:process-response response-js]}]
(when (and (:current-chat-id db) (= "active" (:app-state db)))
@@ -137,7 +149,8 @@
(when (seq senders)
[{:ms 100 :dispatch [:chat/add-senders-to-chat-users (vals senders)]}]))}))
(defn reduce-js-statuses [db ^js message-js]
(defn reduce-js-statuses
[db ^js message-js]
(let [chat-id (.-localChatId message-js)
profile-initialized (get-in db [:pagination-info chat-id :messages-initialized?])
timeline-message (timeline-message? db chat-id)
@@ -155,60 +168,66 @@
(update-in [:message-lists constants/timeline-chat-id] message-list/add message)))
db)))
(fx/defn process-statuses
(rf/defn process-statuses
{:events [:process-statuses]}
[{:keys [db]} statuses]
{:db (reduce reduce-js-statuses db statuses)})
(fx/defn update-db-message-status
(rf/defn update-db-message-status
[{:keys [db] :as cofx} chat-id message-id status]
(when (get-in db [:messages chat-id message-id])
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db
[:messages chat-id message-id :outgoing-status]
status)})))
[:messages chat-id message-id :outgoing-status]
status)})))
(fx/defn update-message-status
(rf/defn update-message-status
[{:keys [db] :as cofx} chat-id message-id status]
(fx/merge cofx
(rf/merge cofx
(update-db-message-status chat-id message-id status)))
(fx/defn resend-message
(rf/defn resend-message
[{:keys [db] :as cofx} chat-id message-id]
(fx/merge cofx
{::json-rpc/call [{:method "wakuext_reSendChatMessage"
:params [message-id]
(rf/merge cofx
{::json-rpc/call [{:method "wakuext_reSendChatMessage"
:params [message-id]
:on-success #(log/debug "re-sent message successfully")
:on-error #(log/error "failed to re-send message" %)}]}
:on-error #(log/error "failed to re-send message" %)}]}
(update-message-status chat-id message-id :sending)))
(fx/defn send-message
(rf/defn send-message
[cofx message]
(protocol/send-chat-messages cofx [message]))
(fx/defn send-messages
(rf/defn send-messages
[cofx messages]
(protocol/send-chat-messages cofx messages))
(fx/defn handle-removed-messages
(rf/defn handle-removed-messages
{:events [::handle-removed-messages]}
[{:keys [db] :as cofx} removed-messages]
(let [mark-as-deleted-fx (->> removed-messages
(map #(assoc % :message-id (:messageId %)))
(group-by :chatId)
(mapv (fn [[chat-id messages]] (delete-message/delete-messages-localy messages chat-id))))
mark-as-seen-fx (mapv (fn [removed-message]
(let [chat-id (:chatId removed-message)
message-id (:messageId removed-message)]
(data-store.messages/mark-messages-seen chat-id
[message-id]
#(re-frame/dispatch [:chat/decrease-unviewed-count chat-id %3]))))
removed-messages)
(mapv (fn [[chat-id messages]]
(delete-message/delete-messages-localy messages chat-id))))
mark-as-seen-fx (mapv
(fn [removed-message]
(let [chat-id (:chatId removed-message)
message-id (:messageId removed-message)]
(data-store.messages/mark-messages-seen chat-id
[message-id]
#(re-frame/dispatch
[:chat/decrease-unviewed-count
chat-id %3]))))
removed-messages)
remove-messages-fx (fn [{:keys [db]}]
{:dispatch [:activity-center.notifications/fetch-unread-count]})]
(apply fx/merge cofx (-> mark-as-deleted-fx
(concat mark-as-seen-fx)
(conj remove-messages-fx)))))
(apply rf/merge
cofx
(-> mark-as-deleted-fx
(concat mark-as-seen-fx)
(conj remove-messages-fx)))))
(comment
(handle-removed-messages
@@ -218,15 +237,20 @@
:m4 {:chat-id :c2 :message-id :m4}}}}}
[:m1 :m3]))
(defn remove-cleared-message [messages cleared-at]
(into {} (remove #(let [message-clock (:clock-value (second %))]
(<= message-clock cleared-at))
messages)))
(defn remove-cleared-message
[messages cleared-at]
(into {}
(remove #(let [message-clock (:clock-value (second %))]
(<= message-clock cleared-at))
messages)))
(fx/defn handle-cleared-histories-messages
(rf/defn handle-cleared-histories-messages
{:events [::handle-cleared-hisotories-messages]}
[{:keys [db]} cleared-histories]
{:db (reduce (fn [acc current]
(update-in acc [:messages (:chatId current)] remove-cleared-message (:clearedAt current)))
(update-in acc
[:messages (:chatId current)]
remove-cleared-message
(:clearedAt current)))
db
cleared-histories)})
+44 -33
View File
@@ -2,22 +2,25 @@
(:require ["functional-red-black-tree" :as rb-tree]
[status-im.constants :as constants]
[status-im.utils.datetime :as time]
[status-im.utils.fx :as fx]))
[utils.re-frame :as rf]))
(defn- add-datemark [{:keys [whisper-timestamp] :as msg}]
(defn- add-datemark
[{:keys [whisper-timestamp] :as msg}]
;;TODO this is slow
(assoc msg :datemark (time/day-relative whisper-timestamp)))
(defn- add-timestamp [{:keys [whisper-timestamp] :as msg}]
(defn- add-timestamp
[{:keys [whisper-timestamp] :as msg}]
(assoc msg :timestamp-str (time/timestamp->time whisper-timestamp)))
(defn prepare-message [{:keys [message-id
clock-value
message-type
from
outgoing
whisper-timestamp
deleted-for-me?]}]
(defn prepare-message
[{:keys [message-id
clock-value
message-type
from
outgoing
whisper-timestamp
deleted-for-me?]}]
(-> {:whisper-timestamp whisper-timestamp
:from from
:one-to-one? (= constants/message-type-one-to-one message-type)
@@ -69,7 +72,8 @@
the most recent message, similarly :first-in-group? is the most recent message
in a group."
[{:keys [system-message?
one-to-one? outgoing] :as current-message}
one-to-one? outgoing]
:as current-message}
{:keys [outgoing-seen?] :as previous-message}
next-message]
(let [last-in-group? (or (nil? next-message)
@@ -87,7 +91,7 @@
(not system-message?)
(not outgoing)
(not one-to-one?))
:display-photo? (display-photo? current-message))))
:display-photo? (display-photo? current-message))))
(defn update-next-message
"Update next message in the list, we set :first? to false, and check if it
@@ -95,26 +99,28 @@
[current-message next-message]
(assoc
next-message
:first? false
:first? false
:first-outgoing? (and
(not (:first-outgoing? current-message))
(:first-outgoing? next-message))
:outgoing-seen? (:outgoing-seen? current-message)
:outgoing-seen? (:outgoing-seen? current-message)
:first-in-group?
(not (same-group? current-message next-message))))
(defn update-previous-message
"If this is a new group, we mark the previous as the last one in the group"
[current-message {:keys [one-to-one?
system-message?
outgoing] :as previous-message}]
[current-message
{:keys [one-to-one?
system-message?
outgoing]
:as previous-message}]
(let [last-in-group? (not (same-group? current-message previous-message))]
(assoc previous-message
:display-username? (and last-in-group?
(not system-message?)
(not outgoing)
(not one-to-one?))
:last-in-group? last-in-group?)))
:last-in-group? last-in-group?)))
(defn get-prev-element
"Get previous item in the iterator, and wind it back to the initial state"
@@ -135,11 +141,11 @@
(defn update-message
"Update the message and siblings with positional info"
[^js tree message]
(let [^js iter (.find tree message)
^js previous-message (when (.-hasPrev iter)
(get-prev-element iter))
^js next-message (when (.-hasNext iter)
(get-next-element iter))
(let [^js iter (.find tree message)
^js previous-message (when (.-hasPrev iter)
(get-prev-element iter))
^js next-message (when (.-hasNext iter)
(get-next-element iter))
^js message-with-pos-data (add-group-info message previous-message next-message)]
(cond-> (.update iter message-with-pos-data)
next-message
@@ -157,9 +163,9 @@
(let [iter (.find tree prepared-message)]
(if (not iter)
tree
(let [^js new-tree (.remove iter)
^js next-message (when (.-hasNext iter)
(get-next-element iter))]
(let [^js new-tree (.remove iter)
^js next-message (when (.-hasNext iter)
(get-next-element iter))]
(if (not next-message)
new-tree
(update-message new-tree next-message))))))
@@ -173,21 +179,26 @@
(let [^js tree (.insert old-message-list prepared-message prepared-message)]
(update-message tree prepared-message)))
(defn add [message-list message]
(defn add
[message-list message]
(insert-message (or message-list (rb-tree compare-fn)) (prepare-message message)))
(defn add-many [message-list messages]
(defn add-many
[message-list messages]
(reduce add
message-list
messages))
(defn ->seq [^js message-list]
(defn ->seq
[^js message-list]
(if message-list
(array-seq (.-values message-list))
[]))
;;TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
(fx/defn rebuild-message-list
;; NOTE(performance): this is too expensive, probably we could mark message somehow and just hide it in
;; the UI
(rf/defn rebuild-message-list
[{:keys [db]} chat-id]
{:db (assoc-in db [:message-lists chat-id]
(add-many nil (vals (get-in db [:messages chat-id]))))})
{:db (assoc-in db
[:message-lists chat-id]
(add-many nil (vals (get-in db [:messages chat-id]))))})
+33 -22
View File
@@ -1,28 +1,36 @@
(ns status-im.chat.models.reactions
(:require [status-im.constants :as constants]
[re-frame.core :as re-frame]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.data-store.reactions :as data-store.reactions]
[status-im.transport.message.protocol :as message.protocol]
[status-im.data-store.reactions :as data-store.reactions]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn update-reaction [acc retracted chat-id message-id emoji-id emoji-reaction-id reaction]
(defn update-reaction
[acc retracted chat-id message-id emoji-id emoji-reaction-id reaction]
;; NOTE(Ferossgp): For a better performance, better to not keep in db all retracted reactions
;; retraction will always come after the reaction so there shouldn't be a conflict
(if retracted
(update-in acc [chat-id message-id emoji-id] dissoc emoji-reaction-id)
(assoc-in acc [chat-id message-id emoji-id emoji-reaction-id] reaction)))
(defn process-reactions [chats]
(defn process-reactions
[chats]
(fn [reactions new-reactions]
;; TODO(Ferossgp): handling own reaction in subscription could be expensive,
;; for better performance we can here separate own reaction into 2 maps
(reduce
(fn [acc {:keys [chat-id message-id emoji-id emoji-reaction-id retracted]
:as reaction}]
(fn [acc
{:keys [chat-id message-id emoji-id emoji-reaction-id retracted]
:as reaction}]
(cond-> (update-reaction acc retracted chat-id message-id emoji-id emoji-reaction-id reaction)
(get-in chats [chat-id :profile-public-key])
(update-reaction retracted constants/timeline-chat-id message-id emoji-id emoji-reaction-id reaction)))
(update-reaction retracted
constants/timeline-chat-id
message-id
emoji-id
emoji-reaction-id
reaction)))
reactions
new-reactions)))
@@ -32,12 +40,12 @@
(get-in db [:chats chat-id])]
(>= deleted-at-clock-value clock-value)))
(fx/defn receive-signal
(rf/defn receive-signal
[{:keys [db] :as cofx} reactions]
(let [reactions (filter (partial earlier-than-deleted-at? cofx) reactions)]
{:db (update db :reactions (process-reactions (:chats db)) reactions)}))
(fx/defn load-more-reactions
(rf/defn load-more-reactions
{:events [:load-more-reactions]}
[{:keys [db]} cursor chat-id]
(when-let [session-id (get-in db [:pagination-info chat-id :messages-initialized?])]
@@ -48,7 +56,7 @@
#(re-frame/dispatch [::reactions-loaded chat-id session-id %])
#(log/error "failed loading reactions" chat-id %))))
(fx/defn reactions-loaded
(rf/defn reactions-loaded
{:events [::reactions-loaded]}
[{db :db}
chat-id
@@ -64,33 +72,36 @@
;; Send reactions
(fx/defn send-emoji-reaction
(rf/defn send-emoji-reaction
{:events [::send-emoji-reaction]}
[{{:keys [current-chat-id]} :db :as cofx} reaction]
(message.protocol/send-reaction cofx
(update reaction :chat-id #(or % current-chat-id))))
(fx/defn send-retract-emoji-reaction
(rf/defn send-retract-emoji-reaction
{:events [::send-emoji-reaction-retraction]}
[{{:keys [current-chat-id]} :db :as cofx} reaction]
(message.protocol/send-retract-reaction cofx
(update reaction :chat-id #(or % current-chat-id))))
(fx/defn receive-one
(rf/defn receive-one
{:events [::receive-one]}
[{:keys [db]} reaction]
{:db (update db :reactions (process-reactions (:chats db)) [reaction])})
(defn message-reactions [current-public-key reactions]
(defn message-reactions
[current-public-key reactions]
(reduce
(fn [acc [emoji-id reactions]]
(if (pos? (count reactions))
(let [own (first (filter (fn [[_ {:keys [from]}]]
(= from current-public-key)) reactions))]
(conj acc {:emoji-id emoji-id
:own (boolean (seq own))
:emoji-reaction-id (:emoji-reaction-id (second own))
:quantity (count reactions)}))
(= from current-public-key))
reactions))]
(conj acc
{:emoji-id emoji-id
:own (boolean (seq own))
:emoji-reaction-id (:emoji-reaction-id (second own))
:quantity (count reactions)}))
acc))
[]
reactions))
+5 -5
View File
@@ -1,14 +1,14 @@
;;this ns is needed because of cycled deps
(ns status-im.chat.models.transport
(:require [status-im.utils.fx :as fx]
(:require [status-im.chat.models.message :as chat.message]
[status-im.transport.message.core :as transport.message]
[status-im.chat.models.message :as chat.message]))
[utils.re-frame :as rf]))
(fx/defn chat-ui-resend-message
(rf/defn chat-ui-resend-message
{:events [:chat.ui/resend-message]}
[{:keys [db] :as cofx} chat-id message-id]
(let [message (get-in db [:messages chat-id message-id])]
(fx/merge
(rf/merge
cofx
(transport.message/set-message-envelope-hash chat-id message-id (:message-type message))
(chat.message/resend-message chat-id message-id))))
(chat.message/resend-message chat-id message-id))))
+7 -1
View File
@@ -1,7 +1,8 @@
(ns status-im.chat.models-test
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.clocks :as utils.clocks]
[status-im.chat.models :as chat]))
[status-im.chat.models :as chat]
[status-im.chat.models.images :as images]))
(deftest clear-history-test
(let [chat-id "1"
@@ -91,3 +92,8 @@
(testing "Pagination info should be reset on navigation"
(let [res (chat/navigate-to-chat-nav2 {:db db} chat-id false)]
(is (nil? (get-in res [:db :pagination-info chat-id :all-loaded?])))))))
(deftest camera-roll-loading-more-test
(let [cofx {:db {:camera-roll/loading-more false}}]
(is (= {:db {:camera-roll/loading-more true}}
(images/camera-roll-loading-more cofx true)))))
+20 -20
View File
@@ -2,44 +2,44 @@
(:require [re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]))
[utils.re-frame :as rf]))
(fx/defn handle-prepare-accept-request-address-for-transaction
(rf/defn handle-prepare-accept-request-address-for-transaction
{:events [::prepare-accept-request-address-for-transaction]}
[{:keys [db]} message]
{:db (assoc db
:commands/select-account
{:message message
:from (ethereum/get-default-account (:multiaccount/accounts db))})
{:db (assoc db
:commands/select-account
{:message message
:from (ethereum/get-default-account (:multiaccount/accounts db))})
:show-select-acc-sheet nil})
(fx/defn set-selected-account
(rf/defn set-selected-account
{:events [::set-selected-account]}
[{:keys [db]} _ account]
{:db (-> (assoc-in db [:commands/select-account :from] account)
(assoc :bottom-sheet/show? false))})
(fx/defn handle-accept-request-address-for-transaction
(rf/defn handle-accept-request-address-for-transaction
{:events [::accept-request-address-for-transaction]}
[{:keys [db]} message-id address]
{:db (dissoc db :commands/select-account)
::json-rpc/call [{:method "wakuext_acceptRequestAddressForTransaction"
:params [message-id address]
{:db (dissoc db :commands/select-account)
::json-rpc/call [{:method "wakuext_acceptRequestAddressForTransaction"
:params [message-id address]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
(fx/defn handle-decline-request-address-for-transaction
(rf/defn handle-decline-request-address-for-transaction
{:events [::decline-request-address-for-transaction]}
[_ message-id]
{::json-rpc/call [{:method "wakuext_declineRequestAddressForTransaction"
:params [message-id]
{::json-rpc/call [{:method "wakuext_declineRequestAddressForTransaction"
:params [message-id]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
(fx/defn handle-decline-request-transaction
(rf/defn handle-decline-request-transaction
{:events [::decline-request-transaction]}
[cofx message-id]
{::json-rpc/call [{:method "wakuext_declineRequestTransaction"
:params [message-id]
{::json-rpc/call [{:method "wakuext_declineRequestTransaction"
:params [message-id]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
+201 -155
View File
@@ -1,25 +1,24 @@
(ns status-im.communities.core
(:require
[re-frame.core :as re-frame]
[clojure.walk :as walk]
[clojure.string :as string]
[clojure.set :as clojure.set]
[taoensso.timbre :as log]
[status-im.async-storage.core :as async-storage]
[status-im.utils.fx :as fx]
[status-im.constants :as constants]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.utils.universal-links.core :as universal-links]
[status-im.ethereum.json-rpc :as json-rpc]
[quo.design-system.colors :as colors]
[status-im2.navigation.events :as navigation]
[status-im.utils.handlers :refer [>evt]]
[status-im.ui.components.emoji-thumbnail.styles :as emoji-thumbnail-styles]
[status-im.activity-center.core :as activity-center]))
(:require [clojure.set :as clojure.set]
[clojure.string :as string]
[clojure.walk :as walk]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.async-storage.core :as async-storage]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ui.components.emoji-thumbnail.styles :as emoji-thumbnail-styles]
[status-im.utils.universal-links.core :as universal-links]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(def crop-size 1000)
(defn universal-link [community-id]
(defn universal-link
[community-id]
(str (:external universal-links/domains)
"/c/"
community-id))
@@ -28,18 +27,22 @@
[{:name "Status"
:id constants/status-community-id}])
(defn <-request-to-join-community-rpc [r]
(clojure.set/rename-keys r {:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(defn <-request-to-join-community-rpc
[r]
(clojure.set/rename-keys r
{:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(defn <-requests-to-join-community-rpc [requests]
(defn <-requests-to-join-community-rpc
[requests]
(reduce (fn [acc r]
(assoc acc (:id r) (<-request-to-join-community-rpc r)))
{}
requests))
(defn <-chats-rpc [chats]
(defn <-chats-rpc
[chats]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
@@ -50,7 +53,8 @@
{}
chats))
(defn <-categories-rpc [categ]
(defn <-categories-rpc
[categ]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
@@ -58,7 +62,8 @@
{}
categ))
(defn <-rpc [c]
(defn <-rpc
[c]
(-> c
(clojure.set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
@@ -70,25 +75,28 @@
(update :chats <-chats-rpc)
(update :categories <-categories-rpc)))
(defn fetch-community-id-input [{:keys [db]}]
(defn fetch-community-id-input
[{:keys [db]}]
(:communities/community-id-input db))
(fx/defn handle-request-to-join [{:keys [db]} r]
(rf/defn handle-request-to-join
[{:keys [db]} r]
(let [{:keys [id community-id] :as request} (<-request-to-join-community-rpc r)]
{:db (assoc-in db [:communities/requests-to-join community-id id] request)}))
(fx/defn handle-removed-chats [{:keys [db]} chat-ids]
(rf/defn handle-removed-chats
[{:keys [db]} chat-ids]
{:db (reduce (fn [db chat-id]
(update db :chats dissoc chat-id))
db
chat-ids)})
(fx/defn handle-community
(rf/defn handle-community
[{:keys [db]} {:keys [id] :as community}]
(when id
{:db (assoc-in db [:communities id] (<-rpc community))}))
(fx/defn handle-communities
(rf/defn handle-communities
{:events [::fetched]}
[{:keys [db]} communities]
{:db (reduce (fn [db {:keys [id] :as community}]
@@ -96,34 +104,36 @@
db
communities)})
(fx/defn handle-response [_ response-js]
(rf/defn handle-response
[_ response-js]
{:dispatch [:sanitize-messages-and-process-response response-js]})
(fx/defn left
(rf/defn left
{:events [::left]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(handle-response cofx response-js)
(navigation/pop-to-root-tab :chat-stack)
(activity-center/notifications-fetch-unread-count)))
(fx/defn joined
(rf/defn joined
{:events [::joined ::requested-to-join]}
[cofx response-js]
(handle-response cofx response-js))
(fx/defn export
(rf/defn export
{:events [::export-pressed]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_exportCommunity"
:params [community-id]
:on-success #(re-frame/dispatch [:show-popover {:view :export-community
:community-key %}])
:on-success #(re-frame/dispatch [:show-popover
{:view :export-community
:community-key %}])
:on-error #(do
(log/error "failed to export community" community-id %)
(re-frame/dispatch [::failed-to-export %]))}]})
(fx/defn import-community
(rf/defn import-community
{:events [::import]}
[cofx community-key]
{::json-rpc/call [{:method "wakuext_importCommunity"
@@ -134,7 +144,7 @@
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
(fx/defn join
(rf/defn join
{:events [:communities/join]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_joinCommunity"
@@ -145,7 +155,7 @@
(log/error "failed to join community" community-id %)
(re-frame/dispatch [::failed-to-join %]))}]})
(fx/defn request-to-join
(rf/defn request-to-join
{:events [::request-to-join]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_requestToJoinCommunity"
@@ -156,7 +166,7 @@
(log/error "failed to request to join community" community-id %)
(re-frame/dispatch [::failed-to-request-to-join %]))}]})
(fx/defn leave
(rf/defn leave
{:events [:communities/leave]}
[{:keys [db]} community-id]
(let [community-chat-ids (map #(str community-id %)
@@ -168,10 +178,13 @@
:js-response true
:on-success #(re-frame/dispatch [::left %])
:on-error #(do
(log/error "failed to leave community" community-id %)
(log/error "failed to leave community"
community-id
%)
(re-frame/dispatch [::failed-to-leave %]))}]}))
(fx/defn fetch [_]
(rf/defn fetch
[_]
{::json-rpc/call [{:method "wakuext_communities"
:params []
:on-success #(re-frame/dispatch [::fetched %])
@@ -179,7 +192,7 @@
(log/error "failed to fetch communities" %)
(re-frame/dispatch [::failed-to-fetch %]))}]})
(fx/defn chat-created
(rf/defn chat-created
{:events [::chat-created]}
[_ community-id user-pk]
{::json-rpc/call [{:method "wakuext_sendChatMessage"
@@ -193,7 +206,7 @@
:on-error
#(log/error "failed to send a message" %)}]})
(fx/defn invite-users
(rf/defn invite-users
{:events [::invite-people-confirmation-pressed]}
[cofx user-pk contacts]
(let [community-id (fetch-community-id-input cofx)
@@ -209,7 +222,7 @@
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
(fx/defn share-community
(rf/defn share-community
{:events [::share-community-confirmation-pressed]}
[cofx user-pk contacts]
(let [community-id (fetch-community-id-input cofx)
@@ -226,7 +239,7 @@
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-share-community %]))}]})))
(fx/defn create
(rf/defn create
{:events [::create-confirmation-pressed]}
[{:keys [db]}]
(let [{:keys [name description membership image]} (get db :communities/create)]
@@ -248,7 +261,7 @@
(log/error "failed to create community" %)
(re-frame/dispatch [::failed-to-create-community %]))}]})))
(fx/defn edit
(rf/defn edit
{:events [::edit-confirmation-pressed]}
[{:keys [db]}]
(let [{:keys [id name description membership new-image color]} (get db :communities/create)]
@@ -268,10 +281,10 @@
(log/error "failed to edit community" %)
(re-frame/dispatch [::failed-to-edit-community %]))}]}))
(fx/defn create-channel
(rf/defn create-channel
{:events [::create-channel-confirmation-pressed]}
[{:keys [db] :as cofx}]
(let [community-id (fetch-community-id-input cofx)
(let [community-id (fetch-community-id-input cofx)
{:keys [name description color emoji]} (get db :communities/create-channel)]
{::json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
@@ -279,7 +292,8 @@
:description description
:color color
:emoji emoji}
:permissions {:access constants/community-channel-access-no-membership}}]
:permissions {:access
constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-created %])
:on-error #(do
@@ -288,10 +302,11 @@
(def community-chat-id-length 68)
(defn to-community-chat-id [chat-id]
(defn to-community-chat-id
[chat-id]
(subs chat-id community-chat-id-length))
(fx/defn edit-channel
(rf/defn edit-channel
{:events [::edit-channel-confirmation-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
@@ -305,161 +320,171 @@
:emoji emoji}
:category_id category-id
:position position
:permissions {:access constants/community-channel-access-no-membership}}]
:permissions {:access
constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-edited %])
:on-error #(do
(log/error "failed to edit community channel" %)
(re-frame/dispatch [::failed-to-edit-community-channel %]))}]}))
(defn require-membership? [permissions]
(defn require-membership?
[permissions]
(not= constants/community-no-membership-access (:access permissions)))
(defn can-post? [community _ local-chat-id]
(defn can-post?
[community _ local-chat-id]
(let [chat-id (to-community-chat-id local-chat-id)]
(get-in community [:chats chat-id :can-post?])))
(fx/defn reset-community-id-input [{:keys [db]} id]
(rf/defn reset-community-id-input
[{:keys [db]} id]
{:db (assoc db :communities/community-id-input id)})
(fx/defn reset-channel-info [{:keys [db]}]
(rf/defn reset-channel-info
[{:keys [db]}]
{:db (assoc db :communities/create-channel {})})
(fx/defn invite-people-pressed
(rf/defn invite-people-pressed
{:events [:communities/invite-people-pressed]}
[cofx id]
(fx/merge cofx
(rf/merge cofx
(reset-community-id-input id)
(bottom-sheet/hide-bottom-sheet)
(navigation/open-modal :invite-people-community {:invite? true})))
(fx/defn share-community-pressed
(rf/defn share-community-pressed
{:events [:communities/share-community-pressed]}
[cofx id]
(fx/merge cofx
(rf/merge cofx
(reset-community-id-input id)
(bottom-sheet/hide-bottom-sheet)
(navigation/open-modal :invite-people-community {})))
(fx/defn create-channel-pressed
(rf/defn create-channel-pressed
{:events [::create-channel-pressed]}
[{:keys [db] :as cofx} id]
(fx/merge cofx
(rf/merge cofx
(reset-community-id-input id)
(reset-channel-info)
(>evt [::create-channel-fields (rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)])
(rf/dispatch [::create-channel-fields
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)])
(navigation/open-modal :create-community-channel {:community-id id})))
(fx/defn edit-channel-pressed
(rf/defn edit-channel-pressed
{:events [::edit-channel-pressed]}
[{:keys [db] :as cofx} community-id chat-name description color emoji chat-id category-id position]
(let [{:keys [color emoji]} (if (string/blank? emoji)
(rand-nth emoji-thumbnail-styles/emoji-picker-default-thumbnails)
{:color color :emoji emoji})]
(fx/merge cofx
{:db (assoc db :communities/create-channel {:name chat-name
:description description
:color color
:community-id community-id
:emoji emoji
:edit-channel-id chat-id
:category-id category-id
:position position})}
(rf/merge cofx
{:db (assoc db
:communities/create-channel
{:name chat-name
:description description
:color color
:community-id community-id
:emoji emoji
:edit-channel-id chat-id
:category-id category-id
:position position})}
(navigation/open-modal :edit-community-channel nil))))
(fx/defn community-created
(rf/defn community-created
{:events [::community-created]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(fx/defn community-edited
(rf/defn community-edited
{:events [::community-edited]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(fx/defn open-create-community
(rf/defn open-create-community
{:events [::open-create-community]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc db :communities/create {:membership constants/community-no-membership-access})}
(navigation/navigate-to :community-create nil)))
(fx/defn open-edit-community
(rf/defn open-edit-community
{:events [::open-edit-community]}
[{:keys [db] :as cofx} id]
(let [{:keys [name description images permissions color]} (get-in db [:communities id])
{:keys [access]} permissions]
(fx/merge cofx
{:db (assoc db :communities/create {:id id
:name name
:description description
:image (get-in images [:large :uri])
:membership access
:color color
:editing? true})}
{:keys [access]} permissions]
(rf/merge cofx
{:db (assoc db
:communities/create
{:id id
:name name
:description description
:image (get-in images [:large :uri])
:membership access
:color color
:editing? true})}
(navigation/navigate-to :community-edit nil))))
(fx/defn community-imported
(rf/defn community-imported
{:events [::community-imported]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(fx/defn people-invited
(rf/defn people-invited
{:events [::people-invited]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(fx/defn community-channel-created
(rf/defn community-channel-created
{:events [::community-channel-created]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(fx/defn community-channel-edited
(rf/defn community-channel-edited
{:events [::community-channel-edited]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(fx/defn create-field
(rf/defn create-field
{:events [::create-field]}
[{:keys [db]} field value]
{:db (assoc-in db [:communities/create field] value)})
(fx/defn remove-field
(rf/defn remove-field
{:events [::remove-field]}
[{:keys [db]} field]
{:db (update-in db [:communities/create] dissoc field)})
(fx/defn create-channel-field
(rf/defn create-channel-field
{:events [::create-channel-field]}
[{:keys [db]} field value]
{:db (assoc-in db [:communities/create-channel field] value)})
(fx/defn create-channel-fields
(rf/defn create-channel-fields
{:events [::create-channel-fields]}
[{:keys [db]} field-values]
{:db (update-in db [:communities/create-channel] merge field-values)})
(fx/defn member-banned
(rf/defn member-banned
{:events [::member-banned]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response-js)
(activity-center/notifications-fetch-unread-count)))
(fx/defn member-ban
(rf/defn member-ban
{:events [::member-ban]}
[cofx community-id public-key]
{::json-rpc/call [{:method "wakuext_banUserFromCommunity"
@@ -467,35 +492,43 @@
:user public-key}]
:js-response true
:on-success #(re-frame/dispatch [::member-banned %])
:on-error #(log/error "failed to ban user from community" community-id public-key %)}]})
:on-error #(log/error "failed to ban user from community"
community-id
public-key
%)}]})
(fx/defn member-kicked
(rf/defn member-kicked
{:events [::member-kicked]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response-js)))
(fx/defn member-kick
(rf/defn member-kick
{:events [::member-kick]}
[cofx community-id public-key]
{::json-rpc/call [{:method "wakuext_removeUserFromCommunity"
:params [community-id public-key]
:js-response true
:on-success #(re-frame/dispatch [::member-kicked %])
:on-error #(log/error "failed to remove user from community" community-id public-key %)}]})
:on-error #(log/error "failed to remove user from community"
community-id
public-key
%)}]})
(fx/defn delete-community
(rf/defn delete-community
{:events [::delete-community]}
[cofx community-id]
(log/error "Community delete is not yet implemented"))
(fx/defn requests-to-join-fetched
(rf/defn requests-to-join-fetched
{:events [::requests-to-join-fetched]}
[{:keys [db]} community-id requests]
{:db (assoc-in db [:communities/requests-to-join community-id] (<-requests-to-join-community-rpc requests))})
{:db (assoc-in db
[:communities/requests-to-join community-id]
(<-requests-to-join-community-rpc requests))})
(fx/defn fetch-requests-to-join
(rf/defn fetch-requests-to-join
{:events [::fetch-requests-to-join]}
[cofx community-id]
{::json-rpc/call [{:method "wakuext_pendingRequestsToJoinForCommunity"
@@ -503,48 +536,56 @@
:on-success #(re-frame/dispatch [::requests-to-join-fetched community-id %])
:on-error #(log/error "failed to fetch requests-to-join" community-id %)}]})
(defn fetch-requests-to-join! [community-id]
(defn fetch-requests-to-join!
[community-id]
(re-frame/dispatch [::fetch-requests-to-join community-id]))
(fx/defn request-to-join-accepted
(rf/defn request-to-join-accepted
{:events [::request-to-join-accepted]}
[{:keys [db] :as cofx} community-id request-id response-js]
(fx/merge cofx
(rf/merge cofx
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)}
(handle-response response-js)))
(fx/defn request-to-join-declined
(rf/defn request-to-join-declined
{:events [::request-to-join-declined]}
[{:keys [db] :as cofx} community-id request-id response-js]
(fx/merge cofx
(rf/merge cofx
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)}
(handle-response response-js)))
(fx/defn accept-request-to-join-pressed
(rf/defn accept-request-to-join-pressed
{:events [:communities.ui/accept-request-to-join-pressed]}
[cofx community-id request-id]
{::json-rpc/call [{:method "wakuext_acceptRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id %])
:on-error #(log/error "failed to accept requests-to-join" community-id request-id %)}]})
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id
%])
:on-error #(log/error "failed to accept requests-to-join"
community-id
request-id
%)}]})
(fx/defn decline-request-to-join-pressed
(rf/defn decline-request-to-join-pressed
{:events [:communities.ui/decline-request-to-join-pressed]}
[cofx community-id request-id]
{::json-rpc/call [{:method "wakuext_declineRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id %])
:on-error #(log/error "failed to decline requests-to-join" community-id request-id)}]})
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id
%])
:on-error #(log/error "failed to decline requests-to-join"
community-id
request-id)}]})
(fx/defn switch-communities-enabled
(rf/defn switch-communities-enabled
{:events [:multiaccounts.ui/switch-communities-enabled]}
[{:keys [db]} enabled?]
{::async-storage/set! {:communities-enabled? enabled?}
:db (assoc db :communities/enabled? enabled?)})
(fx/defn create-category
(rf/defn create-category
{:events [::create-category-confirmation-pressed]}
[_ community-id category-title chat-ids]
{::json-rpc/call [{:method "wakuext_createCommunityCategory"
@@ -557,12 +598,13 @@
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to create community category" %)}]})
(fx/defn remove-chat-from-category
(rf/defn remove-chat-from-category
{:events [:remove-chat-from-community-category]}
[{:keys [db]} community-id id categoryID]
(let [category (get-in db [:communities community-id :categories categoryID])
category-chats (map :id (filter #(and (= (:categoryID %) categoryID) (not= id (:id %)))
(vals (get-in db [:communities community-id :chats]))))]
category-chats (map :id
(filter #(and (= (:categoryID %) categoryID) (not= id (:id %)))
(vals (get-in db [:communities community-id :chats]))))]
{::json-rpc/call [{:method "wakuext_editCommunityCategory"
:params [{:communityId community-id
:categoryId categoryID
@@ -572,7 +614,7 @@
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove chat from community" %)}]}))
(fx/defn delete-community-chat
(rf/defn delete-community-chat
{:events [:delete-community-chat]}
[_ community-id chat-id]
{::json-rpc/call [{:method "wakuext_deleteCommunityChat"
@@ -581,7 +623,7 @@
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community chat" %)}]})
(fx/defn delete-category
(rf/defn delete-category
{:events [:delete-community-category]}
[_ community-id category-id]
{::json-rpc/call [{:method "wakuext_deleteCommunityCategory"
@@ -591,7 +633,7 @@
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community category" %)}]})
(fx/defn change-category
(rf/defn change-category
{:events [::change-category-confirmation-pressed]}
[cofx community-id category-id {:keys [id position categoryID]}]
(if (not (string/blank? category-id))
@@ -605,11 +647,11 @@
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to change community category" %)}]}
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(remove-chat-from-category community-id id categoryID))))
(fx/defn reorder-category-chat
(rf/defn reorder-category-chat
{:events [::reorder-community-category-chat]}
[_ community-id category-id chat-id new-position]
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
@@ -621,7 +663,7 @@
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category chat" %)}]})
(fx/defn reorder-category
(rf/defn reorder-category
{:events [::reorder-community-category]}
[_ community-id category-id new-position]
{::json-rpc/call [{:method "wakuext_reorderCommunityCategories"
@@ -632,17 +674,18 @@
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category" %)}]})
(defn category-hash [public-key community-id category-id]
(defn category-hash
[public-key community-id category-id]
(hash (str public-key community-id category-id)))
(fx/defn store-category-state
(rf/defn store-category-state
{:events [::store-category-state]}
[{:keys [db]} community-id category-id state-open?]
(let [public-key (get-in db [:multiaccount :public-key])
hash (category-hash public-key community-id category-id)]
{::async-storage/set! {hash state-open?}}))
(fx/defn update-category-states-in-db
(rf/defn update-category-states-in-db
{:events [::category-states-loaded]}
[{:keys [db]} community-id hashes states]
(let [public-key (get-in db [:multiaccount :public-key])
@@ -652,10 +695,11 @@
state (get states hash)
category-updated (assoc category :state state)]
(assoc acc category-id category-updated)))
{} categories-old)]
{}
categories-old)]
{:db (update-in db [:communities community-id :categories] merge categories)}))
(fx/defn load-category-states
(rf/defn load-category-states
{:events [:communities/load-category-states]}
[{:keys [db]} community-id]
(let [public-key (get-in db [:multiaccount :public-key])
@@ -669,26 +713,27 @@
(-> acc
(assoc-in [:hashes category-id] hash)
(update :keys #(conj % hash)))))
{} categories)]
{}
categories)]
{::async-storage/get {:keys keys
:cb #(re-frame/dispatch
[::category-states-loaded community-id hashes %])}}))
(fx/defn navigate-to-community
(rf/defn navigate-to-community
{:events [:communities/navigate-to-community]}
[cofx community-id]
(fx/merge cofx
(rf/merge cofx
(navigation/pop-to-root-tab :shell-stack)
(navigation/navigate-to-nav2 :community community-id true)))
(fx/defn member-role-updated
(rf/defn member-role-updated
{:events [:community.member/role-updated]}
[cofx response-js]
(fx/merge cofx
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet)
(handle-response response-js)))
(fx/defn add-role-to-member
(rf/defn add-role-to-member
{:events [:community.member/add-role]}
[cofx community-id public-key role-id]
{::json-rpc/call [{:method "wakuext_addRoleToMember"
@@ -702,7 +747,7 @@
:public-key public-key
:role-id role-id})}]})
(fx/defn remove-role-from-member
(rf/defn remove-role-from-member
{:events [:community.member/remove-role]}
[_ community-id public-key role-id]
{::json-rpc/call [{:method "wakuext_removeRoleFromMember"
@@ -710,8 +755,9 @@
:user public-key
:role role-id}]}
:on-success #(re-frame/dispatch [:community.member/role-updated %])
:on-error #(log/error "failed to remove role from member"
{:error %
:community-id community-id
:public-key public-key
:role-id role-id})]})
:on-error
#(log/error "failed to remove role from member"
{:error %
:community-id community-id
:public-key public-key
:role-id role-id})]})
+7
View File
@@ -200,3 +200,10 @@
(def ^:const community-member-role-all 1)
(def ^:const community-member-role-manage-users 2)
(def ^:const community-member-role-moderator 3)
(def local-pairing-connection-string-identifier
"If any string begins with cs we know its a connection string.
This is useful when we read QR codes we know it is a connection string if it begins with this identifier.
An example of a connection string is -> cs2:5vd6J6:Jfc:27xMmHKEYwzRGXcvTtuiLZFfXscMx4Mz8d9wEHUxDj4p7:EG7Z13QScfWBJNJ5cprszzDQ5fBVsYMirXo8MaQFJvpF:3 "
"cs")
+37 -34
View File
@@ -4,12 +4,12 @@
[status-im.contact.db :as contact.db]
[status-im.data-store.chats :as chats-store]
[status-im.data-store.contacts :as contacts-store]
[status-im2.navigation.events :as navigation]
[status-im.utils.types :as types]
[status-im.activity-center.core :as activity-center]
[status-im.utils.fx :as fx]))
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(fx/defn clean-up-chat
(rf/defn clean-up-chat
[{:keys [db] :as cofx}
public-key
{:keys [chat-id
@@ -21,60 +21,63 @@
(when (= from public-key)
message-id))
(get-in db [:messages chat-id]))
db (-> db
;; remove messages
(update-in [:messages chat-id]
#(apply dissoc % removed-messages-ids))
(update-in [:chats chat-id]
assoc
:unviewed-messages-count unviewed-messages-count
:unviewed-mentions-count unviewed-mentions-count
:last-message last-message))]
{:db (assoc-in db [:message-lists chat-id]
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))}))
db (-> db
;; remove messages
(update-in [:messages chat-id]
#(apply dissoc % removed-messages-ids))
(update-in [:chats chat-id]
assoc
:unviewed-messages-count unviewed-messages-count
:unviewed-mentions-count unviewed-mentions-count
:last-message last-message))]
{:db (assoc-in db
[:message-lists chat-id]
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))}))
(fx/defn contact-blocked
(rf/defn contact-blocked
{:events [::contact-blocked]}
[{:keys [db] :as cofx} {:keys [public-key]} chats]
(let [fxs (when chats
(map #(->> (chats-store/<-rpc %)
(clean-up-chat public-key)) (types/js->clj chats)))]
(apply fx/merge
(clean-up-chat public-key))
(types/js->clj chats)))]
(apply rf/merge
cofx
{:db (-> db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key :added] false))
{:db (-> db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key :added] false))
:clear-message-notifications
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
(activity-center/notifications-fetch-unread-count)
fxs)))
(fx/defn block-contact
(rf/defn block-contact
{:events [:contact.ui/block-contact-confirmed]}
[{:keys [db] :as cofx} public-key]
(let [contact (-> (contact.db/public-key->contact
(:contacts/contacts db)
public-key)
(assoc :blocked true
:added false))
(let [contact (-> (contact.db/public-key->contact
(:contacts/contacts db)
public-key)
(assoc :blocked true
:added false))
from-one-to-one-chat? (not (get-in db [:chats (:current-chat-id db) :group-chat]))]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
;; add the contact to blocked contacts
(update :contacts/blocked (fnil conj #{}) public-key)
;; update the contact in contacts list
(assoc-in [:contacts/contacts public-key] contact))}
(contacts-store/block
public-key #(do (re-frame/dispatch [::contact-blocked contact (.-chats %)])
(re-frame/dispatch [:sanitize-messages-and-process-response %])
(re-frame/dispatch [:hide-popover])))
public-key
#(do (re-frame/dispatch [::contact-blocked contact (.-chats %)])
(re-frame/dispatch [:sanitize-messages-and-process-response %])
(re-frame/dispatch [:hide-popover])))
;; reset navigation to avoid going back to non existing one to one chat
(if from-one-to-one-chat?
(navigation/pop-to-root-tab :chat-stack)
(navigation/navigate-back)))))
(fx/defn contact-unblocked
(rf/defn contact-unblocked
{:events [::contact-unblocked]}
[{:keys [db]} contact-id]
(let [contact (-> (get-in db [:contacts/contacts contact-id])
@@ -83,7 +86,7 @@
(update :contacts/blocked disj contact-id)
(assoc-in [:contacts/contacts contact-id] contact))}))
(fx/defn unblock-contact
(rf/defn unblock-contact
{:events [:contact.ui/unblock-contact-pressed]}
[cofx contact-id]
(contacts-store/unblock
+8 -8
View File
@@ -1,29 +1,29 @@
(ns status-im.contact.chat
(:require [re-frame.core :as re-frame]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.chat.models :as chat]
[status-im.contact.core :as contact]))
[status-im.contact.core :as contact]
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(fx/defn send-message-pressed
(rf/defn send-message-pressed
{:events [:contact.ui/send-message-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[cofx {:keys [public-key ens-name]}]
(chat/start-chat cofx public-key ens-name))
(fx/defn contact-code-submitted
(rf/defn contact-code-submitted
{:events [:contact.ui/contact-code-submitted]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:contacts/keys [new-identity]} :db :as cofx} new-contact? nickname]
(let [{:keys [public-key ens-name]} new-identity]
(fx/merge cofx
(rf/merge cofx
#(if new-contact?
(contact/add-contact % public-key nickname ens-name)
(chat/start-chat % public-key ens-name))
#(when new-contact?
(navigation/navigate-back %)))))
(fx/defn pinned-messages-pressed
{:events [:contact.ui/pinned-messages-pressed]}
(rf/defn pinned-messages-pressed
{:events [:contact.ui/pinned-messages-pressed]}
[cofx public-key]
(chat/navigate-to-user-pinned-messages cofx public-key))
+50 -45
View File
@@ -1,42 +1,44 @@
(ns status-im.contact.core
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.contact.block :as contact.block]
[status-im.contact.db :as contact.db]
[status-im.data-store.contacts :as contacts-store]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im2.navigation.events :as navigation]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[status-im.constants :as constants]
[status-im.contact.block :as contact.block]))
[utils.re-frame :as rf]))
(fx/defn load-contacts
(rf/defn load-contacts
{:events [::contacts-loaded]}
[{:keys [db] :as cofx} all-contacts]
(let [contacts-list (map #(vector (:public-key %) (if (empty? (:address %))
(dissoc % :address)
%))
(let [contacts-list (map #(vector (:public-key %)
(if (empty? (:address %))
(dissoc % :address)
%))
all-contacts)
contacts (into {} contacts-list)]
contacts (into {} contacts-list)]
{:db (cond-> (-> db
(update :contacts/contacts #(merge contacts %))
(assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts))))}))
(defn build-contact
[{{:keys [multiaccount]
:contacts/keys [contacts]} :db} public-key]
[{{:keys [multiaccount]
:contacts/keys [contacts]}
:db} public-key]
(cond-> (contact.db/public-key->contact contacts public-key)
(= public-key (:public-key multiaccount))
(assoc :name (:name multiaccount))))
(fx/defn ensure-contacts
(rf/defn ensure-contacts
[{:keys [db]} contacts chats]
(let [events
(reduce
(fn [acc {:keys [public-key] :as contact}]
(let [added (:added contact)
was-added (contact.db/added? db public-key)
blocked (:blocked contact)
(let [added (:added contact)
was-added (contact.db/added? db public-key)
blocked (:blocked contact)
was-blocked (contact.db/blocked? db public-key)]
(cond-> acc
(and added (not was-added))
@@ -51,7 +53,8 @@
[:activity-center.notifications/fetch-unread-count]]
contacts)]
(merge
{:db (update db :contacts/contacts
{:db (update db
:contacts/contacts
#(reduce (fn [acc {:keys [public-key] :as contact}]
(-> acc
(update public-key merge contact)
@@ -68,15 +71,15 @@
:profile-image identicon
:address address}))
(fx/defn send-contact-request
(rf/defn send-contact-request
{:events [::send-contact-request]}
[{:keys [db] :as cofx} public-key]
(let [{:keys [name profile-image]} (own-info db)]
{::json-rpc/call [{:method "wakuext_sendContactUpdate"
:params [public-key name profile-image]
{::json-rpc/call [{:method "wakuext_sendContactUpdate"
:params [public-key name profile-image]
:on-success #(log/debug "contact request sent" public-key)}]}))
(fx/defn add-contact
(rf/defn add-contact
"Add a contact and set pending to false"
{:events [:contact.ui/add-to-contact-pressed]}
[{:keys [db] :as cofx} public-key nickname ens-name]
@@ -90,60 +93,62 @@
(re-frame/dispatch [:sanitize-messages-and-process-response %])
(re-frame/dispatch [:offload-messages constants/timeline-chat-id])))))
(fx/defn remove-contact
(rf/defn remove-contact
"Remove a contact from current account's contact list"
{:events [:contact.ui/remove-contact-pressed]}
[{:keys [db]} {:keys [public-key]}]
{:db (-> db
(assoc-in [:contacts/contacts public-key :added] false)
(assoc-in [:contacts/contacts public-key :contact-request-state] constants/contact-request-state-none))
::json-rpc/call [{:method "wakuext_removeContact"
:params [public-key]
{:db (-> db
(assoc-in [:contacts/contacts public-key :added] false)
(assoc-in [:contacts/contacts public-key :contact-request-state]
constants/contact-request-state-none))
::json-rpc/call [{:method "wakuext_removeContact"
:params [public-key]
:on-success #(log/debug "contact removed successfully")}
{:method "wakuext_retractContactRequest"
:params [{:contactId public-key}]
{:method "wakuext_retractContactRequest"
:params [{:contactId public-key}]
:on-success #(log/debug "contact removed successfully")}]
:dispatch [:offload-messages constants/timeline-chat-id]})
:dispatch [:offload-messages constants/timeline-chat-id]})
(fx/defn accept-contact-request
(rf/defn accept-contact-request
{:events [:contact-requests.ui/accept-request]}
[{:keys [db]} id]
{::json-rpc/call [{:method "wakuext_acceptContactRequest"
:params [{:id id}]
{::json-rpc/call [{:method "wakuext_acceptContactRequest"
:params [{:id id}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
(fx/defn decline-contact-request
(rf/defn decline-contact-request
{:events [:contact-requests.ui/decline-request]}
[{:keys [db]} id]
{::json-rpc/call [{:method "wakuext_dismissContactRequest"
:params [{:id id}]
{::json-rpc/call [{:method "wakuext_dismissContactRequest"
:params [{:id id}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
(fx/defn initialize-contacts [cofx]
(rf/defn initialize-contacts
[cofx]
(contacts-store/fetch-contacts-rpc cofx #(re-frame/dispatch [::contacts-loaded %])))
(fx/defn open-contact-toggle-list
(rf/defn open-contact-toggle-list
{:events [:contact.ui/start-group-chat-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc db
:group/selected-contacts #{}
:new-chat-name "")}
:new-chat-name "")}
(navigation/navigate-to-cofx :contact-toggle-list nil)))
(fx/defn update-nickname
(rf/defn update-nickname
{:events [:contacts/update-nickname]}
[{:keys [db] :as cofx} public-key nickname]
(fx/merge cofx
(rf/merge cofx
(contacts-store/set-nickname
public-key
nickname
#(re-frame/dispatch [:sanitize-messages-and-process-response %]))
(navigation/navigate-back)))
(fx/defn switch-mutual-contact-requests-enabled
(rf/defn switch-mutual-contact-requests-enabled
{:events [:multiaccounts.ui/switch-mutual-contact-requests-enabled]}
[cofx enabled?]
(multiaccounts.update/multiaccount-update
@@ -152,7 +157,7 @@
enabled?
nil))
(fx/defn set-search-query
(rf/defn set-search-query
{:events [:contacts/set-search-query]}
[{:keys [db] :as cofx} value]
{:db (assoc db :contacts/search-query value)})
+8 -6
View File
@@ -1,16 +1,18 @@
(ns status-im.currency.core
(:require [status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[status-im.wallet.prices :as prices]))
[status-im.wallet.prices :as prices]
[utils.re-frame :as rf]))
(defn get-currency [db]
(defn get-currency
[db]
(get-in db [:multiaccount :currency] :usd))
(fx/defn set-currency
(rf/defn set-currency
{:events [:wallet.settings.ui/currency-selected]}
[{:keys [db] :as cofx} currency]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:currency currency
:currency
currency
{})
(prices/update-prices)))
+1 -1
View File
@@ -1,7 +1,7 @@
(ns status-im.data-store.activities
(:require [clojure.set :as set]
[status-im.constants :as constants]
[status-im.activity-center.notification-types :as notification-types]
[status-im2.contexts.activity-center.notification-types :as notification-types]
[status-im.data-store.messages :as messages]))
(defn- rpc->type [{:keys [type name] :as chat}]
@@ -1,7 +1,7 @@
(ns status-im.data-store.activities-test
(:require [cljs.test :refer [deftest is testing]]
[status-im.constants :as constants]
[status-im.activity-center.notification-types :as notification-types]
[status-im2.contexts.activity-center.notification-types :as notification-types]
[status-im.data-store.activities :as store]))
(def chat-id
+48 -41
View File
@@ -1,31 +1,34 @@
(ns status-im.data-store.chats
(:require [clojure.set :as clojure.set]
[status-im.constants :as constants]
[status-im.data-store.messages :as messages]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.constants :as constants]
[status-im.utils.fx :as fx]
[status-im.utils.types :as types]
[taoensso.timbre :as log]
[status-im.utils.types :as types]))
[utils.re-frame :as rf]))
(defn rpc->type [{:keys [chat-type name] :as chat}]
(defn rpc->type
[{:keys [chat-type name] :as chat}]
(cond
(or (= constants/public-chat-type chat-type)
(= constants/profile-chat-type chat-type)
(= constants/timeline-chat-type chat-type)) (assoc chat
:chat-name (str "#" name)
:public? true
:group-chat true
:timeline? (= constants/timeline-chat-type chat-type))
(= constants/timeline-chat-type chat-type))
(assoc chat
:chat-name (str "#" name)
:public? true
:group-chat true
:timeline? (= constants/timeline-chat-type chat-type))
(= constants/community-chat-type chat-type) (assoc chat
:chat-name name
:chat-name name
:group-chat true)
(= constants/private-group-chat-type chat-type) (assoc chat
:chat-name name
:public? false
:chat-name name
:public? false
:group-chat true)
:else (assoc chat :public? false :group-chat false)))
(defn members-reducer [acc member]
(defn members-reducer
[acc member]
(cond-> acc
(:admin member)
(update :admins conj (:id member))
@@ -34,45 +37,48 @@
:always
(update :contacts conj (:id member))))
(defn- unmarshal-members [{:keys [members chat-type] :as chat}]
(defn- unmarshal-members
[{:keys [members chat-type] :as chat}]
(cond
(= constants/public-chat-type chat-type) (assoc chat
:contacts #{}
:admins #{}
:members-joined #{})
(= constants/public-chat-type chat-type) (assoc chat
:contacts #{}
:admins #{}
:members-joined #{})
(= constants/private-group-chat-type chat-type) (merge chat
(reduce members-reducer
{:admins #{}
{:admins #{}
:members-joined #{}
:contacts #{}}
:contacts #{}}
members))
:else
(assoc chat
:contacts #{(:id chat)}
:admins #{}
:contacts #{(:id chat)}
:admins #{}
:members-joined #{})))
(defn <-rpc [chat]
(defn <-rpc
[chat]
(-> chat
(clojure.set/rename-keys {:id :chat-id
:communityId :community-id
:syncedFrom :synced-from
:syncedTo :synced-to
(clojure.set/rename-keys {:id :chat-id
:communityId :community-id
:syncedFrom :synced-from
:syncedTo :synced-to
:membershipUpdateEvents :membership-update-events
:deletedAtClockValue :deleted-at-clock-value
:chatType :chat-type
:unviewedMessagesCount :unviewed-messages-count
:unviewedMentionsCount :unviewed-mentions-count
:lastMessage :last-message
:lastClockValue :last-clock-value
:invitationAdmin :invitation-admin
:profile :profile-public-key})
:deletedAtClockValue :deleted-at-clock-value
:chatType :chat-type
:unviewedMessagesCount :unviewed-messages-count
:unviewedMentionsCount :unviewed-mentions-count
:lastMessage :last-message
:lastClockValue :last-clock-value
:invitationAdmin :invitation-admin
:profile :profile-public-key})
rpc->type
unmarshal-members
(update :last-message #(when % (messages/<-rpc %)))
(dissoc :members)))
(defn <-rpc-js [^js chat]
(defn <-rpc-js
[^js chat]
(-> {:name (.-name chat)
:description (.-description chat)
:color (.-color chat)
@@ -103,9 +109,10 @@
rpc->type
unmarshal-members))
(fx/defn fetch-chats-rpc [_ {:keys [on-success]}]
{::json-rpc/call [{:method "wakuext_chatsPreview"
:params []
(rf/defn fetch-chats-rpc
[_ {:keys [on-success]}]
{::json-rpc/call [{:method "wakuext_chatsPreview"
:params []
:js-response true
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
:on-success #(on-success ^js %)
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
+42 -35
View File
@@ -1,10 +1,11 @@
(ns status-im.data-store.contacts
(:require [clojure.set :as clojure.set]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn <-rpc [contact]
(defn <-rpc
[contact]
(-> contact
(clojure.set/rename-keys
{:id :public-key
@@ -17,48 +18,54 @@
:lastENSClockValue :last-ens-clock-value
:lastUpdated :last-updated
:localNickname :nickname})
(assoc :mutual? (and (:added contact)
(:hasAddedUs contact)))))
(assoc :mutual?
(and (:added contact)
(:hasAddedUs contact)))))
(fx/defn fetch-contacts-rpc
(rf/defn fetch-contacts-rpc
[_ on-success]
{::json-rpc/call [{:method "wakuext_contacts"
:params []
{::json-rpc/call [{:method "wakuext_contacts"
:params []
:on-success #(on-success (map <-rpc %))
:on-error #(log/error "failed to fetch contacts" %)}]})
:on-error #(log/error "failed to fetch contacts" %)}]})
(fx/defn add
(rf/defn add
[_ public-key nickname ens-name on-success]
{::json-rpc/call [{:method "wakuext_addContact"
:params [{:id public-key :nickname nickname :ensName ens-name}]
{::json-rpc/call [{:method "wakuext_addContact"
:params [{:id public-key :nickname nickname :ensName ens-name}]
:js-response true
:on-success #(do
(log/info "saved contact" public-key "successfuly")
(when on-success
(on-success %)))
:on-error #(log/error "failed to add contact" public-key %)}]})
:on-success #(do
(log/info "saved contact" public-key "successfuly")
(when on-success
(on-success %)))
:on-error #(log/error "failed to add contact" public-key %)}]})
(fx/defn set-nickname
(rf/defn set-nickname
[_ public-key nickname on-success]
{::json-rpc/call [{:method "wakuext_setContactLocalNickname"
:params [{:id public-key :nickname nickname}]
{::json-rpc/call [{:method "wakuext_setContactLocalNickname"
:params [{:id public-key :nickname nickname}]
:js-response true
:on-success #(do
(log/debug "set contact nickname" public-key "successfuly" nickname)
(when on-success
(on-success %)))
:on-error #(log/error "failed to set contact nickname " public-key nickname %)}]})
:on-success #(do
(log/debug "set contact nickname" public-key "successfuly" nickname)
(when on-success
(on-success %)))
:on-error #(log/error "failed to set contact nickname "
public-key
nickname
%)}]})
(fx/defn block [_ contact-id on-success]
{::json-rpc/call [{:method "wakuext_blockContact"
:params [contact-id]
(rf/defn block
[_ contact-id on-success]
{::json-rpc/call [{:method "wakuext_blockContact"
:params [contact-id]
:js-response true
:on-success on-success
:on-error #(log/error "failed to block contact" % contact-id)}]})
:on-success on-success
:on-error #(log/error "failed to block contact" % contact-id)}]})
(fx/defn unblock [_ contact-id on-success]
{::json-rpc/call [{:method "wakuext_unblockContact"
:params [contact-id]
:on-success on-success
(rf/defn unblock
[_ contact-id on-success]
{::json-rpc/call [{:method "wakuext_unblockContact"
:params [contact-id]
:on-success on-success
:js-response true
:on-error #(log/error "failed to unblock contact" % contact-id)}]})
:on-error #(log/error "failed to unblock contact" % contact-id)}]})
+79 -64
View File
@@ -1,103 +1,118 @@
(ns status-im.data-store.messages
(:require [clojure.set :as clojure.set]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn ->rpc [{:keys [content] :as message}]
(defn ->rpc
[{:keys [content] :as message}]
(cond-> message
content
(assoc :text (:text content)
(assoc :text (:text content)
:sticker (:sticker content))
:always
(clojure.set/rename-keys {:chat-id :chat_id
(clojure.set/rename-keys {:chat-id :chat_id
:whisper-timestamp :whisperTimestamp
:community-id :communityId
:clock-value :clock})))
:community-id :communityId
:clock-value :clock})))
(defn <-rpc [message]
(defn <-rpc
[message]
(-> message
(clojure.set/rename-keys {:id :message-id
:whisperTimestamp :whisper-timestamp
:editedAt :edited-at
(clojure.set/rename-keys {:id :message-id
:whisperTimestamp :whisper-timestamp
:editedAt :edited-at
:contactVerificationState :contact-verification-state
:contactRequestState :contact-request-state
:commandParameters :command-parameters
:gapParameters :gap-parameters
:messageType :message-type
:localChatId :chat-id
:communityId :community-id
:contentType :content-type
:clock :clock-value
:quotedMessage :quoted-message
:outgoingStatus :outgoing-status
:audioDurationMs :audio-duration-ms
:deleted :deleted?
:deletedForMe :deleted-for-me?
:new :new?})
:contactRequestState :contact-request-state
:commandParameters :command-parameters
:gapParameters :gap-parameters
:messageType :message-type
:localChatId :chat-id
:communityId :community-id
:contentType :content-type
:clock :clock-value
:quotedMessage :quoted-message
:outgoingStatus :outgoing-status
:audioDurationMs :audio-duration-ms
:deleted :deleted?
:deletedForMe :deleted-for-me?
:new :new?})
(update :quoted-message clojure.set/rename-keys {:parsedText :parsed-text :communityId :community-id})
(update :quoted-message
clojure.set/rename-keys
{:parsedText :parsed-text :communityId :community-id})
(update :outgoing-status keyword)
(update :command-parameters clojure.set/rename-keys {:transactionHash :transaction-hash
:commandState :command-state})
(assoc :content {:chat-id (:chatId message)
:text (:text message)
:image (:image message)
:sticker (:sticker message)
:ens-name (:ensName message)
:line-count (:lineCount message)
:parsed-text (:parsedText message)
:links (:links message)
:rtl? (:rtl message)
:response-to (:responseTo message)}
(update :command-parameters
clojure.set/rename-keys
{:transactionHash :transaction-hash
:commandState :command-state})
(assoc :content {:chat-id (:chatId message)
:text (:text message)
:image (:image message)
:sticker (:sticker message)
:ens-name (:ensName message)
:line-count (:lineCount message)
:parsed-text (:parsedText message)
:links (:links message)
:rtl? (:rtl message)
:response-to (:responseTo message)}
:outgoing (boolean (:outgoingStatus message)))
(dissoc :ensName :chatId :text :rtl :responseTo :image :sticker :lineCount :parsedText :links)))
(defn messages-by-chat-id-rpc [chat-id
cursor
limit
on-success
on-error]
(defn messages-by-chat-id-rpc
[chat-id
cursor
limit
on-success
on-error]
{::json-rpc/call [{:method "wakuext_chatMessages"
:params [chat-id cursor limit]
:on-success (fn [result]
(on-success (update result :messages #(map <-rpc %))))
:on-error on-error}]})
:on-error on-error}]})
(defn mark-seen-rpc [chat-id ids on-success]
{::json-rpc/call [{:method "wakuext_markMessagesSeen"
:params [chat-id ids]
(defn mark-seen-rpc
[chat-id ids on-success]
{::json-rpc/call [{:method "wakuext_markMessagesSeen"
:params [chat-id ids]
:on-success #(do
(log/debug "successfully marked as seen" %)
(when on-success (on-success chat-id ids %)))
:on-error #(log/error "failed to get messages" %)}]})
:on-error #(log/error "failed to get messages" %)}]})
(defn delete-message-rpc [id]
{::json-rpc/call [{:method "wakuext_deleteMessage"
:params [id]
(defn delete-message-rpc
[id]
{::json-rpc/call [{:method "wakuext_deleteMessage"
:params [id]
:on-success #(log/debug "successfully deleted message" id)
:on-error #(log/error "failed to delete message" % id)}]})
:on-error #(log/error "failed to delete message" % id)}]})
(defn delete-messages-from-rpc [author]
{::json-rpc/call [{:method "wakuext_deleteMessagesFrom"
:params [author]
(defn delete-messages-from-rpc
[author]
{::json-rpc/call [{:method "wakuext_deleteMessagesFrom"
:params [author]
:on-success #(log/debug "successfully deleted messages from" author)
:on-error #(log/error "failed to delete messages from" % author)}]})
:on-error #(log/error "failed to delete messages from" % author)}]})
(defn delete-messages-by-chat-id-rpc [chat-id]
{::json-rpc/call [{:method "wakuext_deleteMessagesByChatID"
:params [chat-id]
(defn delete-messages-by-chat-id-rpc
[chat-id]
{::json-rpc/call [{:method "wakuext_deleteMessagesByChatID"
:params [chat-id]
:on-success #(log/debug "successfully deleted messages by chat-id" chat-id)
:on-error #(log/error "failed to delete messages by chat-id" % chat-id)}]})
:on-error #(log/error "failed to delete messages by chat-id" % chat-id)}]})
(fx/defn delete-message [cofx id]
(rf/defn delete-message
[cofx id]
(delete-message-rpc id))
(fx/defn delete-messages-from [cofx author]
(rf/defn delete-messages-from
[cofx author]
(delete-messages-from-rpc author))
(fx/defn mark-messages-seen [cofx chat-id ids on-success]
(rf/defn mark-messages-seen
[cofx chat-id ids on-success]
(mark-seen-rpc chat-id ids on-success))
(fx/defn delete-messages-by-chat-id [cofx chat-id]
(rf/defn delete-messages-by-chat-id
[cofx chat-id]
(delete-messages-by-chat-id-rpc chat-id))
+19 -14
View File
@@ -1,31 +1,36 @@
(ns status-im.data-store.pin-messages
(:require [clojure.set :as clojure.set]
[status-im.data-store.messages :as messages]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]
[status-im.data-store.messages :as messages]))
[utils.re-frame :as rf]))
(defn <-rpc [message]
(defn <-rpc
[message]
(-> message
(merge (messages/<-rpc (message :message)))
(clojure.set/rename-keys {:pinnedAt :pinned-at
:pinnedBy :pinned-by})
(dissoc :message)))
(defn pinned-message-by-chat-id-rpc [chat-id
cursor
limit
on-success
on-error]
(defn pinned-message-by-chat-id-rpc
[chat-id
cursor
limit
on-success
on-error]
{::json-rpc/call [{:method "wakuext_chatPinnedMessages"
:params [chat-id cursor limit]
:on-success (fn [result]
(let [result (clojure.set/rename-keys result {:pinnedMessages :pinned-messages})]
(let [result (clojure.set/rename-keys result
{:pinnedMessages
:pinned-messages})]
(on-success (update result :pinned-messages #(map <-rpc %)))))
:on-error on-error}]})
:on-error on-error}]})
(fx/defn send-pin-message [cofx pin-message]
{::json-rpc/call [{:method "wakuext_sendPinMessage"
:params [(messages/->rpc pin-message)]
(rf/defn send-pin-message
[cofx pin-message]
{::json-rpc/call [{:method "wakuext_sendPinMessage"
:params [(messages/->rpc pin-message)]
:on-success #(log/debug "successfully pinned message" pin-message)
:on-error #(log/error "failed to pin message" % pin-message)}]})
:on-error #(log/error "failed to pin message" % pin-message)}]})
@@ -2,23 +2,28 @@
(:require [clojure.set :as clojure.set]
[re-frame.core :as re-frame]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn <-rpc [visibility-status-update]
(clojure.set/rename-keys visibility-status-update {:publicKey :public-key
:statusType :status-type}))
(defn <-rpc-settings [settings]
(defn <-rpc
[visibility-status-update]
(clojure.set/rename-keys visibility-status-update
{:publicKey :public-key
:statusType :status-type}))
(defn <-rpc-settings
[settings]
(-> settings
(clojure.set/rename-keys
{:current-user-status :current-user-visibility-status})
(update :current-user-visibility-status <-rpc)))
(fx/defn fetch-visibility-status-updates-rpc [_]
(rf/defn fetch-visibility-status-updates-rpc
[_]
{::json-rpc/call [{:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates" %)}]})
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)}]})
+104 -74
View File
@@ -2,18 +2,19 @@
(:refer-clojure :exclude [name])
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im2.navigation.events :as navigation]
[status-im.utils.datetime :as datetime]
[status-im.utils.fx :as fx]
[status-im.utils.random :as random]
[status-im.bottom-sheet.core :as bottom-sheet]))
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(defn fullname [custom-domain? username]
(defn fullname
[custom-domain? username]
(if custom-domain?
username
(stateofus/subdomain username)))
@@ -38,14 +39,16 @@
(fn [[chain-id name cb]]
(ens/expire-at chain-id name cb)))
(fx/defn update-ens-tx-state
(rf/defn update-ens-tx-state
{:events [:update-ens-tx-state]}
[{:keys [db]} new-state username custom-domain? tx-hash]
{:db (assoc-in db [:ens/registrations tx-hash] {:state new-state
:username username
:custom-domain? custom-domain?})})
{:db (assoc-in db
[:ens/registrations tx-hash]
{:state new-state
:username username
:custom-domain? custom-domain?})})
(fx/defn redirect-to-ens-summary
(rf/defn redirect-to-ens-summary
{:events [::redirect-to-ens-summary]}
[cofx]
;; we reset navigation so that navigate back doesn't return
@@ -55,19 +58,19 @@
[:my-profile
:ens-confirmation]))
(fx/defn update-ens-tx-state-and-redirect
(rf/defn update-ens-tx-state-and-redirect
{:events [:update-ens-tx-state-and-redirect]}
[cofx new-state username custom-domain? tx-hash]
(fx/merge cofx
(rf/merge cofx
(update-ens-tx-state new-state username custom-domain? tx-hash)
(redirect-to-ens-summary)))
(fx/defn clear-ens-registration
(rf/defn clear-ens-registration
{:events [:clear-ens-registration]}
[{:keys [db]} tx-hash]
{:db (update db :ens/registrations dissoc tx-hash)})
(fx/defn set-state
(rf/defn set-state
{:events [::name-resolved]}
[{:keys [db]} username state address]
(when (= username
@@ -76,37 +79,43 @@
(assoc-in [:ens/registration :state] state)
(assoc-in [:ens/registration :address] address))}))
(fx/defn save-username
(rf/defn save-username
{:events [::save-username]}
[{:keys [db] :as cofx} custom-domain? username redirectToSummary]
(let [name (fullname custom-domain? username)
names (get-in db [:multiaccount :usernames] [])
(let [name (fullname custom-domain? username)
names (get-in db [:multiaccount :usernames] [])
new-names (conj names name)]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:usernames new-names
:usernames
new-names
(when redirectToSummary
{:on-success #(re-frame/dispatch [::redirect-to-ens-summary])}))
(when (empty? names)
(multiaccounts.update/multiaccount-update
:preferred-name name {})))))
:preferred-name
name
{})))))
(fx/defn set-pub-key
(rf/defn set-pub-key
{:events [::set-pub-key]}
[{:keys [db]}]
(let [{:keys [username address custom-domain?]} (:ens/registration db)
address (or address (ethereum/default-address db))
{:keys [public-key]} (:multiaccount db)
chain-id (ethereum/chain-id db)
username (fullname custom-domain? username)]
address (or address (ethereum/default-address db))
{:keys [public-key]} (:multiaccount db)
chain-id (ethereum/chain-id db)
username (fullname custom-domain? username)]
(ens/set-pub-key-prepare-tx
chain-id address username public-key
chain-id
address
username
public-key
#(re-frame/dispatch [:signing.ui/sign
{:tx-obj %
:on-result [::save-username custom-domain? username true]
:on-error [::on-registration-failure]}]))))
(fx/defn on-input-submitted
(rf/defn on-input-submitted
{:events [::input-submitted]}
[{:keys [db] :as cofx}]
(let [{:keys [state username custom-domain?]} (:ens/registration db)]
@@ -135,14 +144,16 @@
(ens/pubkey
chain-id
(fullname custom-domain? username)
#(re-frame/dispatch [::name-resolved username
(cond
(not public-key) :owned
(and (string/ends-with? % "0000000000000000000000000000000000000000000000000000000000000000") (not custom-domain?))
:invalid-ens
(= % public-key) :connected
:else :connected-with-different-key)
(eip55/address->checksum response)]))
#(re-frame/dispatch
[::name-resolved username
(cond
(not public-key) :owned
(and (string/ends-with? % "0000000000000000000000000000000000000000000000000000000000000000")
(not custom-domain?))
:invalid-ens
(= % public-key) :connected
:else :connected-with-different-key)
(eip55/address->checksum response)]))
:else
(re-frame/dispatch [::name-resolved username :taken]))))
@@ -153,33 +164,40 @@
5 10
1 10))
(fx/defn register-name
(rf/defn register-name
{:events [::register-name-pressed]}
[{:keys [db]} address]
(let [{:keys [username]}
(:ens/registration db)
{:keys [public-key]} (:multiaccount db)
chain-id (ethereum/chain-id db)]
chain-id (ethereum/chain-id db)]
(ens/register-prepare-tx
chain-id address username public-key
chain-id
address
username
public-key
#(re-frame/dispatch [:signing.ui/sign
{:tx-obj %
:on-result [:update-ens-tx-state-and-redirect :submitted username false]
:on-error [::on-registration-failure]}]))))
(defn- valid-custom-domain? [username]
(defn- valid-custom-domain?
[username]
(and (ens/is-valid-eth-name? username)
(stateofus/lower-case? username)))
(defn- valid-username? [custom-domain? username]
(defn- valid-username?
[custom-domain? username]
(if custom-domain?
(valid-custom-domain? username)
(stateofus/valid-username? username)))
(defn- state [custom-domain? username usernames]
(defn- state
[custom-domain? username usernames]
(cond
(or (string/blank? username)
(> 4 (count username))) :too-short
(> 4 (count username)))
:too-short
(valid-username? custom-domain? username)
(if (usernames (fullname custom-domain? username))
:already-added
@@ -189,79 +207,88 @@
;;NOTE we want to handle only last resolve
(def resolve-last-id (atom nil))
(fx/defn set-username-candidate
(rf/defn set-username-candidate
{:events [::set-username-candidate]}
[{:keys [db]} username]
(let [{:keys [custom-domain?]} (:ens/registration db)
usernames (into #{} (get-in db [:multiaccount :usernames]))
state (state custom-domain? username usernames)]
usernames (into #{} (get-in db [:multiaccount :usernames]))
state (state custom-domain? username usernames)]
(reset! resolve-last-id (random/id))
(merge
{:db (update db :ens/registration assoc
:username username
:state state)}
{:db (update db
:ens/registration assoc
:username username
:state state)}
(when (= state :searching)
(let [{:keys [multiaccount]} db
{:keys [public-key]} multiaccount
addresses (ethereum/addresses-without-watch db)
chain-id (ethereum/chain-id db)]
{:keys [public-key]} multiaccount
addresses (ethereum/addresses-without-watch db)
chain-id (ethereum/chain-id db)]
{::resolve-owner [chain-id
(fullname custom-domain? username)
#(on-resolve-owner
chain-id custom-domain? username addresses public-key %
resolve-last-id @resolve-last-id)]})))))
chain-id
custom-domain?
username
addresses
public-key
%
resolve-last-id
@resolve-last-id)]})))))
(fx/defn return-to-ens-main-screen
(rf/defn return-to-ens-main-screen
{:events [::got-it-pressed ::cancel-pressed]}
[{:keys [db] :as cofx} _]
(fx/merge cofx
(rf/merge cofx
;; clear registration data
{:db (dissoc db :ens/registration)}
;; we reset navigation so that navigate back doesn't return
;; into the registration flow
(navigation/set-stack-root :profile-stack [:my-profile
:ens-main])))
(navigation/set-stack-root :profile-stack
[:my-profile
:ens-main])))
(fx/defn switch-domain-type
(rf/defn switch-domain-type
{:events [::switch-domain-type]}
[{:keys [db] :as cofx} _]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(update :ens/registration dissoc :username :state)
(update-in [:ens/registration :custom-domain?] not))}))
(fx/defn change-address
(rf/defn change-address
{:events [::change-address]}
[{:keys [db] :as cofx} _ {:keys [address]}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:ens/registration :address] address)}
(bottom-sheet/hide-bottom-sheet)))
(fx/defn save-preferred-name
(rf/defn save-preferred-name
{:events [::save-preferred-name]}
[cofx name]
(multiaccounts.update/multiaccount-update cofx
:preferred-name name
:preferred-name
name
{}))
(fx/defn on-registration-failure
(rf/defn on-registration-failure
"TODO not sure there is actually anything to do here
it should only be called if the user cancels the signing
Actual registration failure has not been implemented properly"
{:events [::on-registration-failure]}
[_ _])
(fx/defn store-name-address
(rf/defn store-name-address
{:events [::address-resolved]}
[{:keys [db]} username address]
{:db (assoc-in db [:ens/names username :address] address)})
(fx/defn store-name-public-key
(rf/defn store-name-public-key
{:events [::public-key-resolved]}
[{:keys [db]} username public-key]
{:db (assoc-in db [:ens/names username :public-key] public-key)})
(fx/defn store-expiration-date
(rf/defn store-expiration-date
{:events [::get-expiration-time-success]}
[{:keys [now db]} username timestamp]
{:db (-> db
@@ -269,11 +296,11 @@
(datetime/timestamp->year-month-day-date timestamp))
(assoc-in [:ens/names username :releasable?] (<= timestamp now)))})
(fx/defn navigate-to-name
(rf/defn navigate-to-name
{:events [::navigate-to-name]}
[{:keys [db] :as cofx} username]
(let [chain-id (ethereum/chain-id db)]
(fx/merge cofx
(rf/merge cofx
{::get-expiration-time
[chain-id
(stateofus/username username)
@@ -286,24 +313,27 @@
#(re-frame/dispatch [::public-key-resolved username %])]}
(navigation/navigate-to-cofx :ens-name-details username))))
(fx/defn start-registration
(rf/defn start-registration
{:events [::add-username-pressed ::get-started-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
(set-username-candidate (get-in db [:ens/registration :username] ""))
(navigation/navigate-to-cofx :ens-search {})))
(fx/defn remove-username
(rf/defn remove-username
{:events [::remove-username]}
[{:keys [db] :as cofx} name]
(let [names (get-in db [:multiaccount :usernames] [])
preferred-name (get-in db [:multiaccount :preferred-name])
new-names (remove #(= name %) names)]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:usernames new-names
:usernames
new-names
{})
(when (= name preferred-name)
(multiaccounts.update/multiaccount-update
:preferred-name (first new-names) {}))
:preferred-name
(first new-names)
{}))
(navigation/navigate-back))))
+3
View File
@@ -6,6 +6,9 @@
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
;; NOTE(19/12/22 yqrashawn) this namespace has been moved to the
;; status-im2.common.json-rpc.events namespace,
;; we keep this only for old (status 1.0) code, can be removed with old code later
(defn on-error-retry
[call-method {:keys [method number-of-retries delay on-error] :as arg}]
(if (pos? number-of-retries)
+32 -30
View File
@@ -1,22 +1,23 @@
(ns status-im.ethereum.subscriptions
(:require [status-im.ethereum.eip55 :as eip55]
[status-im.wallet.db :as wallet]
[status-im.wallet.core :as wallet.core]
[status-im.ethereum.transactions.core :as transactions]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[status-im.wallet.core :as wallet.core]
[status-im.wallet.db :as wallet]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn new-transfers
(rf/defn new-transfers
[cofx block-number accounts]
(log/debug "[wallet-subs] new-transfers"
"accounts" accounts
"block" block-number)
"block" block-number)
(transactions/check-watched-transactions cofx))
(fx/defn recent-history-fetching-started
(rf/defn recent-history-fetching-started
[{:keys [db]} accounts]
(log/debug "[wallet-subs] recent-history-fetching-started"
"accounts" accounts)
"accounts"
accounts)
(let [event (get db :wallet/on-recent-history-fetching)]
(cond-> {:db (-> db
(transactions/update-fetching-status accounts :recent? true)
@@ -25,20 +26,21 @@
event
(assoc :dispatch event))))
(fx/defn recent-history-fetching-ended
(rf/defn recent-history-fetching-ended
[{:keys [db]} {:keys [accounts blockNumber]}]
(log/debug "[wallet-subs] recent-history-fetching-ended"
"accounts" accounts
"block" blockNumber)
{:db (-> db
(assoc :ethereum/current-block blockNumber)
(update-in [:wallet :accounts]
wallet/remove-transactions-since-block blockNumber)
(transactions/update-fetching-status accounts :recent? false)
(dissoc :wallet/waiting-for-recent-history?
:wallet/refreshing-history?
:wallet/fetching-error
:wallet/recent-history-fetching-started?))
"block" blockNumber)
{:db (-> db
(assoc :ethereum/current-block blockNumber)
(update-in [:wallet :accounts]
wallet/remove-transactions-since-block
blockNumber)
(transactions/update-fetching-status accounts :recent? false)
(dissoc :wallet/waiting-for-recent-history?
:wallet/refreshing-history?
:wallet/fetching-error
:wallet/recent-history-fetching-started?))
:transactions/get-transfers
{:chain-tokens (:wallet/all-tokens db)
:addresses (reduce
@@ -53,27 +55,27 @@
:before-block blockNumber
:limit 20}})
(fx/defn fetching-error
(rf/defn fetching-error
[{:keys [db] :as cofx} {:keys [message]}]
(fx/merge
(rf/merge
cofx
{:db (assoc db :wallet/fetching-error message)}
{:db (assoc db :wallet/fetching-error message)}
(wallet.core/after-checking-history)))
(fx/defn non-archival-node-detected
(rf/defn non-archival-node-detected
[{:keys [db]} _]
{:db (assoc db :wallet/non-archival-node true)})
(fx/defn new-wallet-event
(rf/defn new-wallet-event
[cofx {:keys [type blockNumber accounts] :as event}]
(log/info "[wallet-subs] new-wallet-event"
"event-type" type
"event-type" type
"blockNumber" blockNumber
"accounts" accounts)
"accounts" accounts)
(case type
"new-transfers" (new-transfers cofx blockNumber accounts)
"recent-history-fetching" (recent-history-fetching-started cofx accounts)
"recent-history-ready" (recent-history-fetching-ended cofx event)
"fetching-history-error" (fetching-error cofx event)
"new-transfers" (new-transfers cofx blockNumber accounts)
"recent-history-fetching" (recent-history-fetching-started cofx accounts)
"recent-history-ready" (recent-history-fetching-ended cofx event)
"fetching-history-error" (fetching-error cofx event)
"non-archival-node-detected" (non-archival-node-detected cofx event)
(log/warn ::unknown-wallet-event :type type :event event)))
+118 -98
View File
@@ -7,10 +7,10 @@
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.encode :as encode]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[status-im.utils.mobile-sync :as utils.mobile-sync]
[status-im.wallet.core :as wallet]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(def confirmations-count-threshold 12)
@@ -23,8 +23,9 @@
(def network->subdomain {5 "goerli"})
(defn get-transaction-details-url [chain-id hash]
{:pre [(number? chain-id) (string? hash)]
(defn get-transaction-details-url
[chain-id hash]
{:pre [(number? chain-id) (string? hash)]
:post [(or (nil? %) (string? %))]}
(cond
(etherscan-supported? chain-id)
@@ -51,15 +52,16 @@
(defn- parse-token-transfer
[chain-tokens contract]
(let [{:keys [symbol] :as token} (get chain-tokens contract
(let [{:keys [symbol] :as token} (get chain-tokens
contract
default-erc20-token)]
{:symbol symbol
:token token
{:symbol symbol
:token token
;; NOTE(goranjovic) - just a flag we need when we merge this entry
;; with the existing entry in the app, e.g. transaction info with
;; gas details, or a previous transfer entry with old confirmations
;; count.
:transfer true}))
:transfer true}))
(defn enrich-transfer
[chain-tokens
@@ -105,7 +107,7 @@
(def default-transfers-limit 20)
(fx/defn watch-transaction
(rf/defn watch-transaction
"Set a watch for the given transaction
`watch-params` needs to contain a `trigger-fn` and `on-trigger` functions
`trigger-fn` is a function that returns true if the watch has been triggered
@@ -114,10 +116,11 @@
[{:keys [db]} transaction-id {:keys [trigger-fn on-trigger] :as watch-params}]
(when (and (fn? trigger-fn)
(fn? on-trigger))
{:db (assoc-in db [:ethereum/watched-transactions transaction-id]
watch-params)}))
{:db (assoc-in db
[:ethereum/watched-transactions transaction-id]
watch-params)}))
(fx/defn check-transaction
(rf/defn check-transaction
"Check if the transaction has been triggered and applies the effects returned
by `on-trigger` if that is the case"
[{:keys [db] :as cofx} {:keys [hash] :as transaction}]
@@ -125,12 +128,14 @@
(get-in db [:ethereum/watched-transactions hash])]
(let [{:keys [trigger-fn on-trigger]} watch-params]
(when (trigger-fn db transaction)
(fx/merge cofx
{:db (update db :ethereum/watched-transactions
dissoc hash)}
(rf/merge cofx
{:db (update db
:ethereum/watched-transactions
dissoc
hash)}
(on-trigger transaction))))))
(fx/defn check-watched-transactions
(rf/defn check-watched-transactions
[{:keys [db] :as cofx}]
(let [watched-transactions
(reduce-kv (fn [acc _ {:keys [transactions]}]
@@ -139,13 +144,13 @@
(keys (get db :ethereum/watched-transactions)))))
{}
(get-in db [:wallet :accounts]))]
(apply fx/merge
(apply rf/merge
cofx
(map (fn [[_ transaction]]
(check-transaction transaction))
watched-transactions))))
(fx/defn add-transfer
(rf/defn add-transfer
"We determine a unique id for the transfer before adding it because some
transaction can contain multiple transfers and they would overwrite each other
in the transfer map if identified by hash"
@@ -157,25 +162,30 @@
(:type transfer-by-hash))))
id
hash))]
(fx/merge cofx
{:db (assoc-in db [:wallet :accounts address :transactions unique-id]
(assoc transfer :hash unique-id))}
(rf/merge cofx
{:db (assoc-in db
[:wallet :accounts address :transactions unique-id]
(assoc transfer :hash unique-id))}
(check-transaction transfer)))))
(defn get-min-known-block [db address]
(defn get-min-known-block
[db address]
(get-in db [:wallet :accounts (eip55/address->checksum address) :min-block]))
(defn get-max-block-with-transfers [db address]
(defn get-max-block-with-transfers
[db address]
(get-in db [:wallet :accounts (eip55/address->checksum address) :max-block]))
(defn min-block-transfers-count [db address]
(get-in db [:wallet :accounts
(eip55/address->checksum address)
:min-block-transfers-count]))
(defn min-block-transfers-count
[db address]
(get-in db
[:wallet :accounts
(eip55/address->checksum address)
:min-block-transfers-count]))
(fx/defn set-lowest-fetched-block
(rf/defn set-lowest-fetched-block
[{:keys [db]} address transfers]
(let [checksum (eip55/address->checksum address)
(let [checksum (eip55/address->checksum address)
{:keys [min-block min-block-transfers-count]}
(reduce
(fn [{:keys [min-block] :as acc}
@@ -198,43 +208,47 @@
(min-block-transfers-count db address)}
transfers)]
(log/debug "[transactions] set-lowest-fetched-block"
"address" address
"min-block" min-block
"address" address
"min-block" min-block
"min-block-transfers-count" min-block-transfers-count)
{:db (update-in db [:wallet :accounts checksum] assoc
:min-block min-block
{:db (update-in db
[:wallet :accounts checksum]
assoc
:min-block min-block
:min-block-transfers-count min-block-transfers-count)}))
(defn update-fetching-status
[db addresses fetching-type state]
(update-in
db [:wallet :fetching]
db
[:wallet :fetching]
(fn [accounts]
(reduce
(fn [accounts address]
(assoc-in accounts
[(eip55/address->checksum address) fetching-type]
state))
[(eip55/address->checksum address) fetching-type]
state))
accounts
addresses))))
(fx/defn tx-fetching-in-progress
(rf/defn tx-fetching-in-progress
[{:keys [db]} addresses]
{:db (update-fetching-status db addresses :history? true)})
(fx/defn tx-fetching-ended
(rf/defn tx-fetching-ended
[{:keys [db]} addresses]
{:db (update-fetching-status db addresses :history? false)})
(fx/defn tx-history-end-reached
(rf/defn tx-history-end-reached
[{:keys [db] :as cofx} address]
(let [syncing-allowed? (utils.mobile-sync/syncing-allowed? cofx)]
{:db (assoc-in db [:wallet :fetching address :all-fetched?]
(if syncing-allowed?
:all
:all-preloaded))}))
{:db (assoc-in db
[:wallet :fetching address :all-fetched?]
(if syncing-allowed?
:all
:all-preloaded))}))
(fx/defn delete-pending-transactions
(rf/defn delete-pending-transactions
[{:keys [db]} address transactions]
(let [all-transactions
(get-in db [:wallet :accounts (eip55/address->checksum address) :transactions])
@@ -247,38 +261,38 @@
transactions)]
{:wallet/delete-pending-transactions pending-tx-hashes}))
(fx/defn handle-new-transfer
(rf/defn handle-new-transfer
[{:keys [db] :as cofx} transfers {:keys [address limit]}]
(log/debug "[transfers] new-transfers"
"address" address
"count" (count transfers)
"limit" limit)
(let [checksum (eip55/address->checksum address)
"count" (count transfers)
"limit" limit)
(let [checksum (eip55/address->checksum address)
max-known-block (get-max-block-with-transfers db address)
effects (cond-> [(when (seq transfers)
(set-lowest-fetched-block checksum transfers))
(wallet/set-max-block-with-transfers checksum transfers)]
effects (cond-> [(when (seq transfers)
(set-lowest-fetched-block checksum transfers))
(wallet/set-max-block-with-transfers checksum transfers)]
(seq transfers)
(concat
[(delete-pending-transactions address transfers)]
(mapv add-transfer transfers))
(seq transfers)
(concat
[(delete-pending-transactions address transfers)]
(mapv add-transfer transfers))
(and max-known-block
(some #(> (:block %) max-known-block) transfers))
(conj (wallet/update-balances
[address]
(zero? max-known-block)))
(and max-known-block
(some #(> (:block %) max-known-block) transfers))
(conj (wallet/update-balances
[address]
(zero? max-known-block)))
(and (zero? max-known-block)
(empty? transfers))
(conj (wallet/set-zero-balances {:address address}))
(and (zero? max-known-block)
(empty? transfers))
(conj (wallet/set-zero-balances {:address address}))
(< (count transfers) limit)
(conj (tx-history-end-reached checksum)))]
(apply fx/merge cofx (tx-fetching-ended [checksum]) effects)))
(< (count transfers) limit)
(conj (tx-history-end-reached checksum)))]
(apply rf/merge cofx (tx-fetching-ended [checksum]) effects)))
(fx/defn check-ens-transactions
(rf/defn check-ens-transactions
[{:keys [db] :as cofx} transfers]
(let [set-of-transactions-hash (reduce (fn [acc {:keys [hash]}] (conj acc hash)) #{} transfers)
registrations (filter
@@ -288,12 +302,15 @@
(contains? set-of-transactions-hash hash)))
(get db :ens/registrations))
fxs (map (fn [[hash {:keys [username custom-domain?]}]]
(let [transfer (first (filter (fn [transfer] (let [transfer-hash (get transfer :hash)] (= transfer-hash hash))) transfers))
type (get transfer :type)
(let [transfer (first (filter (fn [transfer]
(let [transfer-hash (get transfer :hash)]
(= transfer-hash hash)))
transfers))
type (get transfer :type)
transaction-success (get transfer :transfer)]
(cond
(= transaction-success true)
(fx/merge cofx
(rf/merge cofx
(ens/clear-ens-registration hash)
(ens/save-username custom-domain? username false))
(= type :failed)
@@ -301,69 +318,72 @@
:else
nil)))
registrations)]
(apply fx/merge cofx fxs)))
(apply rf/merge cofx fxs)))
(fx/defn new-transfers
(rf/defn new-transfers
{:events [::new-transfers]}
[cofx transfers params]
(fx/merge cofx
(rf/merge cofx
(handle-new-transfer transfers params)
(wallet/stop-fetching-on-empty-tx-history transfers)
(check-ens-transactions transfers)))
(fx/defn tx-fetching-failed
(rf/defn tx-fetching-failed
{:events [::tx-fetching-failed]}
[cofx error address]
(log/debug "[transactions] tx-fetching-failed"
"address" address
"error" error)
"error" error)
(tx-fetching-ended cofx [address]))
(re-frame/reg-fx
:transactions/get-transfers
(fn [{:keys [chain-tokens addresses before-block limit
limit-per-address fetch-more?]
:as params
:or {limit default-transfers-limit
(fn
[{:keys [chain-tokens addresses before-block limit
limit-per-address fetch-more?]
:as params
:or {limit default-transfers-limit
fetch-more? true}}]
{:pre [(spec/valid?
(spec/coll-of string?)
addresses)]}
(log/debug "[transactions] get-transfers"
"addresses" addresses
"block" before-block
"limit" limit
"addresses" addresses
"block" before-block
"limit" limit
"limit-per-address" limit-per-address
"fetch-more?" fetch-more?)
"fetch-more?" fetch-more?)
(doseq [address addresses]
(let [limit (or (get limit-per-address address)
limit)]
(json-rpc/call
{:method "wallet_getTransfersByAddress"
:params [address (encode/uint before-block) (encode/uint limit) fetch-more?]
{:method "wallet_getTransfersByAddress"
:params [address (encode/uint before-block) (encode/uint limit) fetch-more?]
:on-success #(re-frame/dispatch
[::new-transfers
(enrich-transfers chain-tokens %)
(assoc params :address address
:limit limit)])
:on-error #(re-frame/dispatch [::tx-fetching-failed address])})))))
(assoc params
:address address
:limit limit)])
:on-error #(re-frame/dispatch [::tx-fetching-failed address])})))))
(defn some-transactions-loaded? [db address]
(defn some-transactions-loaded?
[db address]
(not-empty (get-in db [:wallet :accounts address :transactions])))
(fx/defn fetch-more-tx
(rf/defn fetch-more-tx
{:events [:transactions/fetch-more]}
[{:keys [db] :as cofx} address]
(let [min-known-block (or (get-min-known-block db address)
(:ethereum/current-block db))
(let [min-known-block (or (get-min-known-block db address)
(:ethereum/current-block db))
min-block-transfers-count (or (min-block-transfers-count db address) 0)]
(fx/merge
(rf/merge
cofx
{:transactions/get-transfers
{:chain-tokens (:wallet/all-tokens db)
:addresses [address]
:before-block min-known-block
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
{:chain-tokens (:wallet/all-tokens db)
:addresses [address]
:before-block min-known-block
:fetch-more? (utils.mobile-sync/syncing-allowed? cofx)
;; Transfers are requested before and including `min-known-block` because
;; there is no guarantee that all transfers from that block are shown
;; already. To make sure that we fetch the whole `default-transfers-limit`
@@ -373,7 +393,7 @@
min-block-transfers-count)}}}
(tx-fetching-in-progress [address]))))
(fx/defn get-fetched-transfers
(rf/defn get-fetched-transfers
{:events [:transaction/get-fetched-transfers]}
[{:keys [db]}]
{:transactions/get-transfers
+137 -122
View File
@@ -1,64 +1,65 @@
(ns status-im.events
(:require clojure.set
[re-frame.core :as re-frame]
status-im.add-new.core
[status-im.async-storage.core :as async-storage]
status-im.backup.core
status-im.bootnodes.core
status-im.browser.core
status-im.browser.permissions
[status-im.chat.models :as chat]
status-im.chat.models.images
status-im.chat.models.input
status-im.chat.models.loading
status-im.chat.models.transport
[status-im.constants :as constants]
status-im.contact.block
status-im.contact.chat
status-im.contact.core
status-im.currency.core
[status-im.ethereum.json-rpc :as json-rpc]
status-im.ethereum.subscriptions
status-im.fleet.core
status-im.http.core
[status-im.i18n.i18n :as i18n]
[status-im.keycard.core :as keycard]
status-im.log-level.core
status-im.mailserver.constants
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.biometric.core :as biometric]
status-im.multiaccounts.login.core
status-im.multiaccounts.logout.core
status-im.multiaccounts.update.core
[status-im.native-module.core :as status]
[status-im2.navigation.events :as navigation]
status-im.activity-center.core
status-im.pairing.core
status-im.profile.core
status-im.search.core
status-im.signals.core
status-im.stickers.core
status-im.transport.core
[status-im.ui.components.permissions :as permissions]
[status-im.ui.components.react :as react]
status-im.ui.screens.privacy-and-security-settings.events
[status-im.utils.dimensions :as dimensions]
[status-im.utils.fx :as fx]
status-im.utils.logging.core
[status-im.utils.universal-links.core :as universal-links]
[status-im.utils.utils :as utils]
status-im.visibility-status-updates.core
status-im.waku.core
status-im.wallet.accounts.core
status-im.wallet.choose-recipient.core
[status-im.wallet.core :as wallet]
status-im.wallet.custom-tokens.core
status-im.wallet-connect.core
status-im.wallet-connect-legacy.core
status-im.network.net-info
status-im.visibility-status-popover.core
status-im2.contexts.shell.events
[status-im.multiaccounts.model :as multiaccounts.model]))
(:require
clojure.set
[re-frame.core :as re-frame]
status-im.add-new.core
[status-im.async-storage.core :as async-storage]
status-im.backup.core
status-im.bootnodes.core
status-im.browser.core
status-im.browser.permissions
[status-im.chat.models :as chat]
status-im.chat.models.images
status-im.chat.models.input
status-im.chat.models.loading
status-im.chat.models.transport
[status-im.constants :as constants]
status-im.contact.block
status-im.contact.chat
status-im.contact.core
status-im.currency.core
[status-im.ethereum.json-rpc :as json-rpc]
status-im.ethereum.subscriptions
status-im.fleet.core
status-im.http.core
[status-im.i18n.i18n :as i18n]
[status-im.keycard.core :as keycard]
status-im.log-level.core
status-im.mailserver.constants
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.biometric.core :as biometric]
status-im.multiaccounts.login.core
status-im.multiaccounts.logout.core
[status-im.multiaccounts.model :as multiaccounts.model]
status-im.multiaccounts.update.core
[status-im.native-module.core :as status]
status-im.network.net-info
status-im.pairing.core
status-im.profile.core
status-im.search.core
status-im.signals.core
status-im.stickers.core
status-im.transport.core
[status-im.ui.components.permissions :as permissions]
[status-im.ui.components.react :as react]
status-im.ui.screens.privacy-and-security-settings.events
[status-im.utils.dimensions :as dimensions]
status-im.utils.logging.core
[status-im.utils.universal-links.core :as universal-links]
[status-im.utils.utils :as utils]
status-im.visibility-status-popover.core
status-im.visibility-status-updates.core
status-im.waku.core
status-im.wallet-connect-legacy.core
status-im.wallet-connect.core
status-im.wallet.accounts.core
status-im.wallet.choose-recipient.core
[status-im.wallet.core :as wallet]
status-im.wallet.custom-tokens.core
status-im2.contexts.activity-center.events
status-im2.contexts.shell.events
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(re-frame/reg-fx
:dismiss-keyboard
@@ -95,53 +96,58 @@
(fn []
(dimensions/add-event-listener)))
(fx/defn dismiss-keyboard
(rf/defn dismiss-keyboard
{:events [:dismiss-keyboard]}
[_]
{:dismiss-keyboard nil})
(fx/defn identicon-generated
(rf/defn identicon-generated
{:events [:identicon-generated]}
[{:keys [db]} path identicon]
{:db (assoc-in db path identicon)})
(fx/defn gfycat-generated
(rf/defn gfycat-generated
{:events [:gfycat-generated]}
[{:keys [db]} path gfycat]
{:db (assoc-in db path gfycat)})
(fx/defn system-theme-mode-changed
(rf/defn system-theme-mode-changed
{:events [:system-theme-mode-changed]}
[cofx _]
(when (multiaccounts.model/logged-in? cofx)
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])
:dispatch [:reload-new-ui]}))
:dispatch [:reload-new-ui]}))
(def authentication-options
{:reason (i18n/label :t/biometric-auth-reason-login)})
(defn- on-biometric-auth-result [{:keys [bioauth-success bioauth-code bioauth-message]}]
(defn- on-biometric-auth-result
[{:keys [bioauth-success bioauth-code bioauth-message]}]
(when-not bioauth-success
(if (= bioauth-code "USER_FALLBACK")
(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])
(utils/show-confirmation {:title (i18n/label :t/biometric-auth-confirm-title)
:content (or bioauth-message (i18n/label :t/biometric-auth-confirm-message))
:confirm-button-text (i18n/label :t/biometric-auth-confirm-try-again)
:cancel-button-text (i18n/label :t/biometric-auth-confirm-logout)
:on-accept #(biometric/authenticate nil on-biometric-auth-result authentication-options)
:on-cancel #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])}))))
(utils/show-confirmation
{:title (i18n/label :t/biometric-auth-confirm-title)
:content (or bioauth-message (i18n/label :t/biometric-auth-confirm-message))
:confirm-button-text (i18n/label :t/biometric-auth-confirm-try-again)
:cancel-button-text (i18n/label :t/biometric-auth-confirm-logout)
:on-accept #(biometric/authenticate nil
on-biometric-auth-result
authentication-options)
:on-cancel #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])}))))
(fx/defn on-return-from-background [{:keys [db now] :as cofx}]
(rf/defn on-return-from-background
[{:keys [db now] :as cofx}]
(let [app-in-background-since (get db :app-in-background-since)
signed-up? (get-in db [:multiaccount :signed-up?])
biometric-auth? (= (:auth-method db) "biometric")
requires-bio-auth (and
signed-up?
biometric-auth?
(some? app-in-background-since)
(>= (- now app-in-background-since)
constants/ms-in-bg-for-require-bioauth))]
(fx/merge cofx
signed-up? (get-in db [:multiaccount :signed-up?])
biometric-auth? (= (:auth-method db) "biometric")
requires-bio-auth (and
signed-up?
biometric-auth?
(some? app-in-background-since)
(>= (- now app-in-background-since)
constants/ms-in-bg-for-require-bioauth))]
(rf/merge cofx
{:db (dissoc db :app-in-background-since)}
(mailserver/process-next-messages-request)
(wallet/restart-wallet-service-after-background app-in-background-since)
@@ -151,17 +157,17 @@
#(when requires-bio-auth
(biometric/authenticate % on-biometric-auth-result authentication-options)))))
(fx/defn on-going-in-background
(rf/defn on-going-in-background
[{:keys [db now]}]
{:db (assoc db :app-in-background-since now)
:dispatch-n [[:audio-recorder/on-background] [:audio-message/on-background]]})
(fx/defn app-state-change
(rf/defn app-state-change
{:events [:app-state-change]}
[{:keys [db] :as cofx} state]
(let [app-coming-from-background? (= state "active")
app-going-in-background? (= state "background")]
(fx/merge cofx
app-going-in-background? (= state "background")]
(rf/merge cofx
{::app-state-change-fx state
:db (assoc db :app-state state)}
#(when app-coming-from-background?
@@ -169,31 +175,31 @@
#(when app-going-in-background?
(on-going-in-background %)))))
(fx/defn request-permissions
(rf/defn request-permissions
{:events [:request-permissions]}
[_ options]
{:request-permissions-fx options})
(fx/defn update-window-dimensions
(rf/defn update-window-dimensions
{:events [:update-window-dimensions]}
[{:keys [db]} dimensions]
{:db (assoc db :dimensions/window (dimensions/window dimensions))})
(fx/defn init-timeline-chat
(rf/defn init-timeline-chat
{:events [:init-timeline-chat]}
[{:keys [db] :as cofx}]
(when-not (get-in db [:pagination-info constants/timeline-chat-id :messages-initialized?])
(chat/preload-chat-data cofx constants/timeline-chat-id)))
(fx/defn on-will-focus
(rf/defn on-will-focus
{:events [:screens/on-will-focus]}
[{:keys [db] :as cofx} view-id]
(fx/merge cofx
(rf/merge cofx
(cond
(= :chat view-id)
{::async-storage/set! {:chat-id (get-in cofx [:db :current-chat-id])
:key-uid (get-in cofx [:db :multiaccount :key-uid])}
:db (assoc db :screens/was-focused-once? true)}
:db (assoc db :screens/was-focused-once? true)}
(= :login view-id)
{}
@@ -204,47 +210,49 @@
:else
{::async-storage/set! {:chat-id nil
:key-uid nil}
:db (assoc db :screens/was-focused-once? true)})
:db (assoc db :screens/was-focused-once? true)})
#(case view-id
:keycard-settings (keycard/settings-screen-did-load %)
:reset-card (keycard/reset-card-screen-did-load %)
:enter-pin-settings (keycard/enter-pin-screen-did-load %)
:keycard-login-pin (keycard/login-pin-screen-did-load %)
:add-new-account-pin (keycard/enter-pin-screen-did-load %)
:keycard-settings (keycard/settings-screen-did-load %)
:reset-card (keycard/reset-card-screen-did-load %)
:enter-pin-settings (keycard/enter-pin-screen-did-load %)
:keycard-login-pin (keycard/login-pin-screen-did-load %)
:add-new-account-pin (keycard/enter-pin-screen-did-load %)
:keycard-authentication-method (keycard/authentication-method-screen-did-load %)
:multiaccounts (keycard/multiaccounts-screen-did-load %)
:wallet (wallet/wallet-will-focus %)
:multiaccounts (keycard/multiaccounts-screen-did-load %)
:wallet (wallet/wallet-will-focus %)
nil)))
;;TODO :replace by named events
(fx/defn set-event
(rf/defn set-event
{:events [:set]}
[{:keys [db]} k v]
{:db (assoc db k v)})
(fx/defn set-view-id
(rf/defn set-view-id
{:events [:set-view-id]}
[{:keys [db]} view-id]
{:db (assoc db :view-id view-id)})
;;TODO :replace by named events
(fx/defn set-once-event
(rf/defn set-once-event
{:events [:set-once]}
[{:keys [db]} k v]
(when-not (get db k)
{:db (assoc db k v)}))
;;TODO :replace by named events
(fx/defn set-in-event
(rf/defn set-in-event
{:events [:set-in]}
[{:keys [db]} path v]
{:db (assoc-in db path v)})
(defn on-ramp<-rpc [on-ramp]
(clojure.set/rename-keys on-ramp {:logoUrl :logo-url
:siteUrl :site-url}))
(defn on-ramp<-rpc
[on-ramp]
(clojure.set/rename-keys on-ramp
{:logoUrl :logo-url
:siteUrl :site-url}))
(fx/defn crypto-loaded-event
(rf/defn crypto-loaded-event
{:events [::crypto-loaded]}
[{:keys [db]} on-ramps]
{:db (assoc
@@ -252,7 +260,7 @@
:buy-crypto/on-ramps
(map on-ramp<-rpc on-ramps))})
(fx/defn buy-crypto-ui-loaded
(rf/defn buy-crypto-ui-loaded
{:events [:buy-crypto.ui/loaded]}
[_]
{::json-rpc/call [{:method "wallet_getCryptoOnRamps"
@@ -260,10 +268,10 @@
:on-success (fn [on-ramps]
(re-frame/dispatch [::crypto-loaded on-ramps]))}]})
(fx/defn open-buy-crypto-screen
(rf/defn open-buy-crypto-screen
{:events [:buy-crypto.ui/open-screen]}
[cofx]
(fx/merge
(rf/merge
cofx
(navigation/open-modal :buy-crypto nil)
(wallet/keep-watching-history)))
@@ -275,38 +283,45 @@
:global? true/false (close information box across all profiles)}]"
[])
(defn information-box-id-hash [id public-key global?]
(defn information-box-id-hash
[id public-key global?]
(if global?
(hash id)
(hash (str public-key id))))
(fx/defn close-information-box
(rf/defn close-information-box
{:events [:close-information-box]}
[{:keys [db]} id global?]
(let [public-key (get-in db [:multiaccount :public-key])
hash (information-box-id-hash id public-key global?)]
{::async-storage/set! {hash true}
:db (assoc-in db [:information-box-states id] true)}))
:db (assoc-in db [:information-box-states id] true)}))
(fx/defn information-box-states-loaded
(rf/defn information-box-states-loaded
{:events [:information-box-states-loaded]}
[{:keys [db]} hashes states]
{:db (assoc db :information-box-states (reduce
(fn [acc [id hash]]
(assoc acc id (get states hash)))
{} hashes))})
{:db (assoc db
:information-box-states
(reduce
(fn [acc [id hash]]
(assoc acc id (get states hash)))
{}
hashes))})
(fx/defn load-information-box-states
(rf/defn load-information-box-states
{:events [:load-information-box-states]}
[{:keys [db]}]
(let [public-key (get-in db [:multiaccount :public-key])
{:keys [keys hashes]} (reduce (fn [acc {:keys [id global?]}]
(let [hash (information-box-id-hash
id public-key global?)]
id
public-key
global?)]
(-> acc
(assoc-in [:hashes id] hash)
(update :keys #(conj % hash)))))
{} closable-information-boxes)]
{}
closable-information-boxes)]
{::async-storage/get {:keys keys
:cb #(re-frame/dispatch
[:information-box-states-loaded hashes %])}}))
+24 -20
View File
@@ -5,7 +5,7 @@
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.node.core :as node]
[status-im.utils.config :as config]
[status-im.utils.fx :as fx]))
[utils.re-frame :as rf]))
(defn current-fleet-sub
[multiaccount]
@@ -14,10 +14,10 @@
(defn format-mailserver
[mailserver address]
{:id mailserver
:name (name mailserver)
{:id mailserver
:name (name mailserver)
:password constants/mailserver-password
:address address})
:address address})
(defn format-mailservers
[mailservers]
@@ -26,13 +26,14 @@
{}
mailservers))
(defn default-mailservers [db]
(defn default-mailservers
[db]
(reduce (fn [acc [fleet node-by-type]]
(assoc acc fleet (format-mailservers (:mail node-by-type))))
{}
(node/fleets db)))
(fx/defn show-save-confirmation
(rf/defn show-save-confirmation
{:events [:fleet.ui/fleet-selected]}
[_ fleet]
{:ui/show-confirmation
@@ -44,7 +45,8 @@
#(re-frame/dispatch [:fleet.ui/save-fleet-confirmed (keyword fleet)])
:on-cancel nil}})
(defn nodes->fleet [nodes]
(defn nodes->fleet
[nodes]
(letfn [(format-nodes [nodes]
(reduce (fn [acc n]
(assoc acc
@@ -52,28 +54,30 @@
n))
{}
nodes))]
{:boot (format-nodes nodes)
:mail (format-nodes nodes)
{:boot (format-nodes nodes)
:mail (format-nodes nodes)
:whisper (format-nodes nodes)}))
(fx/defn set-nodes [{:keys [db]} fleet nodes]
(rf/defn set-nodes
[{:keys [db]} fleet nodes]
{:db (-> db
(assoc-in [:custom-fleets fleet] (nodes->fleet nodes))
(assoc-in [:mailserver/mailservers fleet] (format-mailservers
(reduce
(fn [acc e]
(assoc acc
(keyword e)
e))
{}
nodes))))})
(assoc-in [:mailserver/mailservers fleet]
(format-mailservers
(reduce
(fn [acc e]
(assoc acc
(keyword e)
e))
{}
nodes))))})
(fx/defn save
(rf/defn save
{:events [:fleet.ui/save-fleet-confirmed]}
[{:keys [db now] :as cofx} fleet]
(let [old-fleet (get-in db [:multiaccount :fleet])]
(when (not= fleet old-fleet)
(fx/merge
(rf/merge
cofx
(multiaccounts.update/multiaccount-update :fleet fleet {})
(node/prepare-new-config
+45 -40
View File
@@ -4,35 +4,36 @@
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.chat.models :as models.chat]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[status-im.activity-center.core :as activity-center]))
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(fx/defn navigate-chat-updated
(rf/defn navigate-chat-updated
{:events [:navigate-chat-updated]}
[cofx chat-id]
(when (get-in cofx [:db :chats chat-id])
(models.chat/navigate-to-chat cofx chat-id)))
(fx/defn handle-chat-removed
(rf/defn handle-chat-removed
{:events [:chat-removed]}
[cofx response]
(fx/merge cofx
(rf/merge cofx
{:db (dissoc (:db cofx) :current-chat-id)
:dispatch-n [[:sanitize-messages-and-process-response response]
[:pop-to-root-tab :chat-stack]]}
(activity-center/notifications-fetch-unread-count)))
(fx/defn handle-chat-update
(rf/defn handle-chat-update
{:events [:chat-updated]}
[_ response do-not-navigate?]
{:dispatch-n [[:sanitize-messages-and-process-response response]
(when-not do-not-navigate? [:navigate-chat-updated (.-id (aget (.-chats response) 0))])]})
(when-not do-not-navigate?
[:navigate-chat-updated (.-id (aget (.-chats response) 0))])]})
(fx/defn remove-member
(rf/defn remove-member
"Format group update message and sign membership"
{:events [:group-chats.ui/remove-member-pressed]}
[_ chat-id member do-not-navigate?]
@@ -41,7 +42,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated % do-not-navigate?])}]})
(fx/defn join-chat
(rf/defn join-chat
{:events [:group-chats.ui/join-pressed]}
[_ chat-id]
{::json-rpc/call [{:method "wakuext_confirmJoiningGroup"
@@ -49,7 +50,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn create
(rf/defn create
{:events [:group-chats.ui/create-pressed]
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
[{:keys [db] :as cofx} group-name]
@@ -59,7 +60,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
(fx/defn create-from-link
(rf/defn create-from-link
[cofx {:keys [chat-id invitation-admin chat-name]}]
(if (get-in cofx [:db :chats chat-id])
{:dispatch [:chat.ui/navigate-to-chat chat-id]}
@@ -68,7 +69,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
(fx/defn make-admin
(rf/defn make-admin
{:events [:group-chats.ui/make-admin-pressed]}
[_ chat-id member]
{::json-rpc/call [{:method "wakuext_addAdminsToGroupChat"
@@ -76,7 +77,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn add-members
(rf/defn add-members
"Add members to a group chat"
{:events [:group-chats.ui/add-members-pressed]}
[{{:keys [current-chat-id selected-participants]} :db :as cofx}]
@@ -85,7 +86,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn add-members-from-invitation
(rf/defn add-members-from-invitation
"Add members to a group chat"
{:events [:group-chats.ui/add-members-from-invitation]}
[{{:keys [current-chat-id] :as db} :db :as cofx} id participant]
@@ -95,7 +96,7 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]})
(fx/defn leave
(rf/defn leave
"Leave chat"
{:events [:group-chats.ui/leave-chat-confirmed]}
[{:keys [db] :as cofx} chat-id]
@@ -104,21 +105,22 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-removed %])}]})
(fx/defn remove
(rf/defn remove
"Remove chat"
{:events [:group-chats.ui/remove-chat-confirmed]}
[cofx chat-id]
(fx/merge cofx
(rf/merge cofx
(models.chat/deactivate-chat chat-id)
(navigation/pop-to-root-tab :chat-stack)))
(def not-blank?
(complement string/blank?))
(defn- valid-name? [name]
(defn- valid-name?
[name]
(spec/valid? not-blank? name))
(fx/defn name-changed
(rf/defn name-changed
"Save chat from edited profile"
{:events [:group-chats.ui/name-changed]}
[{:keys [db] :as cofx} chat-id new-name]
@@ -129,29 +131,29 @@
:js-response true
:on-success #(re-frame/dispatch [:chat-updated %])}]}))
(fx/defn membership-retry
(rf/defn membership-retry
{:events [:group-chats.ui/membership-retry]}
[{{:keys [current-chat-id] :as db} :db}]
{:db (assoc-in db [:chat/memberships current-chat-id :retry?] true)})
(fx/defn membership-message
(rf/defn membership-message
{:events [:group-chats.ui/update-membership-message]}
[{{:keys [current-chat-id] :as db} :db} message]
{:db (assoc-in db [:chat/memberships current-chat-id :message] message)})
(fx/defn send-group-chat-membership-request
(rf/defn send-group-chat-membership-request
"Send group chat membership request"
{:events [:send-group-chat-membership-request]}
[{{:keys [current-chat-id chats] :as db} :db :as cofx}]
(let [{:keys [invitation-admin]} (get chats current-chat-id)
message (get-in db [:chat/memberships current-chat-id :message])]
message (get-in db [:chat/memberships current-chat-id :message])]
{:db (assoc-in db [:chat/memberships current-chat-id] nil)
::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest"
:params [nil current-chat-id invitation-admin message]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}))
(fx/defn send-group-chat-membership-rejection
(rf/defn send-group-chat-membership-rejection
"Send group chat membership rejection"
{:events [:send-group-chat-membership-rejection]}
[cofx invitation-id]
@@ -160,14 +162,17 @@
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
(fx/defn handle-invitations
(rf/defn handle-invitations
[{db :db} invitations]
{:db (update db :group-chat/invitations #(reduce (fn [acc {:keys [id] :as inv}]
(assoc acc id inv))
%
invitations))})
{:db (update db
:group-chat/invitations
#(reduce (fn [acc {:keys [id] :as inv}]
(assoc acc id inv))
%
invitations))})
(defn member-removed? [{:keys [membership-update-events]} pk]
(defn member-removed?
[{:keys [membership-update-events]} pk]
(->> membership-update-events
(filter #(contains? (set (:members %)) pk))
(sort-by :clockValue >)
@@ -175,41 +180,41 @@
:type
(= constants/invitation-state-removed)))
(fx/defn deselect-contact
(rf/defn deselect-contact
{:events [:deselect-contact]}
[{:keys [db]} id]
{:db (update db :group/selected-contacts disj id)})
(fx/defn select-contact
(rf/defn select-contact
{:events [:select-contact]}
[{:keys [db]} id]
{:db (update db :group/selected-contacts conj id)})
(fx/defn deselect-participant
(rf/defn deselect-participant
{:events [:deselect-participant]}
[{:keys [db]} id]
{:db (update db :selected-participants disj id)})
(fx/defn select-participant
(rf/defn select-participant
{:events [:select-participant]}
[{:keys [db]} id]
{:db (update db :selected-participants conj id)})
(fx/defn add-participants-toggle-list
(rf/defn add-participants-toggle-list
{:events [:group/add-participants-toggle-list]}
[{db :db}]
{:db (assoc db :selected-participants #{})})
(fx/defn show-group-chat-profile
(rf/defn show-group-chat-profile
{:events [:show-group-chat-profile]}
[{:keys [db] :as cofx} chat-id]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc :new-chat-name (get-in db [:chats chat-id :name]))
(assoc :current-chat-id chat-id))}
(navigation/navigate-to-cofx :group-chat-profile nil)))
(fx/defn ui-leave-chat-pressed
(rf/defn ui-leave-chat-pressed
{:events [:group-chats.ui/leave-chat-pressed]}
[{:keys [db]} chat-id]
(let [chat-name (get-in db [:chats chat-id :name])]
+2 -2
View File
@@ -6,7 +6,7 @@
status-im.events
status-im2.navigation.core
[status-im.chat.models :as chat.models]
[status-im.utils.security :as security]
[utils.security.core :as security]
[status-im.multiaccounts.logout.core :as logout]
[status-im.transport.core :as transport]
status-im2.subs.root ;;so integration tests can run independently
@@ -103,7 +103,7 @@
(initialize-app!) ; initialize app
(rf-test/wait-for
[:setup/initialize-view]
(generate-and-derive-addresses!) ; generate 5 new keys
(generate-and-derive-addresses!) ; generate 5 new keys
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded) ; assert keys are generated
+41 -38
View File
@@ -1,69 +1,72 @@
(ns status-im.keycard.backup-key
(:require [status-im.utils.fx :as fx]
[re-frame.core :as re-frame]
[status-im.utils.utils :as utils]
[status-im.i18n.i18n :as i18n]
(:require [re-frame.core :as re-frame]
[status-im.ethereum.mnemonic :as mnemonic]
[status-im.i18n.i18n :as i18n]
[status-im.keycard.common :as common]
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
[status-im2.navigation.events :as navigation]
[status-im.signing.core :as signing.core]
[taoensso.timbre :as log]))
[status-im.utils.utils :as utils]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn backup-card-pressed
(rf/defn backup-card-pressed
{:events [:keycard-settings.ui/backup-card-pressed]}
[{:keys [db] :as cofx} backup-type]
(log/debug "[keycard] start backup")
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :creating-backup?] backup-type))}
(when (:multiaccount db)
(navigation/change-tab :profile))
(navigation/navigate-to-cofx :seed-phrase nil)))
(fx/defn recovery-card-pressed
(rf/defn recovery-card-pressed
{:events [:keycard-settings.ui/recovery-card-pressed]}
[{:keys [db] :as cofx} show-warning]
(fx/merge cofx
{:db (-> db
;setting pin-retry-counter is a workaround for the way the PIN view decides if it should accept PUK or PIN
(assoc-in [:keycard :application-info :pin-retry-counter] 3)
(assoc-in [:keycard :factory-reset-card?] true)
(dissoc :popover/popover))
(rf/merge cofx
{:db (-> db
;setting pin-retry-counter is a workaround for the way the PIN view
;decides if it should accept PUK or PIN
(assoc-in [:keycard :application-info :pin-retry-counter] 3)
(assoc-in [:keycard :factory-reset-card?] true)
(dissoc :popover/popover))
:hide-popover nil}
(signing.core/discard)
(if show-warning
(utils/show-confirmation {:title (i18n/label :t/keycard-recover-title)
:content (i18n/label :t/keycard-recover-text)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/no)
:on-accept #(re-frame/dispatch [:keycard-settings.ui/backup-card-pressed :recovery-card])
:on-cancel #()})
(utils/show-confirmation
{:title (i18n/label :t/keycard-recover-title)
:content (i18n/label :t/keycard-recover-text)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/no)
:on-accept #(re-frame/dispatch [:keycard-settings.ui/backup-card-pressed
:recovery-card])
:on-cancel #()})
(backup-card-pressed :recovery-card))))
(fx/defn start-keycard-backup
(rf/defn start-keycard-backup
{:events [::start-keycard-backup]}
[{:keys [db] :as cofx}]
{::multiaccounts.recover/import-multiaccount {:passphrase (-> db
:multiaccounts/key-storage
:seed-phrase
mnemonic/sanitize-passphrase)
:password nil
{::multiaccounts.recover/import-multiaccount {:passphrase (-> db
:multiaccounts/key-storage
:seed-phrase
mnemonic/sanitize-passphrase)
:password nil
:success-event ::create-backup-card}})
(fx/defn create-backup-card
(rf/defn create-backup-card
{:events [::create-backup-card]}
[{:keys [db] :as cofx} root-data derived-data]
(fx/merge cofx
{:db (-> db
(update :intro-wizard
assoc
:root-key root-data
:derived derived-data
:recovering? true
:selected-storage-type :advanced)
(assoc-in [:keycard :flow] :recovery)
(update :multiaccounts/key-storage dissoc :seed-phrase))
(rf/merge cofx
{:db (-> db
(update :intro-wizard
assoc
:root-key root-data
:derived derived-data
:recovering? true
:selected-storage-type :advanced)
(assoc-in [:keycard :flow] :recovery)
(update :multiaccounts/key-storage dissoc :seed-phrase))
:dismiss-keyboard nil}
(common/listen-to-hardware-back-button)
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
+88 -77
View File
@@ -1,71 +1,74 @@
(ns status-im.keycard.change-pin
(:require [status-im.i18n.i18n :as i18n]
[status-im2.navigation.events :as navigation]
[status-im.keycard.onboarding :as onboarding]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]
[status-im.keycard.common :as common]
[status-im.utils.security :as security]))
[status-im.keycard.onboarding :as onboarding]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(fx/defn change-credentials-pressed
(rf/defn change-credentials-pressed
{:events [:keycard-settings.ui/change-credentials-pressed]}
[{:keys [db] :as cofx} changing]
(fx/merge cofx
(rf/merge cofx
{:db
(assoc-in db [:keycard :pin] {:enter-step :current
:current []
:puk []
:original []
:confirmation []
:puk-original []
:puk-confirmation []
:status nil
:error-label nil
:on-verified (case changing
:pin :keycard/proceed-to-change-pin
:puk :keycard/proceed-to-change-puk
:pairing :keycard/proceed-to-change-pairing)})}
(assoc-in db
[:keycard :pin]
{:enter-step :current
:current []
:puk []
:original []
:confirmation []
:puk-original []
:puk-confirmation []
:status nil
:error-label nil
:on-verified (case changing
:pin :keycard/proceed-to-change-pin
:puk :keycard/proceed-to-change-puk
:pairing :keycard/proceed-to-change-pairing)})}
(common/navigate-to-enter-pin-screen)))
(fx/defn proceed-to-change-pin
(rf/defn proceed-to-change-pin
{:events [:keycard/proceed-to-change-pin]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :pin :enter-step] :original)
(assoc-in [:keycard :pin :status] nil))}
(navigation/navigate-replace :enter-pin-settings nil)))
(fx/defn proceed-to-change-puk
(rf/defn proceed-to-change-puk
{:events [:keycard/proceed-to-change-puk]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :pin :enter-step] :puk-original)
(assoc-in [:keycard :pin :status] nil))}
(navigation/navigate-replace :enter-pin-settings nil)))
(fx/defn proceed-to-change-pairing
(rf/defn proceed-to-change-pairing
{:events [:keycard/proceed-to-change-pairing]}
[{:keys [db] :as cofx}]
(navigation/navigate-replace cofx :change-pairing-code nil))
(fx/defn discard-pin-change
(rf/defn discard-pin-change
{:events [::on-cancel]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
(common/clear-pin)
(common/hide-connection-sheet)
(if (get-in db [:keycard :pin :puk-restore?])
(navigation/navigate-to-cofx :multiaccounts nil)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))))
(fx/defn change-pin
(rf/defn change-pin
{:events [:keycard/change-pin]}
[{:keys [db] :as cofx}]
(let [setup-step (get-in db [:keycard :setup-step])]
(log/debug "[keycard] change-pin"
"setup-step" setup-step)
"setup-step"
setup-step)
(if (= setup-step :pin)
(onboarding/load-preparing-screen cofx)
(common/show-connection-sheet
@@ -78,15 +81,15 @@
(get-in db [:keycard :pin :original]))
current-pin (common/vector->string
(get-in db [:keycard :pin :current]))]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :pin :status] :verifying)
{:db (assoc-in db [:keycard :pin :status] :verifying)
:keycard/change-pin
{:new-pin new-pin
:current-pin current-pin}})))}))))
(fx/defn change-puk
(rf/defn change-puk
{:events [:keycard/change-puk]}
[{:keys [db] :as cofx}]
(common/show-connection-sheet
@@ -99,13 +102,13 @@
(get-in db [:keycard :pin :puk-original]))
pin (common/vector->string
(get-in db [:keycard :pin :current]))]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :pin :status] :verifying)
:keycard/change-puk {:puk puk
:pin pin}})))}))
(fx/defn change-pairing
(rf/defn change-pairing
{:events [:keycard/change-pairing]}
[{:keys [db] :as cofx}]
(common/show-connection-sheet
@@ -117,30 +120,32 @@
(let [pairing (get-in db [:keycard :pin :pairing-code])
pin (common/vector->string
(get-in db [:keycard :pin :current]))]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :pin :status] :verifying)
:keycard/change-pairing {:pairing pairing
:pin pin}})))}))
(fx/defn change-pairing-code
(rf/defn change-pairing-code
{:events [:keycard/change-pairing-code]}
[{:keys [db] :as cofx} pairing]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :pin :pairing-code] (security/unmask pairing))}
(change-pairing)))
(fx/defn on-change-pin-success
(rf/defn on-change-pin-success
{:events [:keycard.callback/on-change-pin-success]}
[{:keys [db] :as cofx}]
(let [pin (get-in db [:keycard :pin :original])
puk-restore? (get-in db [:keycard :pin :puk-restore?])]
(fx/merge cofx
{:db (assoc-in db [:keycard :pin] {:status nil
:login pin
:confirmation []
:error-label nil})
(rf/merge cofx
{:db (assoc-in db
[:keycard :pin]
{:status nil
:login pin
:confirmation []
:error-label nil})
:utils/show-popup {:title ""
:content (i18n/label :t/pin-changed)}}
(common/hide-connection-sheet)
@@ -150,55 +155,61 @@
(when (:multiaccounts/login db)
(common/get-keys-from-keycard)))))
(fx/defn on-change-puk-success
(rf/defn on-change-puk-success
{:events [:keycard.callback/on-change-puk-success]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:keycard :pin] {:status nil
:puk-original []
:puk-confirmation []
:error-label nil})
(rf/merge cofx
{:db (assoc-in db
[:keycard :pin]
{:status nil
:puk-original []
:puk-confirmation []
:error-label nil})
:utils/show-popup {:title ""
:content (i18n/label :t/puk-changed)}}
(common/hide-connection-sheet)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
(fx/defn on-change-pairing-success
(rf/defn on-change-pairing-success
{:events [:keycard.callback/on-change-pairing-success]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:keycard :pin] {:status nil
:pairing-code nil
:error-label nil})
(rf/merge cofx
{:db (assoc-in db
[:keycard :pin]
{:status nil
:pairing-code nil
:error-label nil})
:utils/show-popup {:title ""
:content (i18n/label :t/pairing-changed)}}
(common/hide-connection-sheet)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
(fx/defn on-change-pin-error
(rf/defn on-change-pin-error
{:events [:keycard.callback/on-change-pin-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] change pin error" error)
(let [tag-was-lost? (common/tag-lost? (:error error))
pin-retries (common/pin-retries (:error error))]
(fx/merge cofx
(if tag-was-lost?
(fx/merge cofx
{:db (assoc-in db [:keycard :pin :status] nil)}
(common/set-on-card-connected :keycard/change-pin))
(if-not (nil? pin-retries)
(fx/merge cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
(update-in [:keycard :pin] assoc
:status :error
:enter-step :current
:puk []
:current []
:original []
:confirmation []
:sign []
:error-label :t/pin-mismatch))}
(when (zero? pin-retries) (common/frozen-keycard-popup))
(navigation/navigate-to-cofx :enter-pin-settings nil))
(common/show-wrong-keycard-alert))))))
pin-retries (common/pin-retries (:error error))]
(rf/merge
cofx
(if tag-was-lost?
(rf/merge cofx
{:db (assoc-in db [:keycard :pin :status] nil)}
(common/set-on-card-connected :keycard/change-pin))
(if-not (nil? pin-retries)
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
(update-in [:keycard :pin]
assoc
:status :error
:enter-step :current
:puk []
:current []
:original []
:confirmation []
:sign []
:error-label :t/pin-mismatch))}
(when (zero? pin-retries) (common/frozen-keycard-popup))
(navigation/navigate-to-cofx :enter-pin-settings nil))
(common/show-wrong-keycard-alert))))))
+147 -129
View File
@@ -1,28 +1,30 @@
(ns status-im.keycard.common
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.keycard.nfc :as nfc]
[status-im.i18n.i18n :as i18n]
[status-im2.navigation.events :as navigation]
[status-im.ui.screens.keycard.keycard-interaction :as keycard-sheet]
[status-im.utils.fx :as fx]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.types :as types]
[taoensso.timbre :as log]
[status-im.utils.datetime :as utils.datetime]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.i18n.i18n :as i18n]
[status-im.keycard.nfc :as nfc]
[status-im.popover.core :as popover]
[status-im.ui.screens.keycard.keycard-interaction :as keycard-sheet]
[status-im.utils.datetime :as utils.datetime]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.platform :as platform]
[status-im.popover.core :as popover]))
[status-im.utils.types :as types]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(def default-pin "000000")
(def pin-mismatch-error #"Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)")
(defn pin-retries [error]
(when-let [matched-error (re-matches pin-mismatch-error error)] (js/parseInt (second (filter some? matched-error)))))
(defn pin-retries
[error]
(when-let [matched-error (re-matches pin-mismatch-error error)]
(js/parseInt (second (filter some? matched-error)))))
(fx/defn dispatch-event
(rf/defn dispatch-event
[_ event]
{:dispatch [event]})
@@ -56,7 +58,8 @@
(zero? free-pairing-slots))
:no-pairing-slots))
(defn tag-lost? [error]
(defn tag-lost?
[error]
(or
(= error "Tag was lost.")
(= error "NFCError:100")
@@ -94,24 +97,24 @@
(fn [supported?]
(nfc/set-nfc-supported? supported?)))
(fx/defn listen-to-hardware-back-button
(rf/defn listen-to-hardware-back-button
[{:keys [db]}]
(when-not (get-in db [:keycard :back-button-listener])
{:keycard/listen-to-hardware-back-button nil}))
(fx/defn remove-listener-to-hardware-back-button
(rf/defn remove-listener-to-hardware-back-button
[{:keys [db]}]
(when-let [listener (get-in db [:keycard :back-button-listener])]
{:keycard/remove-listener-to-hardware-back-button listener}))
(fx/defn set-on-card-connected
(rf/defn set-on-card-connected
[{:keys [db]} on-connect]
(log/debug "[keycard] set-on-card-connected" on-connect)
{:db (-> db
(assoc-in [:keycard :on-card-connected] on-connect)
(assoc-in [:keycard :last-on-card-connected] nil))})
(fx/defn stash-on-card-connected
(rf/defn stash-on-card-connected
[{:keys [db]}]
(let [on-connect (get-in db [:keycard :on-card-connected])]
(log/debug "[keycard] stash-on-card-connected" on-connect)
@@ -119,7 +122,7 @@
(assoc-in [:keycard :last-on-card-connected] on-connect)
(assoc-in [:keycard :on-card-connected] nil))}))
(fx/defn restore-on-card-connected
(rf/defn restore-on-card-connected
[{:keys [db]}]
(let [on-connect (or
(get-in db [:keycard :on-card-connected])
@@ -129,21 +132,21 @@
(assoc-in [:keycard :on-card-connected] on-connect)
(assoc-in [:keycard :last-on-card-connect] nil))}))
(fx/defn clear-on-card-connected
(rf/defn clear-on-card-connected
[{:keys [db]}]
(log/debug "[keycard] clear-on-card-connected")
{:db (-> db
(assoc-in [:keycard :on-card-connected] nil)
(assoc-in [:keycard :last-on-card-connected] nil))})
(fx/defn set-on-card-read
(rf/defn set-on-card-read
[{:keys [db]} on-connect]
(log/debug "[keycard] set-on-card-read" on-connect)
{:db (-> db
(assoc-in [:keycard :on-card-read] on-connect)
(assoc-in [:keycard :last-on-card-read] nil))})
(fx/defn stash-on-card-read
(rf/defn stash-on-card-read
[{:keys [db]}]
(let [on-connect (get-in db [:keycard :on-card-read])]
(log/debug "[keycard] stash-on-card-read" on-connect)
@@ -151,7 +154,7 @@
(assoc-in [:keycard :last-on-card-read] on-connect)
(assoc-in [:keycard :on-card-read] nil))}))
(fx/defn restore-on-card-read
(rf/defn restore-on-card-read
[{:keys [db]}]
(let [on-connect (or
(get-in db [:keycard :on-card-read])
@@ -161,14 +164,15 @@
(assoc-in [:keycard :on-card-read] on-connect)
(assoc-in [:keycard :last-on-card-connect] nil))}))
(fx/defn clear-on-card-read
(rf/defn clear-on-card-read
[{:keys [db]}]
(log/debug "[keycard] clear-on-card-read")
{:db (-> db
(assoc-in [:keycard :on-card-read] nil)
(assoc-in [:keycard :last-on-card-read] nil))})
(defn keycard-sheet-content [on-cancel connected? params]
(defn keycard-sheet-content
[on-cancel connected? params]
(fn []
[keycard-sheet/connect-keycard
{:on-cancel #(re-frame/dispatch on-cancel)
@@ -177,17 +181,19 @@
:on-connect ::on-card-connected
:on-disconnect ::on-card-disconnected}]))
(fx/defn show-connection-sheet-component
[{:keys [db] :as cofx} {:keys [on-card-connected on-card-read handler]
{:keys [on-cancel]
:or {on-cancel [::cancel-sheet-confirm]}}
:sheet-options}]
(rf/defn show-connection-sheet-component
[{:keys [db] :as cofx}
{:keys [on-card-connected on-card-read handler]
{:keys [on-cancel]
:or {on-cancel [::cancel-sheet-confirm]}}
:sheet-options}]
(assert (keyword? on-card-connected))
(assert (fn? handler))
(let [connected? (get-in db [:keycard :card-connected?])]
(log/debug "[keycard] show-sheet-with-connection-check"
"card-connected?" connected?)
(fx/merge
"card-connected?"
connected?)
(rf/merge
cofx
{:dismiss-keyboard true}
(bottom-sheet/show-bottom-sheet
@@ -205,7 +211,7 @@
(when connected?
handler))))
(fx/defn show-connection-sheet
(rf/defn show-connection-sheet
[{:keys [db] :as cofx} args]
(let [nfc-running? (get-in db [:keycard :nfc-running?])]
(log/debug "show connection; already running?" nfc-running?)
@@ -213,59 +219,59 @@
(show-connection-sheet-component cofx args)
{:keycard/start-nfc-and-show-connection-sheet args})))
(fx/defn on-nfc-ready-for-sheet
(rf/defn on-nfc-ready-for-sheet
{:events [:keycard.callback/show-connection-sheet]}
[cofx args]
(log/debug "on-nfc-ready-for-sheet")
(show-connection-sheet-component cofx args))
(fx/defn hide-connection-sheet-component
(rf/defn hide-connection-sheet-component
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :card-read-in-progress?] false)}
(restore-on-card-connected)
(restore-on-card-read)
(bottom-sheet/hide-bottom-sheet)))
(fx/defn hide-connection-sheet
(rf/defn hide-connection-sheet
[cofx]
(log/debug "hide-connection-sheet")
{:keycard/stop-nfc-and-hide-connection-sheet nil})
(fx/defn on-nfc-ready-to-close-sheet
(rf/defn on-nfc-ready-to-close-sheet
{:events [:keycard.callback/hide-connection-sheet]}
[cofx]
(log/debug "on-nfc-ready-to-close-sheet")
(hide-connection-sheet-component cofx))
(fx/defn clear-pin
(rf/defn clear-pin
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db
[:keycard :pin]
{:status nil
:login (get-in db [:keycard :pin :original])
:export-key []
:sign []
:puk []
:current []
:original []
:confirmation []
:error-label nil
:on-verified (get-in db [:keycard :pin :on-verified])
:on-verified-failure (get-in db [:keycard :pin :on-verified])})}))
[:keycard :pin]
{:status nil
:login (get-in db [:keycard :pin :original])
:export-key []
:sign []
:puk []
:current []
:original []
:confirmation []
:error-label nil
:on-verified (get-in db [:keycard :pin :on-verified])
:on-verified-failure (get-in db [:keycard :pin :on-verified])})}))
(fx/defn cancel-sheet-confirm
(rf/defn cancel-sheet-confirm
{:events [::cancel-sheet-confirm
:keycard/back-button-pressed]}
[{:keys [db] :as cofx}]
(when-not (get-in db [:keycard :card-connected?])
(fx/merge cofx
(rf/merge cofx
(hide-connection-sheet)
(clear-pin))))
(fx/defn cancel-sheet
(rf/defn cancel-sheet
{:events [::cancel-sheet]}
[_]
{:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title)
@@ -275,7 +281,7 @@
:on-accept #(re-frame/dispatch [::cancel-sheet-confirm])
:on-cancel #()}})
(fx/defn on-add-listener-to-hardware-back-button
(rf/defn on-add-listener-to-hardware-back-button
"Adds listener to hardware back button on Android.
During keycard setup we show user a warning that setup will be cancelled
when back button pressed. This prevents user from going back during setup
@@ -284,120 +290,126 @@
[{:keys [db]} listener]
{:db (assoc-in db [:keycard :back-button-listener] listener)})
(fx/defn show-wrong-keycard-alert
(rf/defn show-wrong-keycard-alert
[_]
(log/debug "show-wrong-keycard-alert")
{:utils/show-popup {:title (i18n/label :t/wrong-card)
:content (i18n/label :t/wrong-card-text)}})
(fx/defn unauthorized-operation
(rf/defn unauthorized-operation
[cofx]
(fx/merge cofx
(rf/merge cofx
{:utils/show-popup {:title ""
:content (i18n/label :t/keycard-unauthorized-operation)}}
(clear-on-card-connected)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
(fx/defn navigate-to-enter-pin-screen
(rf/defn navigate-to-enter-pin-screen
{:events [:keycard/navigate-to-enter-pin-screen]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :pin :current] [])}
(navigation/navigate-to-cofx :enter-pin-settings nil)))
(defn- tag-lost-exception? [code error]
(defn- tag-lost-exception?
[code error]
(or
(= code "android.nfc.TagLostException")
(= error "Tag was lost.")
(= error "NFCError:100")))
(fx/defn process-error [{:keys [db]} code error]
(rf/defn process-error
[{:keys [db]} code error]
(when-not (tag-lost-exception? code error)
{:db (assoc-in db [:keycard :setup-step] :error)}))
(fx/defn get-keys-from-keycard
(rf/defn get-keys-from-keycard
[{:keys [db]}]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
pin (string/join (get-in db [:keycard :pin :login]))]
(log/debug "[keycard] get-keys-from-keycard"
", not empty pin:" (boolean (seq pin)))
", not empty pin:"
(boolean (seq pin)))
(when (seq pin)
{:db (assoc-in db [:keycard :pin :status] :verifying)
:keycard/get-keys {:pin pin}})))
(fx/defn on-get-keys-success
(rf/defn on-get-keys-success
{:events [:keycard.callback/on-get-keys-success]}
[{:keys [db] :as cofx} data]
(let [{:keys [key-uid encryption-public-key whisper-private-key]
:as account-data} (js->clj data :keywordize-keys true)
:as account-data}
(js->clj data :keywordize-keys true)
{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid])
key-uid (get-in db [:keycard :application-info :key-uid])
multiaccount-data (types/clj->json {:name name
:key-uid key-uid
:identicon identicon})
save-keys? (get-in db [:multiaccounts/login :save-password?])]
(fx/merge cofx
key-uid (get-in db [:keycard :application-info :key-uid])
multiaccount-data (types/clj->json {:name name
:key-uid key-uid
:identicon identicon})
save-keys? (get-in db [:multiaccounts/login :save-password?])]
(rf/merge cofx
{:db
(-> db
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :pin :login] [])
(update-in [:keycard :application-info] assoc
(update-in [:keycard :application-info]
assoc
:puk-retry-counter 5
:pin-retry-counter 3)
(assoc-in [:keycard :multiaccount]
(update account-data :whisper-public-key ethereum/normalized-hex))
(assoc-in [:keycard :flow] nil)
(update :multiaccounts/login assoc
:password encryption-public-key
:key-uid key-uid
:identicon identicon
:name name))
:password encryption-public-key
:key-uid key-uid
:identicon identicon
:name name))
:keycard/login-with-keycard {:multiaccount-data multiaccount-data
:password encryption-public-key
:chat-key whisper-private-key
:key-uid key-uid}}
:keycard/login-with-keycard {:multiaccount-data multiaccount-data
:password encryption-public-key
:chat-key whisper-private-key
:key-uid key-uid}}
(when save-keys?
(keychain/save-keycard-keys key-uid encryption-public-key whisper-private-key))
(clear-on-card-connected)
(clear-on-card-read)
(hide-connection-sheet))))
(fx/defn blocked-or-frozen-keycard-popup
(rf/defn blocked-or-frozen-keycard-popup
[{:keys [db] :as cofx} card-status]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :pin :status] card-status)}
(hide-connection-sheet)
; do not try to display the popover if it is already open or
; we are in the login interface (which has a different handling)
; do not try to display the popover if it is already open or
; we are in the login interface (which has a different handling)
(when-not (or (:multiaccounts/login db) (:popover/popover db))
(popover/show-popover {:view card-status}))))
(fx/defn blocked-keycard-popup
(rf/defn blocked-keycard-popup
[cofx]
(blocked-or-frozen-keycard-popup cofx :blocked-card))
(fx/defn frozen-keycard-popup
(rf/defn frozen-keycard-popup
[cofx]
(blocked-or-frozen-keycard-popup cofx :frozen-card))
(fx/defn on-get-keys-error
(rf/defn on-get-keys-error
{:events [:keycard.callback/on-get-keys-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] get keys error: " error)
(let [tag-was-lost? (tag-lost? (:error error))
key-uid (get-in db [:keycard :application-info :key-uid])
flow (get-in db [:keycard :flow])
pin-retries-count (pin-retries (:error error))]
(let [tag-was-lost? (tag-lost? (:error error))
key-uid (get-in db [:keycard :application-info :key-uid])
flow (get-in db [:keycard :flow])
pin-retries-count (pin-retries (:error error))]
(if tag-was-lost?
{:db (assoc-in db [:keycard :pin :status] nil)}
(if-not (nil? pin-retries-count)
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
(update-in [:keycard :pin] assoc
(update-in [:keycard :pin]
assoc
:status :error
:login []
:import-multiaccount []
@@ -406,42 +418,45 @@
(when (zero? pin-retries-count) (frozen-keycard-popup)))
(show-wrong-keycard-alert)))))
(fx/defn factory-reset
(rf/defn factory-reset
{:events [:keycard/factory-reset]}
[{:keys [db]} on-card-read]
(log/debug "[keycard] factory-reset")
{:db (update db :keycard dissoc :factory-reset-card?)
{:db (update db :keycard dissoc :factory-reset-card?)
:keycard/factory-reset {:on-success on-card-read}})
;; Get application info
(fx/defn update-pairings
(rf/defn update-pairings
[{:keys [db]} instance-uid pairing]
(let [paired-on (utils.datetime/timestamp)
pairings (-> (get-in db [:keycard :pairings])
(assoc instance-uid {:pairing pairing :paired-on paired-on}))]
(let [paired-on (utils.datetime/timestamp)
pairings (-> (get-in db [:keycard :pairings])
(assoc instance-uid {:pairing pairing :paired-on paired-on}))]
{:keycard/persist-pairings pairings
:db (assoc-in db [:keycard :pairings] pairings)}))
:db (assoc-in db [:keycard :pairings] pairings)}))
(fx/defn get-application-info
(rf/defn get-application-info
{:events [:keycard/get-application-info]}
[{:keys [db]} on-card-read]
(log/debug "[keycard] get-application-info")
{:keycard/get-application-info {:on-success on-card-read}})
(fx/defn on-get-application-info-success
(rf/defn on-get-application-info-success
{:events [:keycard.callback/on-get-application-info-success]}
[{:keys [db] :as cofx} info on-success]
(let [{:keys [pin-retry-counter puk-retry-counter instance-uid new-pairing]} info
view-id (:view-id db)
{:keys [on-card-read]} (:keycard db)
on-success' (or on-success on-card-read)
enter-step (get-in db [:keycard :pin :enter-step])]
view-id (:view-id db)
{:keys [on-card-read]} (:keycard db)
on-success' (or on-success
on-card-read)
enter-step (get-in db
[:keycard :pin
:enter-step])]
(log/debug "[keycard] on-get-application-info-success"
"on-success" on-success'
"on-success" on-success'
"pin-retry-counter" pin-retry-counter
"puk-retry-counter" puk-retry-counter)
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc-in [:keycard :pin :enter-step] enter-step)
@@ -461,7 +476,7 @@
(when on-success'
(dispatch-event cofx on-success')))))))
(fx/defn on-get-application-info-error
(rf/defn on-get-application-info-error
{:events [:keycard.callback/on-get-application-info-error]}
[{:keys [db] :as cofx} error]
(let [on-card-read (get-in db [:keycard :on-card-read])
@@ -475,10 +490,10 @@
last-on-card-connected)
(when-not tag-was-lost?
(if login?
(fx/merge cofx
(rf/merge cofx
(clear-on-card-read)
(navigation/navigate-to-cofx :not-keycard nil))
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :application-info-error] error)}
(when (contains?
@@ -489,7 +504,7 @@
(when on-card-read
(dispatch-event on-card-read)))))))
(fx/defn on-card-connected
(rf/defn on-card-connected
{:events [::on-card-connected]}
[{:keys [db] :as cofx} _]
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
@@ -500,9 +515,9 @@
should-read-instance-uid? :keycard/get-application-info
:else (get-in db [:keycard :on-card-read]))]
(log/debug "[keycard] on-card-connected" on-card-connected
"on-card-read" on-card-read)
"on-card-read" on-card-read)
(when on-card-connected
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :card-read-in-progress?] (boolean on-card-read)))}
(when on-card-connected
@@ -512,20 +527,21 @@
(nil? on-card-connected))
(get-application-info on-card-read))))))
(fx/defn on-card-disconnected
(rf/defn on-card-disconnected
{:events [::on-card-disconnected]}
[{:keys [db] :as cofx} _]
(log/debug "[keycard] card disconnected")
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :card-read-in-progress?] false))}
(restore-on-card-connected)
(restore-on-card-read)))
(defn keycard-multiaccount? [db]
(defn keycard-multiaccount?
[db]
(boolean (get-in db [:multiaccount :keycard-pairing])))
(fx/defn verify-pin
(rf/defn verify-pin
{:events [:keycard/verify-pin]}
[{:keys [db] :as cofx} {:keys [pin-step on-card-connected on-failure on-success]}]
(let [on-success (or on-success
@@ -534,23 +550,25 @@
(get-in db [:keycard :pin :on-verified-failure]))
pin-step (or pin-step
(get-in db [:keycard :pin :step]))]
(fx/merge
(rf/merge
cofx
{:db (update-in db [:keycard :pin] assoc
:step pin-step
:on-verified on-success
{:db (update-in db
[:keycard :pin]
assoc
:step pin-step
:on-verified on-success
:on-verified-failure on-failure)}
(show-connection-sheet
{:on-card-connected (or on-card-connected :keycard/verify-pin)
:handler
(fn [{:keys [db] :as cofx}]
(let [pin (vector->string (get-in db [:keycard :pin pin-step]))]
(fx/merge
(let [pin (vector->string (get-in db [:keycard :pin pin-step]))]
(rf/merge
cofx
{:db (assoc-in db [:keycard :pin :status] :verifying)
{:db (assoc-in db [:keycard :pin :status] :verifying)
:keycard/verify-pin {:pin pin}})))}))))
(fx/defn navigete-to-keycard-settings
(rf/defn navigete-to-keycard-settings
{:events [::navigate-to-keycard-settings]}
[cofx]
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))
+186 -143
View File
@@ -1,70 +1,74 @@
(ns status-im.keycard.core
(:require [re-frame.db]
[status-im.i18n.i18n :as i18n]
status-im.keycard.backup-key
[status-im.keycard.card :as card]
[status-im.keycard.change-pin :as change-pin]
[status-im.keycard.common :as common]
status-im.keycard.delete-key
status-im.keycard.export-key
status-im.keycard.unpair
status-im.keycard.backup-key
[status-im.keycard.login :as login]
[status-im.keycard.mnemonic :as mnemonic]
[status-im.keycard.onboarding :as onboarding]
[status-im.keycard.recovery :as recovery]
[status-im.keycard.sign :as sign]
status-im.keycard.unpair
[status-im.keycard.wallet :as wallet]
[status-im.keycard.card :as card]
[status-im.i18n.i18n :as i18n]
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im2.navigation.events :as navigation]
[status-im.utils.datetime :as utils.datetime]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn show-keycard-has-multiaccount-alert
(rf/defn show-keycard-has-multiaccount-alert
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :setup-step] nil)
:utils/show-confirmation {:title nil
:content (i18n/label :t/keycard-has-multiaccount-on-it)
:content (i18n/label
:t/keycard-has-multiaccount-on-it)
:cancel-button-text ""
:confirm-button-text :t/okay}}))
(fx/defn load-pin-screen
(rf/defn load-pin-screen
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :setup-step] :pin)
(assoc-in [:keycard :pin] {:enter-step :original
:original []
:confirmation []}))}
(assoc-in [:keycard :pin]
{:enter-step :original
:original []
:confirmation []}))}
(navigation/navigate-to-cofx :keycard-onboarding-pin nil)))
(fx/defn load-recovery-pin-screen
(rf/defn load-recovery-pin-screen
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :pin] {:enter-step :import-multiaccount
:import-multiaccount []
:current []}))}
(assoc-in [:keycard :pin]
{:enter-step :import-multiaccount
:import-multiaccount []
:current []}))}
(common/listen-to-hardware-back-button)
(navigation/navigate-replace :keycard-recovery-pin nil)))
(fx/defn load-pairing
(rf/defn load-pairing
[{:keys [db]}]
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
pairing-data (or (get-in db [:keycard :pairings (keyword instance-uid)])
(get-in db [:keycard :pairings instance-uid]))]
{:db (update-in db [:keycard :secrets] merge pairing-data)}))
(fx/defn proceed-setup-with-initialized-card
(rf/defn proceed-setup-with-initialized-card
[{:keys [db] :as cofx} flow instance-uid paired?]
(log/debug "[keycard] proceed-setup-with-initialized-card"
"instance-uid" instance-uid)
"instance-uid"
instance-uid)
(if (= flow :import)
(navigation/navigate-to-cofx cofx :keycard-recovery-no-key nil)
(if paired?
(fx/merge cofx
(rf/merge cofx
(common/listen-to-hardware-back-button)
(when (= flow :create)
(mnemonic/set-mnemonic))
@@ -74,25 +78,25 @@
(onboarding/load-pairing-screen cofx)
(recovery/load-pair-screen cofx)))))
(fx/defn navigate-to-keycard-settings
(rf/defn navigate-to-keycard-settings
{:events [:profile.ui/keycard-settings-button-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :pin :on-verified] nil)
(assoc-in [:keycard :setup-step] nil))}
(common/clear-on-card-connected)
(navigation/navigate-to-cofx :keycard-settings nil)))
(fx/defn password-option-pressed
(rf/defn password-option-pressed
{:eevents [:keycard.ui/password-option-pressed]}
[{:keys [db]}]
(when (= (get-in db [:keycard :flow]) :create)
#())) ;;TODO with v1 flow
(fx/defn settings-screen-did-load
(rf/defn settings-screen-did-load
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :pin :on-verified] nil)
(assoc-in [:keycard :setup-step] nil))}
@@ -111,7 +115,7 @@
[{:keys [db]}]
(let [enter-step (get-in db [:keycard :pin :enter-step])]
{:db (-> db
(assoc-in [:keycard :pin enter-step] [])
(assoc-in [:keycard :pin enter-step] [])
(dissoc :intro-wizard :recovered-account?))}))
(defn multiaccounts-screen-did-load
@@ -122,44 +126,51 @@
[{:keys [db]}]
{:db (assoc-in db [:keycard :setup-step] nil)})
(fx/defn set-nfc-supported
(rf/defn set-nfc-supported
{:events [:keycard.callback/check-nfc-support-success]}
[_ supported?]
{:keycard/set-nfc-supported supported?})
;; TODO: Should be listener and replace the view in bottom sheet to avoid this
(fx/defn on-check-nfc-enabled-success
(rf/defn on-check-nfc-enabled-success
{:events [:keycard.callback/check-nfc-enabled-success]}
[{:keys [db]} nfc-enabled?]
(log/debug "[keycard] check-nfc-enabled-success"
"nfc-enabled?" nfc-enabled?)
"nfc-enabled?"
nfc-enabled?)
{:db (assoc-in db [:keycard :nfc-enabled?] nfc-enabled?)})
(defn- proceed-to-pin-confirmation [fx]
(defn- proceed-to-pin-confirmation
[fx]
(assoc-in fx [:db :keycard :pin :enter-step] :confirmation))
(defn- proceed-to-change-puk-confirmation [fx]
(defn- proceed-to-change-puk-confirmation
[fx]
(assoc-in fx [:db :keycard :pin :enter-step] :puk-confirmation))
(defn- proceed-to-pin-reset-confirmation [fx]
(defn- proceed-to-pin-reset-confirmation
[fx]
(-> fx
(update-in [:db :keycard :pin] dissoc :reset-confirmation)
(assoc-in [:db :keycard :pin :enter-step] :reset-confirmation)))
(defn- proceed-to-puk-confirmation [fx]
(defn- proceed-to-puk-confirmation
[fx]
(assoc-in fx [:db :keycard :pin :enter-step] :puk))
(fx/defn on-unblock-pin-success
(rf/defn on-unblock-pin-success
{:events [:keycard.callback/on-unblock-pin-success]}
[{:keys [db] :as cofx}]
(let [reset-pin (get-in db [:keycard :pin :reset])]
(fx/merge cofx
(rf/merge cofx
{:db
(-> db
(update-in [:keycard :application-info] assoc
(update-in [:keycard :application-info]
assoc
:puk-retry-counter 5
:pin-retry-counter 3)
(update-in [:keycard :pin] assoc
(update-in [:keycard :pin]
assoc
:status :after-unblocking
:enter-step :login
:login reset-pin
@@ -171,18 +182,19 @@
(common/clear-on-card-connected)
(common/clear-on-card-read))))
(fx/defn on-unblock-pin-error
(rf/defn on-unblock-pin-error
{:events [:keycard.callback/on-unblock-pin-error]}
[{:keys [db] :as cofx} error]
(let [tag-was-lost? (common/tag-lost? (:error error))
puk-retries (common/pin-retries (:error error))]
puk-retries (common/pin-retries (:error error))]
(log/debug "[keycard] unblock pin error" error)
(when-not tag-was-lost?
(fx/merge cofx
(rf/merge cofx
{:db
(-> db
(assoc-in [:keycard :application-info :puk-retry-counter] puk-retries)
(update-in [:keycard :pin] merge
(update-in [:keycard :pin]
merge
{:status (if (zero? puk-retries) :blocked-card :error)
:error-label :t/puk-mismatch
:enter-step :puk
@@ -190,19 +202,25 @@
(common/hide-connection-sheet)))))
(fx/defn clear-on-verify-handlers
(rf/defn clear-on-verify-handlers
[{:keys [db]}]
{:db (update-in db [:keycard :pin]
dissoc :on-verified-failure :on-verified)})
{:db (update-in db
[:keycard :pin]
dissoc
:on-verified-failure
:on-verified)})
(fx/defn on-verify-pin-success
(rf/defn on-verify-pin-success
{:events [:keycard.callback/on-verify-pin-success]}
[{:keys [db] :as cofx}]
(let [on-verified (get-in db [:keycard :pin :on-verified])]
(log/debug "[hardwaller] success pin verification. on-verified" on-verified)
(fx/merge cofx
{:db (update-in db [:keycard :pin] merge {:status nil
:error-label nil})}
(rf/merge cofx
{:db (update-in db
[:keycard :pin]
merge
{:status nil
:error-label nil})}
(common/clear-on-card-connected)
(common/clear-on-card-read)
;; TODO(Ferossgp): Each pin input should handle this event on it's own,
@@ -211,33 +229,36 @@
(when-not (contains? #{:keycard/generate-and-load-key
:wallet.accounts/generate-new-keycard-account
:keycard/remove-key-with-unpair
:keycard/unpair-and-delete} on-verified)
:keycard/unpair-and-delete}
on-verified)
(common/hide-connection-sheet))
(when-not (contains? #{:keycard/unpair
:keycard/generate-and-load-key
:keycard/remove-key-with-unpair
:keycard/unpair-and-delete
:wallet.accounts/generate-new-keycard-account} on-verified)
:wallet.accounts/generate-new-keycard-account}
on-verified)
(common/get-application-info nil))
(when on-verified
(common/dispatch-event on-verified))
(clear-on-verify-handlers))))
(fx/defn on-verify-pin-error
(rf/defn on-verify-pin-error
{:events [:keycard.callback/on-verify-pin-error]}
[{:keys [db] :as cofx} error]
(let [tag-was-lost? (common/tag-lost? (:error error))
setup? (boolean (get-in db [:keycard :setup-step]))
on-verified-failure (get-in db [:keycard :pin :on-verified-failure])
exporting? (get-in db [:keycard :on-export-success])
pin-retries (common/pin-retries (:error error))]
pin-retries (common/pin-retries (:error error))]
(log/debug "[keycard] verify pin error" error)
(when-not tag-was-lost?
(if-not (nil? pin-retries)
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
(update-in [:keycard :pin] assoc
(update-in [:keycard :pin]
assoc
:status :error
:enter-step :current
:puk []
@@ -251,20 +272,21 @@
(not on-verified-failure))
(when exporting?
(navigation/navigate-back)))
;(navigation/navigate-to-cofx :enter-pin-settings nil)))
;(navigation/navigate-to-cofx :enter-pin-settings nil)))
(when (zero? pin-retries) (common/frozen-keycard-popup))
(when on-verified-failure
(fn [_] {:utils/dispatch-later
[{:dispatch [on-verified-failure]
:ms 200}]}))
(fn [_]
{:utils/dispatch-later
[{:dispatch [on-verified-failure]
:ms 200}]}))
#_(clear-on-verify-handlers))
(fx/merge cofx
(rf/merge cofx
(common/hide-connection-sheet)
(common/show-wrong-keycard-alert)
(clear-on-verify-handlers))))))
(fx/defn unblock-pin
(rf/defn unblock-pin
{:events [:keycard/unblock-pin]}
[cofx]
(common/show-connection-sheet
@@ -275,7 +297,7 @@
(let [puk (common/vector->string (get-in db [:keycard :pin :puk]))
pin (common/vector->string (get-in db [:keycard :pin :reset]))
key-uid (get-in db [:keycard :application-info :key-uid])]
{:db (assoc-in db [:keycard :pin :status] :verifying)
{:db (assoc-in db [:keycard :pin :status] :verifying)
:keycard/unblock-pin
{:puk puk
:new-pin pin}}))}))
@@ -283,22 +305,24 @@
(def pin-code-length 6)
(def puk-code-length 12)
(fx/defn handle-pin-input
(rf/defn handle-pin-input
[{:keys [db]} enter-step]
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))]
(when (or (= numbers-entered pin-code-length)
(= numbers-entered puk-code-length))
{:dispatch [:keycard/process-pin-input]})))
(fx/defn update-pin
(rf/defn update-pin
{:events [:keycard.ui/pin-numpad-button-pressed]}
[{:keys [db] :as cofx} number enter-step]
(log/debug "update-pin" enter-step)
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))
need-update? (if (or (= enter-step :puk) (= enter-step :puk-original) (= enter-step :puk-confirmation))
(< numbers-entered puk-code-length)
(< numbers-entered pin-code-length))]
(fx/merge cofx
need-update? (if (or (= enter-step :puk)
(= enter-step :puk-original)
(= enter-step :puk-confirmation))
(< numbers-entered puk-code-length)
(< numbers-entered pin-code-length))]
(rf/merge cofx
{:db (cond-> (-> db
(assoc-in [:keycard :pin :enter-step] enter-step)
(assoc-in [:keycard :pin :status] nil))
@@ -306,26 +330,38 @@
(when need-update?
(handle-pin-input enter-step)))))
(defn- pin-enter-error [fx error-label]
(update-in fx [:db :keycard :pin] merge {:status :error
:error-label error-label
:enter-step :original
:original []
:confirmation []}))
(defn- pin-enter-error
[fx error-label]
(update-in fx
[:db :keycard :pin]
merge
{:status :error
:error-label error-label
:enter-step :original
:original []
:confirmation []}))
(defn- puk-enter-error [fx error-label]
(update-in fx [:db :keycard :pin] merge {:status :error
:error-label error-label
:enter-step :puk-original
:puk-original []
:puk-confirmation []}))
(defn- puk-enter-error
[fx error-label]
(update-in fx
[:db :keycard :pin]
merge
{:status :error
:error-label error-label
:enter-step :puk-original
:puk-original []
:puk-confirmation []}))
(defn- pin-reset-error [fx error-label]
(update-in fx [:db :keycard :pin] merge {:status :error
:error-label error-label
:enter-step :reset
:reset []
:reset-confirmation []}))
(defn- pin-reset-error
[fx error-label]
(update-in fx
[:db :keycard :pin]
merge
{:status :error
:error-label error-label
:enter-step :reset
:reset []
:reset-confirmation []}))
; PIN enter steps:
; login - PIN is used to login
@@ -333,14 +369,14 @@
; current - current PIN to perform actions which require PIN auth
; original - new PIN when user changes it or creates new one
; confirmation - confirmation for new PIN
(fx/defn process-pin-input
(rf/defn process-pin-input
{:events [:keycard/process-pin-input]}
[{:keys [db]}]
(let [enter-step (get-in db [:keycard :pin :enter-step])
pin (get-in db [:keycard :pin enter-step])
(let [enter-step (get-in db [:keycard :pin :enter-step])
pin (get-in db [:keycard :pin enter-step])
numbers-entered (count pin)]
(log/debug "[keycard] process-pin-input"
"enter-step" enter-step
"enter-step" enter-step
"numbers-entered" numbers-entered)
(cond-> {:db (assoc-in db [:keycard :pin :status] nil)}
@@ -417,15 +453,19 @@
(get-in db [:keycard :pin :reset-confirmation])))
(pin-reset-error :t/pin-mismatch))))
(fx/defn set-multiaccount-pairing
(rf/defn set-multiaccount-pairing
[cofx _ pairing paired-on]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:keycard-pairing pairing {})
:keycard-pairing
pairing
{})
(multiaccounts.update/multiaccount-update
:keycard-paired-on paired-on {})))
:keycard-paired-on
paired-on
{})))
(fx/defn on-retrieve-pairings-success
(rf/defn on-retrieve-pairings-success
{:events [:keycard.callback/on-retrieve-pairings-success]}
[{:keys [db]} pairings]
(card/set-pairings pairings)
@@ -438,7 +478,7 @@
;; with setup and skip the pairing step if the pairing was already done during a previous
;; unfinished setup.
(fx/defn on-pair-success
(rf/defn on-pair-success
{:events [:keycard.callback/on-pair-success]}
[{:keys [db] :as cofx} pairing]
(let [setup-step (get-in db [:keycard :setup-step])
@@ -448,19 +488,20 @@
paired-on (utils.datetime/timestamp)
pairings (-> (get-in db [:keycard :pairings])
(dissoc (keyword instance-uid))
(assoc instance-uid {:pairing pairing :paired-on paired-on}))
(assoc instance-uid {:pairing pairing :paired-on paired-on}))
next-step (if (= setup-step :pair)
:begin
:card-ready)]
(fx/merge cofx
(rf/merge cofx
{:keycard/persist-pairings pairings
:db (-> db
(assoc-in [:keycard :pairings] pairings)
(assoc-in [:keycard :application-info :paired?] true)
(assoc-in [:keycard :setup-step] next-step)
(assoc-in [:keycard :secrets :pairing] pairing)
(assoc-in [:keycard :secrets :paired-on] paired-on))}
(when-not (and (= flow :recovery) (= next-step :card-ready)) (common/hide-connection-sheet))
:db (-> db
(assoc-in [:keycard :pairings] pairings)
(assoc-in [:keycard :application-info :paired?] true)
(assoc-in [:keycard :setup-step] next-step)
(assoc-in [:keycard :secrets :pairing] pairing)
(assoc-in [:keycard :secrets :paired-on] paired-on))}
(when-not (and (= flow :recovery) (= next-step :card-ready))
(common/hide-connection-sheet))
(when multiaccount
(set-multiaccount-pairing multiaccount pairing paired-on))
(when (= flow :login)
@@ -474,7 +515,7 @@
(when (= flow :create)
(mnemonic/set-mnemonic)))))
(fx/defn on-pair-error
(rf/defn on-pair-error
{:events [:keycard.callback/on-pair-error]}
[{:keys [db] :as cofx} {:keys [error code]}]
(log/debug "[keycard] pair error: " error)
@@ -483,7 +524,7 @@
flow (get-in db [:keycard :flow])]
(log/debug "[keycard] on-pair-error" setup-step "flow:" flow)
(when-not tag-was-lost?
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :setup-error] (i18n/label :t/invalid-pairing-password))}
(common/set-on-card-connected (if (= setup-step :pairing)
:keycard/load-pairing-screen
@@ -494,17 +535,19 @@
(when (not= setup-step :enter-pair-code)
(common/process-error code error))))))
(fx/defn set-setup-step
(rf/defn set-setup-step
[{:keys [db]} card-state]
{:db (assoc-in db [:keycard :setup-step]
(case card-state
:not-paired :pair
:no-pairing-slots :no-slots
:init :card-ready
:multiaccount :import-multiaccount
:begin))})
{:db (assoc-in db
[:keycard :setup-step]
(case card-state
:not-paired :pair
:no-pairing-slots :no-slots
:init :card-ready
:multiaccount :import-multiaccount
:begin))})
(fx/defn show-no-keycard-applet-alert [_]
(rf/defn show-no-keycard-applet-alert
[_]
{:utils/show-confirmation {:title (i18n/label :t/no-keycard-applet-on-card)
:content (i18n/label :t/keycard-applet-install-instructions)
:cancel-button-text ""
@@ -512,17 +555,17 @@
;; NOTE: Maybe replaced by multiple events based on on flow to make it easier to maintain.
;; Because there are many execution paths it is harder to follow all possible states.
(fx/defn check-card-state
(rf/defn check-card-state
{:events [:keycard/check-card-state]}
[{:keys [db] :as cofx}]
(let [app-info (get-in db [:keycard :application-info])
flow (get-in db [:keycard :flow])
(let [app-info (get-in db [:keycard :application-info])
flow (get-in db [:keycard :flow])
{:keys [instance-uid key-uid paired?]} app-info
card-state (common/get-card-state app-info)]
card-state (common/get-card-state app-info)]
(log/debug "[keycard] check-card-state"
"card-state" card-state
"flow" flow)
(fx/merge cofx
"flow" flow)
(rf/merge cofx
{:db (assoc-in db [:keycard :card-state] card-state)}
(set-setup-step card-state)
@@ -538,7 +581,7 @@
(if (= flow :import)
(navigation/navigate-to-cofx :keycard-recovery-no-key nil)
(fn [cofx]
(fx/merge
(rf/merge
cofx
(common/clear-on-card-read)
(load-pin-screen)))))
@@ -560,72 +603,72 @@
(#{:create :recovery} flow))
(show-keycard-has-multiaccount-alert)))))
(fx/defn on-card-connected
(rf/defn on-card-connected
{:events [:keycard.callback/on-card-connected]}
[{:keys [db]} _]
(log/debug "[keycard] card globally connected")
{:db (assoc-in db [:keycard :card-connected?] true)})
(fx/defn on-card-disconnected
(rf/defn on-card-disconnected
{:events [:keycard.callback/on-card-disconnected]}
[{:keys [db]} _]
(log/debug "[keycard] card disconnected")
{:db (assoc-in db [:keycard :card-connected?] false)})
(fx/defn on-nfc-user-cancelled
(rf/defn on-nfc-user-cancelled
{:events [:keycard.callback/on-nfc-user-cancelled]}
[{:keys [db]} _]
(log/debug "[keycard] nfc user cancelled")
{:dispatch [:signing.ui/cancel-is-pressed]})
(fx/defn on-nfc-timeout
(rf/defn on-nfc-timeout
{:events [:keycard.callback/on-nfc-timeout]}
[{:keys [db]} _]
(log/debug "[keycard] nfc timeout")
{:db (-> db
(assoc-in [:keycard :nfc-running?] false)
(assoc-in [:keycard :card-connected?] false))
{:db (-> db
(assoc-in [:keycard :nfc-running?] false)
(assoc-in [:keycard :card-connected?] false))
:dispatch-later [{:ms 500 :dispatch [:keycard.ui/start-nfc]}]})
(fx/defn on-register-card-events
(rf/defn on-register-card-events
{:events [:keycard.callback/on-register-card-events]}
[{:keys [db]} listeners]
{:db (update-in db [:keycard :listeners] merge listeners)})
(fx/defn ui-recovery-phrase-cancel-pressed
(rf/defn ui-recovery-phrase-cancel-pressed
{:events [:keycard.ui/recovery-phrase-cancel-pressed]}
[{:keys [db]}]
{:db (assoc-in db [:keycard :setup-step] :recovery-phrase)})
(fx/defn ui-pin-numpad-delete-button-pressed
(rf/defn ui-pin-numpad-delete-button-pressed
{:events [:keycard.ui/pin-numpad-delete-button-pressed]}
[{:keys [db]} step]
(when-not (empty? (get-in db [:keycard :pin step]))
{:db (update-in db [:keycard :pin step] pop)}))
(fx/defn start-nfc
(rf/defn start-nfc
{:events [:keycard.ui/start-nfc]}
[cofx]
{:keycard/start-nfc nil})
(fx/defn stop-nfc
(rf/defn stop-nfc
{:events [:keycard.ui/stop-nfc]}
[cofx]
{:keycard/stop-nfc nil
{:keycard/stop-nfc nil
:keycard.callback/on-card-disconnected nil})
(fx/defn start-nfc-success
(rf/defn start-nfc-success
{:events [:keycard.callback/start-nfc-success]}
[{:keys [db]} _]
(log/debug "[keycard] nfc started success")
{:db (assoc-in db [:keycard :nfc-running?] true)})
(fx/defn start-nfc-failure
(rf/defn start-nfc-failure
{:events [:keycard.callback/start-nfc-failure]}
[{:keys [db]} _]
(log/debug "[keycard] nfc failed starting")) ;; leave current value on :nfc-running
(fx/defn stop-nfc-success
(rf/defn stop-nfc-success
{:events [:keycard.callback/stop-nfc-success]}
[{:keys [db]} _]
(log/debug "[keycard] nfc stopped success")
@@ -634,7 +677,7 @@
(assoc-in [:keycard :nfc-running?] false)
(assoc-in [:keycard :card-connected?] false))})
(fx/defn stop-nfc-failure
(rf/defn stop-nfc-failure
{:events [:keycard.callback/stop-nfc-failure]}
[{:keys [db]} _]
(log/debug "[keycard] nfc failed stopping")) ;; leave current value on :nfc-running
+20 -18
View File
@@ -1,44 +1,46 @@
(ns status-im.keycard.delete-key
(:require [status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.keycard.common :as common]))
(:require [status-im.keycard.common :as common]
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(fx/defn reset-card-pressed
(rf/defn reset-card-pressed
{:events [:keycard-settings.ui/reset-card-pressed]}
[cofx]
(navigation/navigate-to-cofx cofx :reset-card nil))
(fx/defn delete-card
(rf/defn delete-card
[{:keys [db] :as cofx}]
(let [key-uid (get-in db [:keycard :application-info :key-uid])
(let [key-uid (get-in db [:keycard :application-info :key-uid])
multiaccount-key-uid (get-in db [:multiaccount :key-uid])]
(if (and key-uid
(= key-uid multiaccount-key-uid))
{:keycard/delete nil}
(common/unauthorized-operation cofx))))
(fx/defn navigate-to-reset-card-screen
(rf/defn navigate-to-reset-card-screen
{:events [:keycard/navigate-to-reset-card-screen]}
[cofx]
(navigation/navigate-to-cofx cofx :reset-card nil))
(fx/defn reset-card-next-button-pressed
(rf/defn reset-card-next-button-pressed
{:events [:keycard-settings.ui/reset-card-next-button-pressed]}
[{:keys [db]}]
{:db (assoc-in db [:keycard :reset-card :disabled?] true)
:dispatch [:keycard/proceed-to-reset-card false]})
(fx/defn proceed-to-reset-card
(rf/defn proceed-to-reset-card
{:events [:keycard/proceed-to-reset-card]}
[{:keys [db] :as cofx} keep-keys-on-keycard?]
(fx/merge cofx
{:db (assoc-in db [:keycard :pin] {:enter-step :current
:current []
:puk []
:status nil
:error-label nil
:on-verified (if keep-keys-on-keycard?
:keycard/unpair-and-delete
:keycard/remove-key-with-unpair)})}
(rf/merge cofx
{:db (assoc-in db
[:keycard :pin]
{:enter-step :current
:current []
:puk []
:status nil
:error-label nil
:on-verified (if keep-keys-on-keycard?
:keycard/unpair-and-delete
:keycard/remove-key-with-unpair)})}
(common/set-on-card-connected :keycard/navigate-to-enter-pin-screen)
(common/navigate-to-enter-pin-screen)))
+34 -32
View File
@@ -1,47 +1,49 @@
(ns status-im.keycard.export-key
(:require [status-im.utils.fx :as fx]
[taoensso.timbre :as log]
(:require [status-im.keycard.common :as common]
[status-im.keycard.wallet :as wallet]
[status-im.keycard.common :as common]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn on-export-key-error
(rf/defn on-export-key-error
{:events [:keycard.callback/on-export-key-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] export key error" error)
(let [tag-was-lost? (common/tag-lost? (:error error))
pin-retries (common/pin-retries (:error error))]
(cond tag-was-lost?
(fx/merge cofx
{:db (assoc-in db [:keycard :pin :status] nil)}
(common/set-on-card-connected :wallet.accounts/generate-new-keycard-account))
pin-retries (common/pin-retries (:error error))]
(cond
tag-was-lost?
(rf/merge cofx
{:db (assoc-in db [:keycard :pin :status] nil)}
(common/set-on-card-connected :wallet.accounts/generate-new-keycard-account))
(not (nil? pin-retries))
(fx/merge cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
(update-in [:keycard :pin] assoc
:status :error
:enter-step :export-key
:puk []
:current []
:original []
:confirmation []
:sign []
:export-key []
:error-label :t/pin-mismatch))}
(common/hide-connection-sheet)
(when (zero? pin-retries) (common/frozen-keycard-popup)))
:else
(fx/merge cofx
(common/show-wrong-keycard-alert)
(common/clear-pin)
(common/hide-connection-sheet)))))
(not (nil? pin-retries))
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
(update-in [:keycard :pin]
assoc
:status :error
:enter-step :export-key
:puk []
:current []
:original []
:confirmation []
:sign []
:export-key []
:error-label :t/pin-mismatch))}
(common/hide-connection-sheet)
(when (zero? pin-retries) (common/frozen-keycard-popup)))
:else
(rf/merge cofx
(common/show-wrong-keycard-alert)
(common/clear-pin)
(common/hide-connection-sheet)))))
(fx/defn on-export-key-success
(rf/defn on-export-key-success
{:events [:keycard.callback/on-export-key-success]}
[{:keys [db] :as cofx} pubkey]
(let [callback-fn (get-in db [:keycard :on-export-success])]
(fx/merge cofx
(rf/merge cofx
{:dispatch (callback-fn pubkey)}
(wallet/hide-pin-sheet)
(common/clear-pin)
+61 -55
View File
@@ -1,70 +1,73 @@
(ns status-im.keycard.login
(:require [status-im.ethereum.core :as ethereum]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.utils.types :as types]
[taoensso.timbre :as log]
(:require [status-im.bottom-sheet.core :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.keycard.common :as common]
[status-im.keycard.recovery :as recovery]
[status-im.keycard.onboarding :as onboarding]
status-im.keycard.fx
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.signing.core :as signing.core]))
[status-im.keycard.onboarding :as onboarding]
[status-im.keycard.recovery :as recovery]
[status-im.signing.core :as signing.core]
[status-im.utils.types :as types]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn login-got-it-pressed
(rf/defn login-got-it-pressed
{:events [:keycard.login.pin.ui/got-it-pressed
:keycard.login.pin.ui/cancel-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db db}
(navigation/pop-to-root-tab :multiaccounts-stack)))
(fx/defn login-pin-more-icon-pressed
(rf/defn login-pin-more-icon-pressed
{:events [:keycard.login.pin.ui/more-icon-pressed]}
[cofx]
(bottom-sheet/show-bottom-sheet cofx {:view :keycard.login/more}))
(fx/defn login-create-key-pressed
(rf/defn login-create-key-pressed
{:events [:keycard.login.ui/create-new-key-pressed]}
[cofx]
(fx/merge cofx
(rf/merge cofx
(bottom-sheet/hide-bottom-sheet)
(onboarding/start-onboarding-flow)))
(fx/defn login-add-key-pressed
(rf/defn login-add-key-pressed
{:events [:keycard.login.ui/add-key-pressed]}
[cofx]
(recovery/start-import-flow cofx))
(fx/defn login-remember-me-changed
(rf/defn login-remember-me-changed
{:events [:keycard.login.ui/remember-me-changed]}
[{:keys [db] :as cofx} value]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :remember-me?] value)}))
(fx/defn login-pair-card-pressed
(rf/defn login-pair-card-pressed
{:events [:keycard.login.ui/pair-card-pressed]}
[{:keys [db] :as cofx}]
(log/debug "[keycard] load-pair-card-pressed")
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :flow] :login)}
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
(fx/defn reset-pin
(rf/defn reset-pin
{:events [::reset-pin]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
(signing.core/discard)
(fn [{:keys [db]}]
{:db (-> db
(dissoc :popover/popover)
(update-in [:keycard :pin] dissoc
:reset :puk)
(update-in [:keycard :pin] assoc
:enter-step :reset
:error nil
:status nil))
{:db (-> db
(dissoc :popover/popover)
(update-in [:keycard :pin]
dissoc
:reset
:puk)
(update-in [:keycard :pin]
assoc
:enter-step :reset
:error nil
:status nil))
:hide-popover nil})
(when (:multiaccount db)
(navigation/change-tab :profile))
@@ -73,50 +76,51 @@
(navigation/navigate-replace :keycard-pin nil)
(navigation/navigate-to-cofx :keycard-pin nil)))))
(fx/defn dismiss-frozen-keycard-popover
(rf/defn dismiss-frozen-keycard-popover
{:events [::frozen-keycard-popover-dismissed]}
[{:keys [db]}]
{:db (-> db
(dissoc :popover/popover)
(update :keycard dissoc :setup-step))
{:db (-> db
(dissoc :popover/popover)
(update :keycard dissoc :setup-step))
:hide-popover nil})
(fx/defn login-with-keycard
(rf/defn login-with-keycard
{:events [:keycard/login-with-keycard]}
[{:keys [db] :as cofx}]
(let [{:keys [:pin-retry-counter :puk-retry-counter]
:as application-info}
:as application-info}
(get-in db [:keycard :application-info])
key-uid (get-in db [:keycard :application-info :key-uid])
paired? (get-in db [:keycard :application-info :paired?])
multiaccount (get-in db [:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :key-uid])])
multiaccount-key-uid (get multiaccount :key-uid)
key-uid (get-in db [:keycard :application-info :key-uid])
paired? (get-in db [:keycard :application-info :paired?])
multiaccount (get-in db
[:multiaccounts/multiaccounts (get-in db [:multiaccounts/login :key-uid])])
multiaccount-key-uid (get multiaccount :key-uid)
multiaccount-mismatch? (or (nil? multiaccount)
(not= multiaccount-key-uid key-uid))]
(log/debug "[keycard] login-with-keycard"
"empty application info" (empty? application-info)
"no key-uid" (empty? key-uid)
"no key-uid" (empty? key-uid)
"multiaccount-mismatch?" multiaccount-mismatch?
"no pairing" paired?)
"no pairing" paired?)
(cond
(empty? application-info)
(fx/merge cofx
(rf/merge cofx
(common/hide-connection-sheet)
(navigation/navigate-to-cofx :not-keycard nil))
(empty? key-uid)
(fx/merge cofx
(rf/merge cofx
(common/hide-connection-sheet)
(navigation/navigate-to-cofx :keycard-blank nil))
multiaccount-mismatch?
(fx/merge cofx
(rf/merge cofx
(common/hide-connection-sheet)
(navigation/navigate-to-cofx :keycard-wrong nil))
(not paired?)
(fx/merge cofx
(rf/merge cofx
(common/hide-connection-sheet)
(navigation/navigate-to-cofx :keycard-unpaired nil))
@@ -128,7 +132,7 @@
:else
(common/get-keys-from-keycard cofx))))
(fx/defn proceed-to-login
(rf/defn proceed-to-login
{:events [::login-after-reset]}
[cofx]
(log/debug "[keycard] proceed-to-login")
@@ -139,12 +143,14 @@
:on-card-read :keycard/login-with-keycard
:handler (common/get-application-info :keycard/login-with-keycard)}))
(fx/defn on-keycard-keychain-keys
(rf/defn on-keycard-keychain-keys
{:events [:multiaccounts.login.callback/get-keycard-keys-success]}
[{:keys [db] :as cofx} key-uid [encryption-public-key whisper-private-key :as creds]]
(if (nil? creds)
(navigation/set-stack-root cofx :multiaccounts-stack [:multiaccounts
:keycard-login-pin])
(navigation/set-stack-root cofx
:multiaccounts-stack
[:multiaccounts
:keycard-login-pin])
(let [{:keys [identicon name]} (get-in db [:multiaccounts/multiaccounts key-uid])
multiaccount-data (types/clj->json {:name name
:key-uid key-uid
@@ -160,18 +166,18 @@
(update account-data :whisper-public-key ethereum/normalized-hex))
(assoc-in [:keycard :flow] nil)
(update :multiaccounts/login assoc
:password encryption-public-key
:key-uid key-uid
:identicon identicon
:name name
:save-password? true))
:password encryption-public-key
:key-uid key-uid
:identicon identicon
:name name
:save-password? true))
:keycard/login-with-keycard
{:multiaccount-data multiaccount-data
:key-uid key-uid
:password encryption-public-key
:chat-key whisper-private-key}})))
(fx/defn on-login-success
(rf/defn on-login-success
{:events [:keycard.login.callback/login-success]}
[_ result]
(log/debug "loginWithKeycard success: " result))
+14 -14
View File
@@ -1,21 +1,21 @@
(ns status-im.keycard.mnemonic
(:require [status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
(:require [status-im.keycard.common :as common]
status-im.keycard.fx
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[status-im.keycard.common :as common]
status-im.keycard.fx))
[utils.re-frame :as rf]))
(fx/defn set-mnemonic
(rf/defn set-mnemonic
[{:keys [db] :as cofx}]
(log/debug "[keycard] set-mnemonic")
(let [selected-id (get-in db [:intro-wizard :selected-id])
mnemonic (reduce
(fn [_ {:keys [id mnemonic]}]
(when (= selected-id id)
(reduced mnemonic)))
nil
(get-in db [:intro-wizard :multiaccounts]))]
(fx/merge
mnemonic (reduce
(fn [_ {:keys [id mnemonic]}]
(when (= selected-id id)
(reduced mnemonic)))
nil
(get-in db [:intro-wizard :multiaccounts]))]
(rf/merge
cofx
{:db (-> db
(assoc-in [:keycard :setup-step] :recovery-phrase)
@@ -24,11 +24,11 @@
(common/hide-connection-sheet)
(navigation/navigate-replace :keycard-onboarding-recovery-phrase nil))))
(fx/defn load-loading-keys-screen
(rf/defn load-loading-keys-screen
{:events [:keycard.ui/recovery-phrase-confirm-pressed
:keycard/load-loading-keys-screen]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
(common/show-connection-sheet
+90 -78
View File
@@ -1,18 +1,18 @@
(ns status-im.keycard.onboarding
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.i18n.i18n :as i18n]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.utils.utils :as utils]
[status-im.keycard.common :as common]
[status-im.keycard.mnemonic :as mnemonic]
[taoensso.timbre :as log]
status-im.keycard.fx
[status-im.keycard.mnemonic :as mnemonic]
[status-im.ui.components.react :as react]
[status-im.constants :as constants]))
[status-im.utils.utils :as utils]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn begin-setup-button-pressed
(rf/defn begin-setup-button-pressed
{:keys [:keycard.ui/begin-setup-button-pressed]}
[{:keys [db]}]
{:db (-> db
@@ -21,7 +21,7 @@
(assoc-in [:keycard :pin :original] [])
(assoc-in [:keycard :pin :confirmation] []))})
(fx/defn start-installation
(rf/defn start-installation
[{:keys [db] :as cofx}]
(let [card-state (get-in db [:keycard :card-state])
pin (common/vector->string (get-in db [:keycard :pin :original]))]
@@ -33,12 +33,12 @@
(do
(log/debug (str "Cannot start keycard installation from state: " card-state))
(fx/merge cofx
(rf/merge cofx
{:utils/show-popup {:title (i18n/label :t/error)
:content (i18n/label :t/something-went-wrong)}}
(navigation/navigate-to-cofx :keycard-authentication-method nil))))))
(fx/defn load-preparing-screen
(rf/defn load-preparing-screen
{:events [:keycard/load-preparing-screen]}
[cofx]
(common/show-connection-sheet
@@ -47,11 +47,11 @@
:on-card-connected :keycard/load-preparing-screen
:handler start-installation}))
(fx/defn load-pairing-screen
(rf/defn load-pairing-screen
{:events [:keycard/load-pairing-screen
:keycard.onboarding.puk-code.ui/confirm-pressed]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :setup-step] :pairing)}
(common/show-connection-sheet
@@ -59,21 +59,22 @@
:on-card-connected :keycard/load-pairing-screen
:handler (common/dispatch-event :keycard/pair)})))
(fx/defn puk-code-next-pressed
(rf/defn puk-code-next-pressed
{:events [:keycard.onboarding.puk-code.ui/next-pressed]}
[_]
{:ui/show-confirmation {:title (i18n/label :t/secret-keys-confirmation-title)
:content (i18n/label :t/secret-keys-confirmation-text)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/cancel)
:on-accept #(re-frame/dispatch [:keycard.onboarding.puk-code.ui/confirm-pressed])
:on-accept #(re-frame/dispatch
[:keycard.onboarding.puk-code.ui/confirm-pressed])
:on-cancel #()}})
(fx/defn load-finishing-screen
(rf/defn load-finishing-screen
{:events [:keycard.onboarding.recovery-phrase-confirm-word2.ui/next-pressed
:keycard/load-finishing-screen]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
(common/show-connection-sheet
@@ -81,29 +82,30 @@
:on-card-connected :keycard/load-finishing-screen
:handler (common/dispatch-event :keycard/generate-and-load-key)})))
(fx/defn recovery-phrase-learn-more-pressed
(rf/defn recovery-phrase-learn-more-pressed
{:events [:keycard.onboarding.recovery-phrase.ui/learn-more-pressed]}
[_]
(.openURL ^js react/linking constants/keycard-integration-link))
(fx/defn recovery-phrase-next-pressed
(rf/defn recovery-phrase-next-pressed
{:events [:keycard.onboarding.recovery-phrase.ui/next-pressed
:keycard.ui/recovery-phrase-next-button-pressed]}
[_]
{:ui/show-confirmation {:title (i18n/label :t/keycard-recovery-phrase-confirmation-title)
:content (i18n/label :t/keycard-recovery-phrase-confirmation-text)
{:ui/show-confirmation {:title (i18n/label :t/keycard-recovery-phrase-confirmation-title)
:content (i18n/label :t/keycard-recovery-phrase-confirmation-text)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/cancel)
:on-accept #(re-frame/dispatch [:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
:on-cancel #()}})
:cancel-button-text (i18n/label :t/cancel)
:on-accept #(re-frame/dispatch
[:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
:on-cancel #()}})
(fx/defn recovery-phrase-start-confirmation
(rf/defn recovery-phrase-start-confirmation
[{:keys [db] :as cofx}]
(let [mnemonic (get-in db [:keycard :secrets :mnemonic])
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
word1 (zipmap [:idx :word] word1)
word2 (zipmap [:idx :word] word2)]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word1)
(assoc-in [:keycard :recovery-phrase :step] :word1)
@@ -113,14 +115,14 @@
(assoc-in [:keycard :recovery-phrase :word2] word2))}
(common/remove-listener-to-hardware-back-button))))
(fx/defn recovery-phrase-confirm-pressed
(rf/defn recovery-phrase-confirm-pressed
{:events [:keycard.onboarding.recovery-phrase.ui/confirm-pressed]}
[cofx]
(fx/merge cofx
(rf/merge cofx
(recovery-phrase-start-confirmation)
(navigation/navigate-to-cofx :keycard-onboarding-recovery-phrase-confirm-word1 nil)))
(fx/defn recovery-phrase-next-word
(rf/defn recovery-phrase-next-word
[{:keys [db]}]
{:db (-> db
(assoc-in [:keycard :recovery-phrase :step] :word2)
@@ -128,50 +130,52 @@
(assoc-in [:keycard :recovery-phrase :input-word] nil)
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word2))})
(fx/defn proceed-with-generating-key
(rf/defn proceed-with-generating-key
[{:keys [db] :as cofx}]
(let [pin (get-in db [:keycard :secrets :pin]
(let [pin (get-in db
[:keycard :secrets :pin]
(common/vector->string (get-in db [:keycard :pin :current])))]
(if (empty? pin)
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :pin] {:enter-step :current
:on-verified :keycard/generate-and-load-key
:current []})
(assoc-in [:keycard :pin]
{:enter-step :current
:on-verified :keycard/generate-and-load-key
:current []})
(assoc-in [:keycard :setup-step] :loading-keys))}
(navigation/navigate-to-cofx :keycard-onboarding-pin nil))
(load-finishing-screen cofx))))
(fx/defn recovery-phrase-confirm-word-next-pressed
(rf/defn recovery-phrase-confirm-word-next-pressed
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/next-pressed
:keycard.onboarding.recovery-phrase-confirm-word.ui/input-submitted]}
[{:keys [db] :as cofx}]
(let [step (get-in db [:keycard :recovery-phrase :step])
input-word (get-in db [:keycard :recovery-phrase :input-word])
(let [step (get-in db [:keycard :recovery-phrase :step])
input-word (get-in db [:keycard :recovery-phrase :input-word])
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
(if (= word input-word)
(if (= (:view-id db) :keycard-onboarding-recovery-phrase-confirm-word1)
(fx/merge cofx
(rf/merge cofx
(recovery-phrase-next-word)
(navigation/navigate-replace :keycard-onboarding-recovery-phrase-confirm-word2 nil))
(proceed-with-generating-key cofx))
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
(fx/defn recovery-phrase-confirm-word-input-changed
(rf/defn recovery-phrase-confirm-word-input-changed
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/input-changed]}
[{:keys [db]} input]
{:db (assoc-in db [:keycard :recovery-phrase :input-word] input)})
(fx/defn pair-code-input-changed
(rf/defn pair-code-input-changed
{:events [:keycard.onboarding.pair.ui/input-changed]}
[{:keys [db]} input]
{:db (assoc-in db [:keycard :secrets :password] input)})
(fx/defn keycard-option-pressed
(rf/defn keycard-option-pressed
{:events [:onboarding.ui/keycard-option-pressed]}
[{:keys [db] :as cofx}]
(let [flow (get-in db [:keycard :flow])]
(fx/merge cofx
(rf/merge cofx
{:keycard/check-nfc-enabled nil}
(if (= flow :import)
(navigation/navigate-to-cofx :keycard-recovery-intro nil)
@@ -179,33 +183,36 @@
(common/listen-to-hardware-back-button)
(navigation/navigate-to-cofx :keycard-onboarding-intro nil))))))
(fx/defn start-onboarding-flow
(rf/defn start-onboarding-flow
{:events [:keycard/start-onboarding-flow]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:keycard :flow] :create)
(rf/merge cofx
{:db (assoc-in db [:keycard :flow] :create)
:keycard/check-nfc-enabled nil}
(common/listen-to-hardware-back-button)
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
(fx/defn open-nfc-settings-pressed
(rf/defn open-nfc-settings-pressed
{:events [:keycard.onboarding.nfc-on/open-nfc-settings-pressed]}
[_]
{:keycard/open-nfc-settings nil})
(defn- show-recover-confirmation []
(defn- show-recover-confirmation
[]
{:ui/show-confirmation {:title (i18n/label :t/are-you-sure?)
:content (i18n/label :t/are-you-sure-description)
:confirm-button-text (clojure.string/upper-case (i18n/label :t/yes))
:cancel-button-text (i18n/label :t/see-it-again)
:on-accept #(re-frame/dispatch [:keycard.ui/recovery-phrase-confirm-pressed])
:on-cancel #(re-frame/dispatch [:keycard.ui/recovery-phrase-cancel-pressed])}})
:on-accept #(re-frame/dispatch
[:keycard.ui/recovery-phrase-confirm-pressed])
:on-cancel #(re-frame/dispatch
[:keycard.ui/recovery-phrase-cancel-pressed])}})
(fx/defn recovery-phrase-confirm-word
(rf/defn recovery-phrase-confirm-word
{:events [:keycard.ui/recovery-phrase-confirm-word-next-button-pressed]}
[{:keys [db]}]
(let [step (get-in db [:keycard :recovery-phrase :step])
input-word (get-in db [:keycard :recovery-phrase :input-word])
(let [step (get-in db [:keycard :recovery-phrase :step])
input-word (get-in db [:keycard :recovery-phrase :input-word])
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
(if (= word input-word)
(if (= step :word1)
@@ -213,21 +220,21 @@
(show-recover-confirmation))
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
(fx/defn recovery-phrase-next-button-pressed
(rf/defn recovery-phrase-next-button-pressed
[{:keys [db] :as cofx}]
(if (= (get-in db [:keycard :flow]) :create)
(recovery-phrase-start-confirmation cofx)
(let [mnemonic (get-in db [:multiaccounts/recover :passphrase])]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :secrets :mnemonic] mnemonic)}
(mnemonic/load-loading-keys-screen)))))
(fx/defn on-install-applet-and-init-card-success
(rf/defn on-install-applet-and-init-card-success
{:events [:keycard.callback/on-install-applet-and-init-card-success
:keycard.callback/on-init-card-success]}
[{:keys [db] :as cofx} secrets]
(let [secrets' (js->clj secrets :keywordize-keys true)]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :card-state] :init)
(assoc-in [:keycard :setup-step] :secret-keys)
@@ -237,17 +244,17 @@
:on-card-read :keycard/check-card-state
:handler (common/get-application-info :keycard/check-card-state)}))))
(fx/defn on-install-applet-and-init-card-error
(rf/defn on-install-applet-and-init-card-error
{:events [:keycard.callback/on-install-applet-and-init-card-error
:keycard.callback/on-init-card-error]}
[{:keys [db] :as cofx} {:keys [code error]}]
(log/debug "[keycard] install applet and init card error: " error)
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :setup-error] error)}
(common/set-on-card-connected :keycard/load-preparing-screen)
(common/process-error code error)))
(fx/defn generate-and-load-key
(rf/defn generate-and-load-key
{:events [:keycard/generate-and-load-key]}
[{:keys [db] :as cofx}]
(let [{:keys [pin]}
@@ -256,36 +263,41 @@
{:keys [selected-id multiaccounts]}
(:intro-wizard db)
multiaccount (or (->> multiaccounts
(filter #(= (:id %) selected-id))
first)
(assoc (get-in db [:intro-wizard :root-key])
:derived
(get-in db [:intro-wizard :derived])))
recovery-mnemonic (get-in db [:intro-wizard :passphrase])
mnemonic (or (:mnemonic multiaccount)
recovery-mnemonic)
pin' (or pin (common/vector->string (get-in db [:keycard :pin :current])))]
(fx/merge cofx
multiaccount (or (->> multiaccounts
(filter #(= (:id %) selected-id))
first)
(assoc (get-in db [:intro-wizard :root-key])
:derived
(get-in db [:intro-wizard :derived])))
recovery-mnemonic (get-in db [:intro-wizard :passphrase])
mnemonic (or (:mnemonic multiaccount)
recovery-mnemonic)
pin' (or pin
(common/vector->string (get-in db
[:keycard :pin
:current])))]
(rf/merge cofx
{:keycard/generate-and-load-key
{:mnemonic mnemonic
:pin pin'
:key-uid (:key-uid multiaccount)
:delete-multiaccount? (get-in db [:keycard :delete-account?])}})))
(fx/defn factory-reset-card-toggle
(rf/defn factory-reset-card-toggle
{:events [:keycard.onboarding.intro.ui/factory-reset-card-toggle]}
[{:keys [db] :as cofx} checked?]
{:db (assoc-in db [:keycard :factory-reset-card?] checked?)})
(fx/defn begin-setup-pressed
(rf/defn begin-setup-pressed
{:events [:keycard.onboarding.intro.ui/begin-setup-pressed]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(update :keycard
dissoc :secrets :card-state :multiaccount-wallet-address
dissoc
:secrets
:card-state :multiaccount-wallet-address
:multiaccount-whisper-public-key :application-info)
(assoc-in [:keycard :setup-step] :begin)
(assoc-in [:keycard :pin :on-verified] nil))}
@@ -301,7 +313,7 @@
:on-card-read :keycard/check-card-state
:handler (common/get-application-info :keycard/check-card-state)}))))
(fx/defn factory-reset
(rf/defn factory-reset
{:events [::factory-reset]}
[cofx]
(common/show-connection-sheet
@@ -310,14 +322,14 @@
:on-card-read :keycard/check-card-state
:handler (common/factory-reset :keycard/check-card-state)}))
(fx/defn factory-reset-cancel
(rf/defn factory-reset-cancel
{:events [::factory-reset-cancel]}
[{:keys [db] :as cofx}]
{:db (update db :keycard dissoc :factory-reset-card?)})
(fx/defn cancel-pressed
(rf/defn cancel-pressed
{:events [::cancel-pressed]}
[cofx]
(fx/merge cofx
(rf/merge cofx
(navigation/navigate-back)
(common/cancel-sheet-confirm)))
+156 -136
View File
@@ -1,30 +1,31 @@
(ns status-im.keycard.recovery
(:require [status-im2.navigation.events :as navigation]
[status-im.utils.datetime :as utils.datetime]
[status-im.multiaccounts.create.core :as multiaccounts.create]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.utils.fx :as fx]
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[clojure.string :as string]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[status-im.i18n.i18n :as i18n]
[taoensso.timbre :as log]
[status-im.keycard.common :as common]
status-im.keycard.fx
[status-im.constants :as constants]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.core :as ethereum]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.multiaccounts.create.core :as multiaccounts.create]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.native-module.core :as status]
[status-im.popover.core :as popover]
[status-im.utils.types :as types]
[status-im.utils.security :as security]
[status-im.utils.datetime :as utils.datetime]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.platform :as platform]))
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(fx/defn pair* [_ password]
(rf/defn pair*
[_ password]
{:keycard/pair {:password password}})
(fx/defn pair
(rf/defn pair
{:events [:keycard/pair]}
[cofx]
(let [{:keys [password]} (get-in cofx [:db :keycard :secrets])]
@@ -33,41 +34,41 @@
{:on-card-connected :keycard/pair
:handler (pair* password)})))
(fx/defn pair-code-next-button-pressed
(rf/defn pair-code-next-button-pressed
{:events [:keycard.onboarding.pair.ui/input-submitted
:keycard.ui/pair-code-next-button-pressed
:keycard.onboarding.pair.ui/next-pressed]}
[{:keys [db] :as cofx}]
(let [pairing (get-in db [:keycard :secrets :pairing])
(let [pairing (get-in db [:keycard :secrets :pairing])
paired-on (get-in db [:keycard :secrets :paired-on] (utils.datetime/timestamp))]
(fx/merge cofx
(rf/merge cofx
(if pairing
{:db (-> db
(assoc-in [:keycard :setup-step] :import-multiaccount)
(assoc-in [:keycard :secrets :paired-on] paired-on))}
(pair)))))
(fx/defn load-pair-screen
(rf/defn load-pair-screen
[{:keys [db] :as cofx}]
(log/debug "[keycard] load-pair-screen")
(fx/merge cofx
{:db (-> db
(assoc-in [:keycard :setup-step] :pair))
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :setup-step] :pair))
:dispatch [:bottom-sheet/hide]}
(common/listen-to-hardware-back-button)
(navigation/navigate-to-cofx :keycard-recovery-pair nil)))
(fx/defn keycard-storage-selected-for-recovery
(rf/defn keycard-storage-selected-for-recovery
{:events [:recovery.ui/keycard-storage-selected]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :flow] :recovery)}
(navigation/navigate-to-cofx :keycard-recovery-enter-mnemonic nil)))
(fx/defn start-import-flow
(rf/defn start-import-flow
{:events [::recover-with-keycard-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db
(-> db
(assoc-in [:keycard :flow] :import)
@@ -76,35 +77,37 @@
(bottom-sheet/hide-bottom-sheet)
(navigation/navigate-to-cofx :keycard-recovery-intro nil)))
(fx/defn access-key-pressed
(rf/defn access-key-pressed
{:events [:multiaccounts.recover.ui/recover-multiaccount-button-pressed]}
[_]
{:dispatch [:bottom-sheet/show-sheet :recover-sheet]})
(fx/defn recovery-keycard-selected
(rf/defn recovery-keycard-selected
{:events [:recovery.ui/keycard-option-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:keycard :flow] :recovery)
(rf/merge cofx
{:db (assoc-in db [:keycard :flow] :recovery)
:keycard/check-nfc-enabled nil}
(common/listen-to-hardware-back-button)
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
(fx/defn cancel-pressed
(rf/defn cancel-pressed
{:events [::cancel-pressed]}
[cofx]
(fx/merge cofx
(rf/merge cofx
(common/cancel-sheet-confirm)
(navigation/navigate-back)))
(fx/defn begin-setup-pressed
(rf/defn begin-setup-pressed
{:events [:keycard.recovery.intro.ui/begin-recovery-pressed]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(update :keycard
dissoc :secrets :card-state :multiaccount-wallet-address
dissoc
:secrets
:card-state :multiaccount-wallet-address
:multiaccount-whisper-public-key
:application-info)
(assoc-in [:keycard :setup-step] :begin)
@@ -115,21 +118,24 @@
:sheet-options {:on-cancel [::cancel-pressed]}
:handler (common/get-application-info :keycard/check-card-state)})))
(fx/defn recovery-success-finish-pressed
(rf/defn recovery-success-finish-pressed
{:events [:keycard.recovery.success/finish-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (update db :keycard dissoc
(rf/merge cofx
{:db (update db
:keycard dissoc
:multiaccount-wallet-address
:multiaccount-whisper-public-key)}
(navigation/navigate-to-cofx (if platform/android?
:notifications-settings :welcome) nil)))
:notifications-settings
:welcome)
nil)))
(fx/defn intro-wizard
(rf/defn intro-wizard
{:events [:multiaccounts.create.ui/intro-wizard]}
[{:keys [db] :as cofx}]
(let [accs (get db :multiaccounts/multiaccounts)]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(update :keycard dissoc :flow)
(dissoc :restored-account?))}
@@ -138,16 +144,16 @@
(navigation/navigate-to-cofx :get-your-keys nil)
(navigation/set-stack-root :onboarding [:get-your-keys])))))
(fx/defn recovery-no-key
(rf/defn recovery-no-key
{:events [:keycard.recovery.no-key.ui/generate-key-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:keycard :flow] :create)
(rf/merge cofx
{:db (assoc-in db [:keycard :flow] :create)
:keycard/check-nfc-enabled nil}
(intro-wizard)))
(fx/defn create-keycard-multiaccount
{:events [::create-keycard-multiaccount]
(rf/defn create-keycard-multiaccount
{:events [::create-keycard-multiaccount]
:interceptors [(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
[{:keys [db] :as cofx}]
@@ -166,13 +172,14 @@
encryption-public-key
instance-uid
key-uid
recovered]} multiaccount
{:keys [pairing paired-on]} secrets
recovered]}
multiaccount
{:keys [pairing paired-on]} secrets
{:keys [name identicon]}
(if (nil? name)
;; name might have been generated during recovery via passphrase
(get-in db [:intro-wizard :derived constants/path-whisper-keyword])
{:name name
{:name name
:identicon identicon})]
;; if a name is still `nil` we have to generate it before multiaccount's
;; creation otherwise spec validation will fail
@@ -180,7 +187,7 @@
{:keycard/generate-name-and-photo
{:public-key whisper-public-key
:on-success ::on-name-and-photo-generated}}
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :setup-step] nil)
(dissoc :intro-wizard))}
@@ -193,7 +200,7 @@
{:public-key whisper-public-key
:address (eip55/address->checksum whisper-address)
:name name
:identicon identicon}
:identicon identicon}
constants/path-default-wallet-keyword
{:public-key wallet-public-key
:address (eip55/address->checksum wallet-address)}}
@@ -207,24 +214,29 @@
encryption-public-key
{})))))
(fx/defn return-to-keycard-login
(rf/defn return-to-keycard-login
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(update-in [:keycard :pin] assoc :enter-step :login
:status nil
:login [])
(update-in [:keycard :pin]
assoc
:enter-step :login
:status nil
:login [])
(update :keycard dissoc :application-info))}
(navigation/set-stack-root :multiaccounts-stack [:multiaccounts
:keycard-login-pin])))
(navigation/set-stack-root :multiaccounts-stack
[:multiaccounts
:keycard-login-pin])))
(fx/defn on-backup-success
(rf/defn on-backup-success
[{:keys [db] :as cofx} backup-type]
(fx/merge cofx
{:utils/show-popup {:title (i18n/label (if (= backup-type :recovery-card)
:t/keycard-access-reset :t/keycard-backup-success-title))
:content (i18n/label (if (= backup-type :recovery-card)
:t/keycard-can-use-with-new-passcode :t/keycard-backup-success-body))}}
(rf/merge cofx
{:utils/show-popup {:title (i18n/label (if (= backup-type :recovery-card)
:t/keycard-access-reset
:t/keycard-backup-success-title))
:content (i18n/label (if (= backup-type :recovery-card)
:t/keycard-can-use-with-new-passcode
:t/keycard-backup-success-body))}}
(cond
(multiaccounts.model/logged-in? cofx)
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
@@ -246,36 +258,40 @@
#(let [{:keys [error]} (types/json->clj %)]
(if (string/blank? error)
(status/login-with-keycard login-params)
(throw (js/Error. "Please shake the phone to report this error and restart the app. Migration failed unexpectedly.")))))))
(throw
(js/Error.
"Please shake the phone to report this error and restart the app. Migration failed unexpectedly.")))))))
(fx/defn migrate-account
(rf/defn migrate-account
[{:keys [db] :as cofx}]
(let [pairing (get-in db [:keycard :secrets :pairing])
paired-on (get-in db [:keycard :secrets :paired-on])
instance-uid (get-in db [:keycard :multiaccount :instance-uid])
account (-> db
:multiaccounts/login
(assoc :keycard-pairing pairing)
(assoc :save-password? false))
key-uid (-> account :key-uid)
settings {:keycard-instance-uid instance-uid
:keycard-paired-on paired-on
:keycard-pairing pairing}
password (ethereum/sha3 (security/safe-unmask-data (get-in db [:keycard :migration-password])))
(let [pairing (get-in db [:keycard :secrets :pairing])
paired-on (get-in db [:keycard :secrets :paired-on])
instance-uid (get-in db [:keycard :multiaccount :instance-uid])
account (-> db
:multiaccounts/login
(assoc :keycard-pairing pairing)
(assoc :save-password? false))
key-uid (-> account :key-uid)
settings {:keycard-instance-uid instance-uid
:keycard-paired-on paired-on
:keycard-pairing pairing}
password (ethereum/sha3 (security/safe-unmask-data (get-in db
[:keycard
:migration-password])))
encryption-pass (get-in db [:keycard :multiaccount :encryption-public-key])
login-params {:key-uid key-uid
:multiaccount-data (types/clj->json account)
:password encryption-pass
:chat-key (get-in db [:keycard :multiaccount :whisper-private-key])}]
{:db (-> db
(assoc-in [:multiaccounts/multiaccounts key-uid :keycard-pairing] pairing)
(assoc :multiaccounts/login account)
(assoc :auth-method keychain/auth-method-none)
(update :keycard dissoc :flow :migration-password)
(dissoc :recovered-account?))
login-params {:key-uid key-uid
:multiaccount-data (types/clj->json account)
:password encryption-pass
:chat-key (get-in db [:keycard :multiaccount :whisper-private-key])}]
{:db (-> db
(assoc-in [:multiaccounts/multiaccounts key-uid :keycard-pairing] pairing)
(assoc :multiaccounts/login account)
(assoc :auth-method keychain/auth-method-none)
(update :keycard dissoc :flow :migration-password)
(dissoc :recovered-account?))
::finish-migration [account settings password encryption-pass login-params]}))
(fx/defn delete-multiaccount
(rf/defn delete-multiaccount
[{:keys [db]}]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])]
{:keycard/delete-multiaccount-before-migration
@@ -283,61 +299,63 @@
:on-error #(re-frame/dispatch [::delete-multiaccount-error %])
:on-success #(re-frame/dispatch [::create-keycard-multiaccount])}}))
(fx/defn handle-delete-multiaccount-error
(rf/defn handle-delete-multiaccount-error
{:events [::delete-multiaccount-error]}
[cofx _]
(popover/show-popover cofx {:view :transfer-multiaccount-unknown-error}))
(fx/defn on-generate-and-load-key-success
(rf/defn on-generate-and-load-key-success
{:events [:keycard.callback/on-generate-and-load-key-success]
:interceptors [(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
[{:keys [db random-guid-generator] :as cofx} data]
(let [account-data (js->clj data :keywordize-keys true)
backup? (get-in db [:keycard :creating-backup?])
migration? (get-in db [:keycard :converting-account?])]
(fx/merge cofx
{:db (-> db
(assoc-in [:keycard :multiaccount]
(-> account-data
(update :address ethereum/normalized-hex)
(update :whisper-address ethereum/normalized-hex)
(update :wallet-address ethereum/normalized-hex)
(update :wallet-root-address ethereum/normalized-hex)
(update :public-key ethereum/normalized-hex)
(update :whisper-public-key ethereum/normalized-hex)
(update :wallet-public-key ethereum/normalized-hex)
(update :wallet-root-public-key ethereum/normalized-hex)
(update :instance-uid #(get-in db [:keycard :multiaccount :instance-uid] %))))
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :application-info :key-uid]
(ethereum/normalized-hex (:key-uid account-data)))
(update :keycard dissoc :recovery-phrase :creating-backup? :converting-account?)
(update-in [:keycard :secrets] dissoc :pin :puk :password :mnemonic)
(assoc :multiaccounts/new-installation-id (random-guid-generator)))}
(common/remove-listener-to-hardware-back-button)
(common/hide-connection-sheet)
(cond backup? (on-backup-success backup?)
migration? (migrate-account)
backup? (get-in db [:keycard :creating-backup?])
migration? (get-in db [:keycard :converting-account?])]
(rf/merge
cofx
{:db (-> db
(assoc-in
[:keycard :multiaccount]
(-> account-data
(update :address ethereum/normalized-hex)
(update :whisper-address ethereum/normalized-hex)
(update :wallet-address ethereum/normalized-hex)
(update :wallet-root-address ethereum/normalized-hex)
(update :public-key ethereum/normalized-hex)
(update :whisper-public-key ethereum/normalized-hex)
(update :wallet-public-key ethereum/normalized-hex)
(update :wallet-root-public-key ethereum/normalized-hex)
(update :instance-uid #(get-in db [:keycard :multiaccount :instance-uid] %))))
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
(assoc-in [:keycard :pin :status] nil)
(assoc-in [:keycard :application-info :key-uid]
(ethereum/normalized-hex (:key-uid account-data)))
(update :keycard dissoc :recovery-phrase :creating-backup? :converting-account?)
(update-in [:keycard :secrets] dissoc :pin :puk :password :mnemonic)
(assoc :multiaccounts/new-installation-id (random-guid-generator)))}
(common/remove-listener-to-hardware-back-button)
(common/hide-connection-sheet)
(cond backup? (on-backup-success backup?)
migration? (migrate-account)
(get-in db [:keycard :delete-account?])
(delete-multiaccount)
(get-in db [:keycard :delete-account?])
(delete-multiaccount)
:else (create-keycard-multiaccount)))))
:else (create-keycard-multiaccount)))))
(fx/defn on-generate-and-load-key-error
(rf/defn on-generate-and-load-key-error
{:events [:keycard.callback/on-generate-and-load-key-error]}
[{:keys [db] :as cofx} {:keys [error code]}]
(log/debug "[keycard] generate and load key error: " error)
(when-not (common/tag-lost? error)
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :setup-error] error)}
(common/set-on-card-connected :keycard/load-loading-keys-screen)
(common/process-error code error))))
(fx/defn import-multiaccount
(rf/defn import-multiaccount
{:events [:keycard/import-multiaccount]}
[{:keys [db] :as cofx}]
(let [{:keys [pairing]} (get-in db [:keycard :secrets])
@@ -345,17 +363,18 @@
key-uid (get-in db [:keycard :application-info :key-uid])
pairing' (or pairing (common/get-pairing db key-uid))
pin (common/vector->string (get-in db [:keycard :pin :import-multiaccount]))]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :multiaccount :instance-uid] instance-uid)
(assoc-in [:keycard :pin :status] :verifying)
(assoc-in [:keycard :secrets] {:pairing pairing'
:paired-on (utils.datetime/timestamp)}))
(assoc-in [:keycard :secrets]
{:pairing pairing'
:paired-on (utils.datetime/timestamp)}))
:keycard/import-keys
{:pin pin
:on-success :keycard.callback/on-generate-and-load-key-success}})))
{:pin pin
:on-success :keycard.callback/on-generate-and-load-key-success}})))
(fx/defn load-recovering-key-screen
(rf/defn load-recovering-key-screen
{:events [:keycard/load-recovering-key-screen]}
[cofx]
(common/show-connection-sheet
@@ -363,17 +382,18 @@
{:on-card-connected :keycard/load-recovering-key-screen
:handler (common/dispatch-event :keycard/import-multiaccount)}))
(fx/defn on-name-and-photo-generated
{:events [::on-name-and-photo-generated]
(rf/defn on-name-and-photo-generated
{:events [::on-name-and-photo-generated]
:interceptors [(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
[{:keys [db] :as cofx} whisper-name identicon]
(fx/merge
(rf/merge
cofx
{:db (update-in db [:keycard :multiaccount]
{:db (update-in db
[:keycard :multiaccount]
(fn [multiacc]
(assoc multiacc
:recovered (get db :recovered-account?)
:name whisper-name
:name whisper-name
:identicon identicon)))}
(create-keycard-multiaccount)))
+72 -63
View File
@@ -1,46 +1,49 @@
(ns status-im.keycard.sign
(:require [re-frame.core :as re-frame]
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[status-im.keycard.common :as common]
[status-im.utils.money :as money]
[status-im.utils.types :as types]
[taoensso.timbre :as log]
[status-im.keycard.common :as common]
[clojure.string :as string]))
[utils.re-frame :as rf]))
(fx/defn sign
(rf/defn sign
{:events [:keycard/sign]}
[{:keys [db] :as cofx} hash on-success]
(let [card-connected? (get-in db [:keycard :card-connected?])
key-uid (get-in db [:multiaccount :key-uid])
keycard-key-uid (get-in db [:keycard :application-info :key-uid])
keycard-pin-retries (get-in db [:keycard :application-info :pin-retry-counter])
keycard-match? (= key-uid keycard-key-uid)
hash (or hash (get-in db [:keycard :hash]))
data (get-in db [:keycard :data])
typed? (get-in db [:keycard :typed?])
pin (common/vector->string (get-in db [:keycard :pin :sign]))
from (or (get-in db [:signing/tx :from :address]) (get-in db [:signing/tx :message :from]) (ethereum/default-address db))
path (reduce
(fn [_ {:keys [address path]}]
(when (ethereum/address= from address)
(reduced path)))
nil
(:multiaccount/accounts db))]
(let [card-connected? (get-in db [:keycard :card-connected?])
key-uid (get-in db [:multiaccount :key-uid])
keycard-key-uid (get-in db [:keycard :application-info :key-uid])
keycard-pin-retries (get-in db [:keycard :application-info :pin-retry-counter])
keycard-match? (= key-uid keycard-key-uid)
hash (or hash (get-in db [:keycard :hash]))
data (get-in db [:keycard :data])
typed? (get-in db [:keycard :typed?])
pin (common/vector->string (get-in db [:keycard :pin :sign]))
from (or (get-in db [:signing/tx :from :address])
(get-in db [:signing/tx :message :from])
(ethereum/default-address db))
path (reduce
(fn [_ {:keys [address path]}]
(when (ethereum/address= from address)
(reduced path)))
nil
(:multiaccount/accounts db))]
(cond
(not keycard-match?)
(common/show-wrong-keycard-alert cofx)
(not card-connected?)
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}
(common/set-on-card-connected :keycard/sign))
(pos? keycard-pin-retries) ; if 0, get-application-info will have already closed the connection sheet and opened the frozen card popup
{:db (-> db
(assoc-in [:keycard :card-read-in-progress?] true)
(assoc-in [:keycard :pin :status] :verifying))
(pos? keycard-pin-retries) ; if 0, get-application-info will have already closed the connection
; sheet and opened the frozen card popup
{:db (-> db
(assoc-in [:keycard :card-read-in-progress?] true)
(assoc-in [:keycard :pin :status] :verifying))
:keycard/sign {:hash (ethereum/naked-address hash)
:data data
:typed? typed? ; this parameter is for e2e
@@ -48,76 +51,80 @@
:pin pin
:path path}})))
(defn normalize-signature [signature]
(defn normalize-signature
[signature]
(-> signature
(string/replace-first #"00$", "1b")
(string/replace-first #"01$", "1c")
(string/replace-first #"00$" "1b")
(string/replace-first #"01$" "1c")
ethereum/normalized-hex))
(fx/defn sign-message
(rf/defn sign-message
{:events [:keycard/sign-message]}
[cofx params result]
(let [{:keys [result error]} (types/json->clj result)
on-success #(re-frame/dispatch [:keycard/on-sign-message-success params
(normalize-signature %)])
hash (ethereum/naked-address result)]
on-success #(re-frame/dispatch [:keycard/on-sign-message-success params
(normalize-signature %)])
hash (ethereum/naked-address result)]
(sign cofx hash on-success)))
(fx/defn on-sign-message-success
(rf/defn on-sign-message-success
{:events [:keycard/on-sign-message-success]}
[{:keys [db] :as cofx} {:keys [tx-hash message-id chat-id value contract]} signature]
(fx/merge
(rf/merge
cofx
{:dispatch
(if message-id
[:sign/send-accept-transaction-message message-id tx-hash signature]
[:sign/send-transaction-message chat-id value contract tx-hash signature])
:signing/show-transaction-result nil
:db (-> db
(assoc-in [:keycard :pin :sign] [])
(assoc-in [:keycard :pin :status] nil))}
:db (-> db
(assoc-in [:keycard :pin :sign] [])
(assoc-in [:keycard :pin :status] nil))}
(common/clear-on-card-connected)
(common/get-application-info nil)
(common/hide-connection-sheet)))
(fx/defn sign-typed-data
(rf/defn sign-typed-data
{:events [:keycard/sign-typed-data]}
[{:keys [db] :as cofx}]
(let [card-connected? (get-in db [:keycard :card-connected?])
hash (get-in db [:keycard :hash])]
hash (get-in db [:keycard :hash])]
(if card-connected?
{:db (-> db
(assoc-in [:keycard :card-read-in-progress?] true)
(assoc-in [:signing/sign :keycard-step] :signing))
:keycard/sign-typed-data {:hash (ethereum/naked-address hash)}}
(fx/merge cofx
(rf/merge cofx
(common/set-on-card-connected :keycard/sign-typed-data)
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}))))
(fx/defn fetch-currency-token-on-success
(rf/defn fetch-currency-token-on-success
{:events [:keycard/fetch-currency-token-on-success]}
[{:keys [db]} {:keys [decimals symbol]}]
{:db (-> db
(assoc-in [:signing/sign :formatted-data :message :formatted-currency] symbol)
(update-in [:signing/sign :formatted-data :message]
#(assoc % :formatted-amount (.dividedBy ^js (money/bignumber (:amount %))
(money/bignumber (money/from-decimal decimals))))))})
#(assoc %
:formatted-amount
(.dividedBy ^js (money/bignumber (:amount %))
(money/bignumber (money/from-decimal decimals))))))})
(fx/defn store-hash-and-sign-typed
(rf/defn store-hash-and-sign-typed
{:events [:keycard/store-hash-and-sign-typed]}
[{:keys [db] :as cofx} result]
(let [{:keys [result]} (types/json->clj result)
message (get-in db [:signing/sign :formatted-data :message])
(let [{:keys [result]} (types/json->clj result)
message (get-in db [:signing/sign :formatted-data :message])
currency-contract (:currency message)]
(when currency-contract
{::json-rpc/call [{:method "wallet_discoverToken"
:params [(ethereum/chain-id db) currency-contract]
:on-success #(re-frame/dispatch [:keycard/fetch-currency-token-on-success %])}]})
(fx/merge cofx
{::json-rpc/call [{:method "wallet_discoverToken"
:params [(ethereum/chain-id db) currency-contract]
:on-success #(re-frame/dispatch [:keycard/fetch-currency-token-on-success
%])}]})
(rf/merge cofx
{:db (assoc-in db [:keycard :hash] result)}
sign-typed-data)))
(fx/defn prepare-to-sign
(rf/defn prepare-to-sign
{:events [:keycard/prepare-to-sign]}
[{:keys [db] :as cofx}]
(common/show-connection-sheet
@@ -125,30 +132,31 @@
{:on-card-connected :keycard/prepare-to-sign
:handler (common/get-application-info :keycard/sign)}))
(fx/defn sign-message-completed
(rf/defn sign-message-completed
[_ signature]
{:dispatch
[:signing/sign-message-completed signature]})
(fx/defn send-transaction-with-signature
(rf/defn send-transaction-with-signature
[_ data]
{:send-transaction-with-signature data})
(fx/defn on-sign-success
(rf/defn on-sign-success
{:events [:keycard.callback/on-sign-success]}
[{:keys [db] :as cofx} signature]
(log/debug "[keycard] sign success: " signature)
(let [signature-json (types/clj->json {:result (normalize-signature signature)})
transaction (get-in db [:keycard :transaction])
tx-obj (select-keys transaction [:from :to :value :gas :gasPrice :command? :chat-id :message-id])
tx-obj (select-keys transaction
[:from :to :value :gas :gasPrice :command? :chat-id :message-id])
command? (:command? transaction)]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :hash] nil)
(assoc-in [:keycard :transaction] nil))}
(when-not command?
(fn [{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc-in [:keycard :pin :sign] [])
@@ -163,18 +171,19 @@
:on-completed #(re-frame/dispatch [:signing/transaction-completed % tx-obj])})
(sign-message-completed signature-json)))))
(fx/defn on-sign-error
(rf/defn on-sign-error
{:events [:keycard.callback/on-sign-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] sign error: " error)
(let [tag-was-lost? (common/tag-lost? (:error error))
pin-retries (common/pin-retries (:error error))]
pin-retries (common/pin-retries (:error error))]
(when-not tag-was-lost?
(if (not (nil? pin-retries))
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
(update-in [:keycard :pin] assoc
(update-in [:keycard :pin]
assoc
:status :error
:sign []
:error-label :t/pin-mismatch)
@@ -182,6 +191,6 @@
(common/hide-connection-sheet)
(when (zero? pin-retries) (common/frozen-keycard-popup)))
(fx/merge cofx
(rf/merge cofx
(common/hide-connection-sheet)
(common/show-wrong-keycard-alert))))))
+101 -79
View File
@@ -1,42 +1,45 @@
(ns status-im.keycard.unpair
(:require [re-frame.core :as re-frame]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.i18n.i18n :as i18n]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]
[status-im.keycard.common :as common]
[status-im.multiaccounts.key-storage.core :as key-storage]))
[status-im.multiaccounts.key-storage.core :as key-storage]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn unpair-card-pressed
(rf/defn unpair-card-pressed
{:events [:keycard-settings.ui/unpair-card-pressed]}
[_]
{:ui/show-confirmation {:title (i18n/label :t/unpair-card)
:content (i18n/label :t/unpair-card-confirmation)
:confirm-button-text (i18n/label :t/yes)
:cancel-button-text (i18n/label :t/no)
:on-accept #(re-frame/dispatch [:keycard-settings.ui/unpair-card-confirmed])
:on-accept #(re-frame/dispatch
[:keycard-settings.ui/unpair-card-confirmed])
:on-cancel #()}})
(fx/defn unpair-card-confirmed
(rf/defn unpair-card-confirmed
{:events [:keycard-settings.ui/unpair-card-confirmed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (assoc-in db [:keycard :pin] {:enter-step :current
:current []
:puk []
:status nil
:error-label nil
:on-verified :keycard/unpair})}
(rf/merge cofx
{:db (assoc-in db
[:keycard :pin]
{:enter-step :current
:current []
:puk []
:status nil
:error-label nil
:on-verified :keycard/unpair})}
(common/navigate-to-enter-pin-screen)))
(fx/defn unpair
(rf/defn unpair
{:events [:keycard/unpair]}
[{:keys [db]}]
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
{:keycard/unpair {:pin pin}}))
(fx/defn unpair-and-delete
(rf/defn unpair-and-delete
{:events [:keycard/unpair-and-delete]}
[cofx]
(common/show-connection-sheet
@@ -44,55 +47,65 @@
{:on-card-connected :keycard/unpair-and-delete
:handler
(fn [{:keys [db]}]
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
{:keycard/unpair-and-delete
{:pin pin}}))}))
(fx/defn remove-pairing-from-multiaccount
(rf/defn remove-pairing-from-multiaccount
[cofx {:keys [remove-instance-uid?]}]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:keycard-pairing nil {})
:keycard-pairing
nil
{})
(multiaccounts.update/multiaccount-update
:keycard-paired-on nil {})
:keycard-paired-on
nil
{})
(when remove-instance-uid?
(multiaccounts.update/multiaccount-update
:keycard-instance-uid nil {}))))
:keycard-instance-uid
nil
{}))))
(fx/defn on-unpair-success
(rf/defn on-unpair-success
{:events [:keycard.callback/on-unpair-success]}
[{:keys [db] :as cofx}]
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
pairings (get-in db [:keycard :pairings])]
(fx/merge cofx
{:db (-> db
(assoc-in [:keycard :secrets] nil)
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
(assoc-in [:keycard :pin] {:status nil
:error-label nil
:on-verified nil}))
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
:utils/show-popup {:title ""
:content (i18n/label :t/card-unpaired)}}
(common/clear-on-card-connected)
(remove-pairing-from-multiaccount nil)
(navigation/navigate-to-cofx :keycard-settings nil))))
(rf/merge
cofx
{:db (-> db
(assoc-in [:keycard :secrets] nil)
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
(assoc-in [:keycard :pin]
{:status nil
:error-label nil
:on-verified nil}))
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
:utils/show-popup {:title ""
:content (i18n/label :t/card-unpaired)}}
(common/clear-on-card-connected)
(remove-pairing-from-multiaccount nil)
(navigation/navigate-to-cofx :keycard-settings nil))))
(fx/defn on-unpair-error
(rf/defn on-unpair-error
{:events [:keycard.callback/on-unpair-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] unpair error" error)
(fx/merge cofx
{:db (assoc-in db [:keycard :pin] {:status nil
:error-label nil
:on-verified nil})
(rf/merge cofx
{:db (assoc-in db
[:keycard :pin]
{:status nil
:error-label nil
:on-verified nil})
:keycard/get-application-info nil
:utils/show-popup {:title ""
:content (i18n/label :t/something-went-wrong)}}
:utils/show-popup {:title ""
:content (i18n/label :t/something-went-wrong)}}
(common/clear-on-card-connected)
(navigation/navigate-to-cofx :keycard-settings nil)))
(fx/defn remove-key-with-unpair
(rf/defn remove-key-with-unpair
{:events [:keycard/remove-key-with-unpair]}
[cofx]
(common/show-connection-sheet
@@ -100,66 +113,75 @@
{:on-card-connected :keycard/remove-key-with-unpair
:handler
(fn [{:keys [db]}]
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
{:keycard/remove-key-with-unpair
{:pin pin}}))}))
(defn handle-account-removal [{:keys [db] :as cofx} keys-removed-from-card?]
(let [key-uid (get-in db [:multiaccount :key-uid])
(defn handle-account-removal
[{:keys [db] :as cofx} keys-removed-from-card?]
(let [key-uid (get-in db [:multiaccount :key-uid])
instance-uid (get-in db [:keycard :application-info :instance-uid])
pairings (get-in db [:keycard :pairings])]
(fx/merge cofx
{:db (-> db
(update :multiaccounts/multiaccounts dissoc key-uid)
(assoc-in [:keycard :secrets] nil)
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
(update-in [:keycard :pairings] dissoc instance-uid)
(assoc-in [:keycard :whisper-public-key] nil)
(assoc-in [:keycard :wallet-address] nil)
(assoc-in [:keycard :application-info] nil)
(assoc-in [:keycard :pin] {:status nil
:error-label nil
:on-verified nil}))
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
:utils/show-popup {:title (i18n/label (if keys-removed-from-card? :t/profile-deleted-title :t/database-reset-title))
:content (i18n/label (if keys-removed-from-card? :t/profile-deleted-keycard :t/database-reset-content))
:on-dismiss #(re-frame/dispatch [:logout])}
::key-storage/delete-multiaccount {:key-uid key-uid
:on-success #(log/debug "[keycard] remove account ok")
:on-error #(log/warn "[keycard] remove account: " %)}}
(common/clear-on-card-connected)
(common/hide-connection-sheet))))
pairings (get-in db [:keycard :pairings])]
(rf/merge
cofx
{:db (-> db
(update :multiaccounts/multiaccounts dissoc key-uid)
(assoc-in [:keycard :secrets] nil)
(update-in [:keycard :pairings]
dissoc
(keyword instance-uid))
(update-in [:keycard :pairings] dissoc instance-uid)
(assoc-in [:keycard :whisper-public-key] nil)
(assoc-in [:keycard :wallet-address] nil)
(assoc-in [:keycard :application-info] nil)
(assoc-in [:keycard :pin]
{:status nil
:error-label nil
:on-verified nil}))
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
:utils/show-popup {:title (i18n/label (if keys-removed-from-card?
:t/profile-deleted-title
:t/database-reset-title))
:content (i18n/label (if keys-removed-from-card?
:t/profile-deleted-keycard
:t/database-reset-content))
:on-dismiss #(re-frame/dispatch [:logout])}
::key-storage/delete-multiaccount {:key-uid key-uid
:on-success #(log/debug "[keycard] remove account ok")
:on-error #(log/warn "[keycard] remove account: " %)}}
(common/clear-on-card-connected)
(common/hide-connection-sheet))))
(fx/defn on-remove-key-success
(rf/defn on-remove-key-success
{:events [:keycard.callback/on-remove-key-success]}
[cofx]
(handle-account-removal cofx true))
(fx/defn on-remove-key-error
(rf/defn on-remove-key-error
{:events [:keycard.callback/on-remove-key-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] remove key error" error)
(let [tag-was-lost? (common/tag-lost? (:error error))]
(fx/merge cofx
(rf/merge cofx
(if tag-was-lost?
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :pin :status] nil)}
(common/set-on-card-connected :keycard/remove-key-with-unpair))
(common/show-wrong-keycard-alert)))))
(fx/defn on-unpair-and-delete-success
(rf/defn on-unpair-and-delete-success
{:events [:keycard.callback/on-unpair-and-delete-success]}
[cofx]
(handle-account-removal cofx false))
(fx/defn on-unpair-and-delete-error
(rf/defn on-unpair-and-delete-error
{:events [:keycard.callback/on-unpair-and-delete-error]}
[{:keys [db] :as cofx} error]
(log/debug "[keycard] unpair and delete error" error)
(let [tag-was-lost? (common/tag-lost? (:error error))]
(fx/merge cofx
(rf/merge cofx
(if tag-was-lost?
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db [:keycard :pin :status] nil)}
(common/set-on-card-connected :keycard/unpair-and-delete))
(common/show-wrong-keycard-alert)))))
+17 -16
View File
@@ -1,37 +1,37 @@
(ns status-im.keycard.wallet
(:require [status-im.ethereum.core :as ethereum]
[status-im.utils.fx :as fx]
[status-im.keycard.common :as common]
(:require [status-im.bottom-sheet.core :as bottom-sheet]
[status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
[status-im.utils.hex :as utils.hex]
[status-im.keycard.common :as common]
[status-im.ui.screens.wallet.add-new.views :as add-new.views]
[status-im.bottom-sheet.core :as bottom-sheet]))
[status-im.utils.hex :as utils.hex]
[utils.re-frame :as rf]))
(fx/defn show-pin-sheet
(rf/defn show-pin-sheet
{:events [:keycard/new-account-pin-sheet]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc-in [:keycard :pin :enter-step] :export-key)
(update-in [:keycard :pin] dissoc :export-key))
{:db (-> db
(assoc-in [:keycard :pin :enter-step] :export-key)
(update-in [:keycard :pin] dissoc :export-key))
:dismiss-keyboard nil}
(bottom-sheet/show-bottom-sheet {:view {:content add-new.views/pin}})))
(fx/defn verify-pin-with-delay
(rf/defn verify-pin-with-delay
[cofx]
{:utils/dispatch-later
;; We need to give previous sheet some time to be fully hidden
[{:ms 200
[{:ms 200
:dispatch [:wallet.accounts/verify-pin]}]})
(fx/defn hide-pin-sheet
(rf/defn hide-pin-sheet
{:events [:keycard/new-account-pin-sheet-hide]}
[cofx]
(bottom-sheet/hide-bottom-sheet cofx))
(fx/defn generate-new-keycard-account
(rf/defn generate-new-keycard-account
{:events [:wallet.accounts/generate-new-keycard-account]}
[{:keys [db]}]
(let [path-num (inc (get-in db [:multiaccount :latest-derived-path]))
@@ -39,7 +39,8 @@
pin (common/vector->string (get-in db [:keycard :pin :export-key]))]
{:db
(assoc-in
db [:keycard :on-export-success]
db
[:keycard :on-export-success]
#(vector :wallet.accounts/account-stored
(let [public-key (utils.hex/normalize-hex %)]
{;; Strip leading 04 prefix denoting uncompressed key format
@@ -52,7 +53,7 @@
:keycard/export-key {:pin pin :path path}}))
(fx/defn verify-pin
(rf/defn verify-pin
{:events [:wallet.accounts/verify-pin]}
[cofx]
(common/verify-pin
+7 -6
View File
@@ -1,23 +1,24 @@
(ns status-im.log-level.core
(:require [re-frame.core :as re-frame]
[status-im.i18n.i18n :as i18n]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.node.core :as node]
[status-im.i18n.i18n :as i18n]
[status-im.utils.fx :as fx]))
[utils.re-frame :as rf]))
(fx/defn save-log-level
(rf/defn save-log-level
{:events [:log-level.ui/change-log-level-confirmed]}
[{:keys [db now] :as cofx} log-level]
(let [old-log-level (get-in db [:multiaccount :log-level])]
(when (not= old-log-level log-level)
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:log-level log-level
:log-level
log-level
{})
(node/prepare-new-config
{:on-success #(re-frame/dispatch [:logout])})))))
(fx/defn show-change-log-level-confirmation
(rf/defn show-change-log-level-confirmation
{:events [:log-level.ui/log-level-selected]}
[_ {:keys [name value]}]
{:ui/show-confirmation
+142 -119
View File
@@ -1,5 +1,4 @@
(ns ^{:doc "Mailserver events and API"}
status-im.mailserver.core
(ns ^{:doc "Mailserver events and API"} status-im.mailserver.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.ethereum.json-rpc :as json-rpc]
@@ -8,8 +7,8 @@
[status-im.node.core :as node]
[status-im.utils.mobile-sync :as mobile-network-utils]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
;; How do mailserver work ?
;;
@@ -24,22 +23,28 @@
;; as soon as the mailserver becomes available
(defn connected? [db id]
(defn connected?
[db id]
(= (:mailserver/current-id db) id))
(defn fetch [db id]
(defn fetch
[db id]
(get-in db [:mailserver/mailservers (node/current-fleet-key db) id]))
(defn fetch-current [db]
(defn fetch-current
[db]
(fetch db (:mailserver/current-id db)))
(defn preferred-mailserver-id [db]
(defn preferred-mailserver-id
[db]
(get-in db [:multiaccount :pinned-mailservers (node/current-fleet-key db)]))
(defn connection-error-dismissed [db]
(defn connection-error-dismissed
[db]
(get-in db [:mailserver/connection-error-dismissed]))
(defn mailserver-address->id [db address]
(defn mailserver-address->id
[db address]
(let [current-fleet (node/current-fleet-key db)]
(:id (some #(when (= address (:address %))
%)
@@ -48,19 +53,21 @@
current-fleet
vals)))))
(fx/defn disconnect-from-mailserver
(rf/defn disconnect-from-mailserver
{:events [::disconnect-from-mailserver]}
[{:keys [db] :as cofx}]
{:db (-> db
(assoc :mailserver/state nil)
(dissoc :mailserver/current-request :mailserver/fetching-gaps-in-progress))})
(defn fetch-use-mailservers? [{:keys [db]}]
(defn fetch-use-mailservers?
[{:keys [db]}]
(get-in db [:multiaccount :use-mailservers?]))
(defonce showing-connection-error-popup? (atom false))
(defn cancel-connection-popup! []
(defn cancel-connection-popup!
[]
(reset! showing-connection-error-popup? false)
(re-frame/dispatch [:mailserver.ui/dismiss-connection-error true]))
@@ -68,7 +75,8 @@
::cancel-connection-popup
cancel-connection-popup!)
(fx/defn show-connection-error! [cofx current-fleet preferred-mailserver]
(rf/defn show-connection-error!
[cofx current-fleet preferred-mailserver]
(reset! showing-connection-error-popup? true)
{:ui/show-confirmation
{:title (i18n/label :t/mailserver-error-title)
@@ -88,27 +96,28 @@
preferred-mailserver]))
:style "default"}]}})
(fx/defn handle-successful-request
(rf/defn handle-successful-request
{:events [::request-success]}
[{:keys [db] :as cofx} response-js]
{:db (dissoc db :mailserver/current-request)
:dispatch [:sanitize-messages-and-process-response response-js]})
(fx/defn handle-mailserver-not-working [{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
error-dismissed? (connection-error-dismissed db)
pinned-mailserver (get-in db [:multiaccount :pinned-mailservers current-fleet])]
(rf/defn handle-mailserver-not-working
[{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
error-dismissed? (connection-error-dismissed db)
pinned-mailserver (get-in db [:multiaccount :pinned-mailservers current-fleet])]
(when (and pinned-mailserver
(not error-dismissed?)
(not @showing-connection-error-popup?))
(show-connection-error! cofx current-fleet pinned-mailserver))))
(fx/defn handle-request-error
(rf/defn handle-request-error
{:events [::request-error]}
[{:keys [db] :as cofx}]
{:db (dissoc db :mailserver/current-request)})
(fx/defn process-next-messages-request
(rf/defn process-next-messages-request
{:events [::request-messages]}
[{:keys [db now] :as cofx}]
(when (and
@@ -116,93 +125,99 @@
(mobile-network-utils/syncing-allowed? cofx)
(fetch-use-mailservers? cofx)
(not (:mailserver/current-request db)))
{:db (assoc db :mailserver/current-request true)
::json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
:params []
{:db (assoc db :mailserver/current-request true)
::json-rpc/call [{:method "wakuext_requestAllHistoricMessagesWithRetries"
:params []
:js-response true
:on-success #(do
(log/info "fetched historical messages")
(re-frame/dispatch [::request-success %]))
:on-error #(do
(log/error "failed retrieve historical messages" %)
(re-frame/dispatch [::request-error]))}]}))
:on-success #(do
(log/info "fetched historical messages")
(re-frame/dispatch [::request-success %]))
:on-error #(do
(log/error "failed retrieve historical messages" %)
(re-frame/dispatch [::request-error]))}]}))
(fx/defn handle-mailserver-changed
(rf/defn handle-mailserver-changed
[{:keys [db] :as cofx} ms]
(if (seq ms)
{:db (assoc db :mailserver/state :connecting
{:db (assoc db
:mailserver/state :connecting
:mailserver/current-id (keyword ms))}
{:db (assoc db :mailserver/state nil)}))
(fx/defn handle-mailserver-available
(rf/defn handle-mailserver-available
[{:keys [db] :as cofx} ms]
{::cancel-connection-popup []
:db (assoc db :mailserver/state :connected
:mailserver/current-id (keyword ms))})
:db (assoc db
:mailserver/state :connected
:mailserver/current-id (keyword ms))})
(fx/defn connected-to-mailserver
(rf/defn connected-to-mailserver
[{:keys [db] :as cofx}]
(let [{:keys [address]} (fetch-current db)]
(fx/merge
(let [{:keys [address]} (fetch-current db)]
(rf/merge
cofx
{:mailserver/update-mailservers [[address] #(re-frame/dispatch [::request-messages])]})))
(fx/defn handle-request-success
(rf/defn handle-request-success
{:events [:mailserver.callback/request-success]}
[{{:keys [chats] :as db} :db} {:keys [request-id topics]}]
(when (:mailserver/current-request db)
{:db (assoc-in db [:mailserver/current-request :request-id]
request-id)}))
{:db (assoc-in db
[:mailserver/current-request :request-id]
request-id)}))
(fx/defn toggle-use-mailservers
(rf/defn toggle-use-mailservers
[cofx value]
{::json-rpc/call
[{:method "wakuext_toggleUseMailservers"
:params [value]
[{:method "wakuext_toggleUseMailservers"
:params [value]
:on-success #(log/info "successfully toggled use-mailservers" value)
:on-failure #(log/error "failed to toggle use-mailserver" value %)}]})
(fx/defn update-use-mailservers
(rf/defn update-use-mailservers
{:events [:mailserver.ui/use-history-switch-pressed]}
[cofx use-mailservers?]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/optimistic :use-mailservers? use-mailservers?)
(toggle-use-mailservers use-mailservers?)
(when use-mailservers?
(disconnect-from-mailserver))))
(fx/defn retry-next-messages-request
(rf/defn retry-next-messages-request
{:events [:mailserver.ui/retry-request-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :mailserver/request-error)}
(process-next-messages-request)))
(fx/defn show-request-error-popup
(rf/defn show-request-error-popup
{:events [:mailserver.ui/request-error-pressed]}
[{:keys [db]}]
(let [mailserver-error (:mailserver/request-error db)]
{:utils/show-confirmation
{:title (i18n/label :t/mailserver-request-error-title)
:content (i18n/label :t/mailserver-request-error-content
{:error mailserver-error})
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
{:title (i18n/label :t/mailserver-request-error-title)
:content (i18n/label :t/mailserver-request-error-content
{:error mailserver-error})
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
:confirm-button-text (i18n/label :t/mailserver-request-retry)}}))
(def enode-url-regex
#"enode://[a-zA-Z0-9]+\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
(defn- extract-url-components [address]
(defn- extract-url-components
[address]
(rest (re-matches #"enode://(.*)@(.*)" address)))
(defn valid-enode-url? [address]
(defn valid-enode-url?
[address]
(re-matches enode-url-regex address))
(defn build-url [address]
(defn build-url
[address]
(let [[initial host] (extract-url-components address)]
(str "enode://" initial "@" host)))
(fx/defn set-input
(rf/defn set-input
{:events [:mailserver.ui/input-changed]}
[{:keys [db]} input-key value]
{:db (update
@@ -216,26 +231,28 @@
:name (string/blank? value)
:url (not (valid-enode-url? value)))})})
(defn- address->mailserver [address]
(defn- address->mailserver
[address]
(let [[enode url :as response] (extract-url-components address)]
{:address (if (seq response)
(str "enode://" enode "@" url)
address)
:custom true}))
:custom true}))
(defn- build [id mailserver-name address]
(defn- build
[id mailserver-name address]
(assoc (address->mailserver address)
:id id
:id id
:name mailserver-name))
(def default? (comp not :custom fetch))
(fx/defn edit
(rf/defn edit
{:events [:mailserver.ui/custom-mailserver-selected]}
[{:keys [db] :as cofx} id]
(let [{:keys [id address name]} (fetch db id)
url (when address (build-url address))]
(fx/merge cofx
url (when address (build-url address))]
(rf/merge cofx
(set-input :id id)
(set-input :url (str url))
(set-input :name (str name))
@@ -247,14 +264,15 @@
(assoc :fleet (name current-fleet))
(update :id name)))
(fx/defn upsert
{:events [:mailserver.ui/save-pressed]
(rf/defn upsert
{:events [:mailserver.ui/save-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:mailserver.edit/keys [mailserver] :keys [multiaccount] :as db} :db
random-id-generator :random-id-generator :as cofx}]
random-id-generator :random-id-generator
:as cofx}]
(let [{:keys [name url id]} mailserver
current-fleet (node/current-fleet-key db)]
current-fleet (node/current-fleet-key db)]
(when (and (not (string/blank? (:value name)))
(valid-enode-url? (:value url)))
@@ -263,14 +281,14 @@
(keyword (string/replace (random-id-generator) "-" "")))
(:value name)
(:value url))
current (connected? db (:id mailserver))]
{:db (-> db
(dissoc :mailserver.edit/mailserver)
(assoc-in [:mailserver/mailservers current-fleet (:id mailserver)]
mailserver))
current (connected? db (:id mailserver))]
{:db (-> db
(dissoc :mailserver.edit/mailserver)
(assoc-in [:mailserver/mailservers current-fleet (:id mailserver)]
mailserver))
::json-rpc/call
[{:method "mailservers_addMailserver"
:params [(mailserver->rpc mailserver current-fleet)]
[{:method "mailservers_addMailserver"
:params [(mailserver->rpc mailserver current-fleet)]
:on-success (fn []
;; we naively logout if the user is connected to
;; the edited mailserver
@@ -279,47 +297,49 @@
[:multiaccounts.logout.ui/logout-confirmed]))
(log/debug "saved mailserver" id "successfuly"))
:on-failure #(log/error "failed to save mailserver" id %)}]
:dispatch [:navigate-back]}))))
:dispatch [:navigate-back]}))))
(defn can-delete?
[db id]
(not (or (default? db id)
(connected? db id))))
(fx/defn delete
(rf/defn delete
{:events [:mailserver.ui/delete-confirmed]}
[{:keys [db] :as cofx} id]
(if (can-delete? db id)
{:db (-> db
(update-in
[:mailserver/mailservers (node/current-fleet-key db)]
dissoc id)
(dissoc :mailserver.edit/mailserver))
{:db (-> db
(update-in
[:mailserver/mailservers (node/current-fleet-key db)]
dissoc
id)
(dissoc :mailserver.edit/mailserver))
::json-rpc/call
[{:method "mailservers_deleteMailserver"
:params [(name id)]
[{:method "mailservers_deleteMailserver"
:params [(name id)]
:on-success #(log/debug "deleted mailserver" id)
:on-failure #(log/error "failed to delete mailserver" id %)}]
:dispatch [:navigate-back]}
:dispatch [:navigate-back]}
{:dispatch [:navigate-back]}))
(fx/defn show-connection-confirmation
(rf/defn show-connection-confirmation
{:events [:mailserver.ui/default-mailserver-selected :mailserver.ui/connect-pressed]}
[{:keys [db]} mailserver-id]
(let [current-fleet (node/current-fleet-key db)]
{:ui/show-confirmation
{:title (i18n/label :t/close-app-title)
{:title (i18n/label :t/close-app-title)
:content
(i18n/label :t/connect-mailserver-content
{:name (get-in db [:mailserver/mailservers
current-fleet mailserver-id :name])})
{:name (get-in db
[:mailserver/mailservers
current-fleet mailserver-id :name])})
:confirm-button-text (i18n/label :t/close-app-button)
:on-accept
#(re-frame/dispatch
[:mailserver.ui/connect-confirmed current-fleet mailserver-id])
:on-cancel nil}}))
:on-cancel nil}}))
(fx/defn show-delete-confirmation
(rf/defn show-delete-confirmation
{:events [:mailserver.ui/delete-pressed]}
[{:keys [db]} mailserver-id]
{:ui/show-confirmation
@@ -329,64 +349,67 @@
:on-accept #(re-frame/dispatch
[:mailserver.ui/delete-confirmed mailserver-id])}})
(fx/defn set-url-from-qr
(rf/defn set-url-from-qr
{:events [:mailserver.callback/qr-code-scanned]}
[cofx url]
(assoc (set-input cofx :url url)
:dispatch [:navigate-back]))
:dispatch
[:navigate-back]))
(fx/defn dismiss-connection-error
(rf/defn dismiss-connection-error
{:events [:mailserver.ui/dismiss-connection-error]}
[{:keys [db]} new-state]
{:db (assoc db :mailserver/connection-error-dismissed new-state)})
(fx/defn pin-mailserver
(rf/defn pin-mailserver
{:events [:mailserver.ui/connect-confirmed]}
[{:keys [db] :as cofx} current-fleet mailserver-id]
(let [pinned-mailservers (-> db
(get-in [:multiaccount :pinned-mailservers])
(assoc current-fleet mailserver-id))]
(fx/merge cofx
{:db (assoc db :mailserver/current-id mailserver-id)
::json-rpc/call [{:method "wakuext_setPinnedMailservers"
:params [pinned-mailservers]
(rf/merge cofx
{:db (assoc db :mailserver/current-id mailserver-id)
::json-rpc/call [{:method "wakuext_setPinnedMailservers"
:params [pinned-mailservers]
:on-success #(log/info "successfully pinned mailserver")
:on-error #(log/error "failed to pin mailserver" %)}]}
:on-error #(log/error "failed to pin mailserver" %)}]}
(multiaccounts.update/optimistic :pinned-mailservers pinned-mailservers))))
(fx/defn unpin
(rf/defn unpin
{:events [:mailserver.ui/unpin-pressed]}
[{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
pinned-mailservers (-> db
(get-in [:multiaccount :pinned-mailservers])
(dissoc current-fleet))]
(fx/merge cofx
{::json-rpc/call [{:method "wakuext_setPinnedMailservers"
:params [pinned-mailservers]
(let [current-fleet (node/current-fleet-key db)
pinned-mailservers (-> db
(get-in [:multiaccount :pinned-mailservers])
(dissoc current-fleet))]
(rf/merge cofx
{::json-rpc/call [{:method "wakuext_setPinnedMailservers"
:params [pinned-mailservers]
:on-success #(log/info "successfully unpinned mailserver")
:on-error #(log/error "failed to unpin mailserver" %)}]}
:on-error #(log/error "failed to unpin mailserver" %)}]}
(multiaccounts.update/optimistic
:pinned-mailservers pinned-mailservers)
:pinned-mailservers
pinned-mailservers)
(dismiss-connection-error false))))
(fx/defn pin
(rf/defn pin
{:events [:mailserver.ui/pin-pressed]}
[{:keys [db] :as cofx}]
(let [current-fleet (node/current-fleet-key db)
mailserver-id (:mailserver/current-id db)
(let [current-fleet (node/current-fleet-key db)
mailserver-id (:mailserver/current-id db)
pinned-mailservers (get-in db [:multiaccount :pinned-mailservers])]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:pinned-mailservers (assoc pinned-mailservers
current-fleet
mailserver-id)
:pinned-mailservers
(assoc pinned-mailservers
current-fleet
mailserver-id)
{})
(dismiss-connection-error false))))
(fx/defn mailserver-ui-add-pressed
(rf/defn mailserver-ui-add-pressed
{:events [:mailserver.ui/add-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :mailserver.edit/mailserver)}
(navigation/navigate-to-cofx :edit-mailserver nil)))
+37 -32
View File
@@ -1,28 +1,29 @@
(ns status-im.mobile-sync-settings.core
(:require
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[status-im.wallet.core :as wallet]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im2.navigation.events :as navigation]
[status-im.mailserver.core :as mailserver]
[status-im.utils.mobile-sync :as utils]
[taoensso.timbre :as log]))
(:require [status-im.bottom-sheet.core :as bottom-sheet]
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.mobile-sync :as utils]
[status-im.wallet.core :as wallet]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(fx/defn sheet-defaults
(rf/defn sheet-defaults
[{:keys [db]}]
(let [remember-choice? (get-in db [:multiaccount :remember-syncing-choice?])]
{:db (assoc db :mobile-network/remember-choice? (or (nil? remember-choice?)
remember-choice?))}))
{:db (assoc db
:mobile-network/remember-choice?
(or (nil? remember-choice?)
remember-choice?))}))
(fx/defn on-network-status-change
(rf/defn on-network-status-change
[{:keys [db] :as cofx}]
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? cofx)
(let [initialized? (get db :network-status/initialized?)
logged-in? (multiaccounts.model/logged-in? cofx)
{:keys [remember-syncing-choice?]} (:multiaccount db)]
(apply
fx/merge
rf/merge
cofx
{:db (assoc db :network-status/initialized? true)}
(cond
@@ -51,67 +52,71 @@
([sync?] (apply-settings sync? :default))
([sync? remember?]
(fn [{:keys [db] :as cofx}]
(let [network (:network/type db)
(let [network (:network/type db)
remember-choice?
(if (not= :default remember?)
remember?
(:mobile-network/remember-choice? db))
cellular? (utils/cellular? network)]
cellular? (utils/cellular? network)]
(log/info "apply mobile network settings"
"sunc?" sync?
"sunc?" sync?
"remember?" remember?
"cellular?" cellular?)
(fx/merge
(rf/merge
cofx
(multiaccounts.update/multiaccount-update
:syncing-on-mobile-network? (boolean sync?) {})
:syncing-on-mobile-network?
(boolean sync?)
{})
(multiaccounts.update/multiaccount-update
:remember-syncing-choice? (boolean remember-choice?) {})
:remember-syncing-choice?
(boolean remember-choice?)
{})
(when (and cellular? sync?)
(mailserver/process-next-messages-request))
(wallet/restart-wallet-service nil))))))
(fx/defn mobile-network-continue-syncing
(rf/defn mobile-network-continue-syncing
{:events [:mobile-network/continue-syncing]}
[cofx]
((apply-settings true) cofx))
(fx/defn mobile-network-stop-syncing
(rf/defn mobile-network-stop-syncing
{:events [:mobile-network/stop-syncing]}
[cofx]
((apply-settings false) cofx))
(fx/defn mobile-network-set-syncing
(rf/defn mobile-network-set-syncing
{:events [:mobile-network/set-syncing]}
[{:keys [db] :as cofx} syncing?]
(let [{:keys [remember-syncing-choice?]} (:multiaccount db)]
((apply-settings syncing? remember-syncing-choice?) cofx)))
(fx/defn mobile-network-ask-on-mobile-network?
(rf/defn mobile-network-ask-on-mobile-network?
{:events [:mobile-network/ask-on-mobile-network?]}
[{:keys [db] :as cofx} ask?]
(let [{:keys [syncing-on-mobile-network?]} (:multiaccount db)]
((apply-settings syncing-on-mobile-network? (not ask?)) cofx)))
(fx/defn mobile-network-restore-defaults
(rf/defn mobile-network-restore-defaults
{:events [:mobile-network/restore-defaults]}
[cofx]
((apply-settings false false) cofx))
(fx/defn mobile-network-remember-choice?
(rf/defn mobile-network-remember-choice?
{:events [:mobile-network/remember-choice?]}
[{:keys [db]} remember-choice?]
{:db (assoc db :mobile-network/remember-choice? remember-choice?)})
(fx/defn mobile-network-navigate-to-settings
(rf/defn mobile-network-navigate-to-settings
{:events [:mobile-network/navigate-to-settings]}
[cofx]
(fx/merge
(rf/merge
cofx
(bottom-sheet/hide-bottom-sheet)
(navigation/navigate-to-cofx :mobile-network-settings nil)))
(fx/defn mobile-network-show-offline-sheet
(rf/defn mobile-network-show-offline-sheet
{:events [:mobile-network/show-offline-sheet]}
[cofx]
(bottom-sheet/show-bottom-sheet
+35 -28
View File
@@ -1,14 +1,14 @@
(ns status-im.multiaccounts.biometric.core
(:require [re-frame.core :as re-frame]
(:require ["react-native-touch-id" :default touchid]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.i18n.i18n :as i18n]
[status-im.native-module.core :as status]
[status-im.popover.core :as popover]
[quo.design-system.colors :as colors]
[status-im.utils.fx :as fx]
[status-im.utils.keychain.core :as keychain]
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]
["react-native-touch-id" :default touchid]))
[utils.re-frame :as rf]))
;; currently, for android, react-native-touch-id
;; is not returning supported biometric type
@@ -28,11 +28,12 @@
(def android-device-blacklisted?
(cond
(= (:brand deviceinfo) "bannedbrand") true
:else false))
:else false))
;; biometric auth config
;; https://github.com/naoufal/react-native-touch-id#authenticatereason-config
(defn- authenticate-options [ios-fallback-label]
(defn- authenticate-options
[ios-fallback-label]
(clj->js (merge
{:unifiedErrors true}
(when platform/ios?
@@ -46,7 +47,8 @@
:sensorErrorDescription (i18n/label :t/biometric-auth-android-sensor-error-desc)
:cancelText (i18n/label :cancel)}))))
(defn get-label [supported-biometric-auth]
(defn get-label
[supported-biometric-auth]
(case supported-biometric-auth
:fingerprint (i18n/label :t/biometric-fingerprint)
:FaceID (i18n/label :t/biometric-faceid)
@@ -61,29 +63,33 @@
(= touchid-error-code "USER_FALLBACK") nil
;; add here more specific errors if needed
;; https://github.com/naoufal/react-native-touch-id#unified-errors
:else (i18n/label :t/biometric-auth-error {:code touchid-error-code})))
:else (i18n/label :t/biometric-auth-error
{:code touchid-error-code})))
(def success-result
{:bioauth-success true})
(defn- generate-error-result [touchid-error-obj]
(defn- generate-error-result
[touchid-error-obj]
(let [code (aget touchid-error-obj "code")]
{:bioauth-success false
:bioauth-code code
:bioauth-message (get-error-message code)}))
(defn- do-get-supported [callback]
(defn- do-get-supported
[callback]
(-> (.isSupported touchid)
(.then #(callback (or (keyword %) android-default-support)))
(.catch #(callback nil))))
(defn get-supported [callback]
(defn get-supported
[callback]
(log/debug "[biometric] get-supported")
(cond platform/ios? (do-get-supported callback)
(cond platform/ios? (do-get-supported callback)
platform/android? (if android-device-blacklisted?
(callback nil)
(do-get-supported callback))
:else (callback nil)))
:else (callback nil)))
(defn authenticate-fx
([cb]
@@ -105,12 +111,12 @@
(get-supported callback)
(callback nil)))))))
(fx/defn set-supported-biometric-auth
(rf/defn set-supported-biometric-auth
{:events [:init.callback/get-supported-biometric-auth-success]}
[{:keys [db]} supported-biometric-auth]
{:db (assoc db :supported-biometric-auth supported-biometric-auth)})
(fx/defn authenticate
(rf/defn authenticate
[_ cb options]
{:biometric-auth/authenticate [cb options]})
@@ -119,10 +125,11 @@
(fn [[cb options]]
(authenticate-fx #(cb %) options)))
(fx/defn update-biometric [{db :db :as cofx} biometric-auth?]
(rf/defn update-biometric
[{db :db :as cofx} biometric-auth?]
(let [key-uid (or (get-in db [:multiaccount :key-uid])
(get-in db [:multiaccounts/login :key-uid]))]
(fx/merge cofx
(rf/merge cofx
(keychain/save-auth-method
key-uid
(if biometric-auth?
@@ -131,7 +138,7 @@
#(when-not biometric-auth?
{:keychain/clear-user-password key-uid}))))
(fx/defn biometric-auth-switched
(rf/defn biometric-auth-switched
{:events [:multiaccounts.ui/biometric-auth-switched]}
[cofx biometric-auth?]
(if biometric-auth?
@@ -141,17 +148,17 @@
{})
(update-biometric cofx false)))
(fx/defn show-message
(rf/defn show-message
[cofx bioauth-message bioauth-code]
(let [content (or (when (get #{"NOT_AVAILABLE" "NOT_ENROLLED"} bioauth-code)
(i18n/label :t/grant-face-id-permissions))
bioauth-message)]
(when content
{:utils/show-popup
{:title (i18n/label :t/biometric-auth-login-error-title)
{:title (i18n/label :t/biometric-auth-login-error-title)
:content content}})))
(fx/defn biometric-init-done
(rf/defn biometric-init-done
{:events [:biometric-init-done]}
[cofx {:keys [bioauth-success bioauth-message bioauth-code]}]
(if bioauth-success
@@ -161,7 +168,7 @@
(popover/show-popover cofx {:view :enable-biometric}))
(show-message cofx bioauth-message bioauth-code)))
(fx/defn biometric-auth
(rf/defn biometric-auth
{:events [:biometric-authenticate]}
[cofx]
(authenticate
@@ -170,31 +177,31 @@
{:reason (i18n/label :t/biometric-auth-reason-login)
:ios-fallback-label (i18n/label :t/biometric-auth-login-ios-fallback-label)}))
(fx/defn enable
(rf/defn enable
{:events [:biometric/enable]}
[cofx]
(fx/merge
(rf/merge
cofx
(popover/hide-popover)
(authenticate #(re-frame/dispatch [:biometric/setup-done %]) {})))
(fx/defn disable
(rf/defn disable
{:events [:biometric/disable]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc :auth-method keychain/auth-method-none)
(assoc-in [:multiaccounts/login :save-password?] false))}
(popover/hide-popover)))
(fx/defn setup-done
(rf/defn setup-done
{:events [:biometric/setup-done]}
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
(log/debug "[biometric] setup-done"
"bioauth-success" bioauth-success
"bioauth-message" bioauth-message
"bioauth-code" bioauth-code)
"bioauth-code" bioauth-code)
(if bioauth-success
{:db (assoc db :auth-method keychain/auth-method-biometric-prepare)}
(show-message cofx bioauth-message bioauth-code)))
+63 -46
View File
@@ -1,19 +1,19 @@
(ns status-im.multiaccounts.core
(:require [re-frame.core :as re-frame]
(:require [clojure.string :as string]
[quo.platform :as platform]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.native-module.core :as native-module]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[status-im.theme.core :as theme]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.identicon :as identicon]
[status-im.theme.core :as theme]
[status-im.utils.utils :as utils]
[quo.platform :as platform]
[status-im2.common.theme.core :as utils.theme]
[taoensso.timbre :as log]
[clojure.string :as string]
[status-im2.common.theme.core :as utils.theme]))
[utils.re-frame :as rf]))
;; validate that the given mnemonic was generated from Status Dictionary
(re-frame/reg-fx
@@ -35,7 +35,7 @@
(cond-> {:nickname nickname
:display-name display-name
:three-words-name (or alias (gfycat/generate-gfy public-key))}
;; Preferred name is our own otherwise we make sure it's verified
;; Preferred name is our own otherwise we make sure it's verified
(or preferred-name (and ens-verified name))
(assoc :ens-name (str "@" (or (stateofus/username ens-name) ens-name))))))
@@ -48,7 +48,8 @@
(let [{:keys [nickname
ens-name
display-name
three-words-name]} (or names (contact-names contact))
three-words-name]}
(or names (contact-names contact))
short-public-key (when public-key? (utils/get-shortened-address public-key))]
(->> [nickname ens-name display-name three-words-name short-public-key]
(remove string/blank?)
@@ -70,11 +71,13 @@
(str "@" (or username ens-name)))
(or alias (gfycat/generate-gfy public-key)))))
(defn contact-by-identity [contacts identity]
(defn contact-by-identity
[contacts identity]
(or (get contacts identity)
(contact-with-names {:public-key identity})))
(defn contact-two-names-by-identity [contact current-multiaccount identity]
(defn contact-two-names-by-identity
[contact current-multiaccount identity]
(let [me? (= (:public-key current-multiaccount) identity)]
(if me?
[(or (:preferred-name current-multiaccount)
@@ -110,53 +113,61 @@
(fn [flag]
(native-module/set-blank-preview-flag flag)))
(fx/defn confirm-wallet-set-up
(rf/defn confirm-wallet-set-up
{:events [:multiaccounts.ui/wallet-set-up-confirmed]}
[cofx]
(multiaccounts.update/multiaccount-update cofx
:wallet-set-up-passed? true {}))
:wallet-set-up-passed?
true
{}))
(fx/defn confirm-home-tooltip
(rf/defn confirm-home-tooltip
{:events [:multiaccounts.ui/hide-home-tooltip]}
[cofx]
(multiaccounts.update/multiaccount-update cofx
:hide-home-tooltip? true {}))
:hide-home-tooltip?
true
{}))
(fx/defn switch-webview-debug
(rf/defn switch-webview-debug
{:events [:multiaccounts.ui/switch-webview-debug]}
[{:keys [db] :as cofx} value]
(fx/merge cofx
(rf/merge cofx
{::webview-debug-changed value}
(multiaccounts.update/multiaccount-update
:webview-debug (boolean value)
:webview-debug
(boolean value)
{})))
(fx/defn switch-preview-privacy-mode
(rf/defn switch-preview-privacy-mode
{:events [:multiaccounts.ui/preview-privacy-mode-switched]}
[{:keys [db] :as cofx} private?]
(fx/merge cofx
(rf/merge cofx
{::blank-preview-flag-changed private?}
(multiaccounts.update/multiaccount-update
:preview-privacy? (boolean private?)
:preview-privacy?
(boolean private?)
{})))
(fx/defn switch-webview-permission-requests?
(rf/defn switch-webview-permission-requests?
{:events [:multiaccounts.ui/webview-permission-requests-switched]}
[cofx enabled?]
(multiaccounts.update/multiaccount-update
cofx
:webview-allow-permission-requests? (boolean enabled?)
:webview-allow-permission-requests?
(boolean enabled?)
{}))
(fx/defn switch-default-sync-period
(rf/defn switch-default-sync-period
{:events [:multiaccounts.ui/default-sync-period-switched]}
[cofx value]
(multiaccounts.update/multiaccount-update
cofx
:default-sync-period value
:default-sync-period
value
{}))
(fx/defn switch-preview-privacy-mode-flag
(rf/defn switch-preview-privacy-mode-flag
[{:keys [db]}]
(let [private? (get-in db [:multiaccount :preview-privacy?])]
{::blank-preview-flag-changed private?}))
@@ -169,48 +180,49 @@
:light)]
(theme/change-theme theme))))
(fx/defn switch-appearance
(rf/defn switch-appearance
{:events [:multiaccounts.ui/appearance-switched]}
[cofx theme]
(fx/merge cofx
(rf/merge cofx
{:multiaccounts.ui/switch-theme theme}
(multiaccounts.update/multiaccount-update :appearance theme {})))
(fx/defn switch-profile-picture-show-to
(rf/defn switch-profile-picture-show-to
{:events [:multiaccounts.ui/profile-picture-show-to-switched]}
[cofx id]
(fx/merge cofx
{::json-rpc/call [{:method "wakuext_changeIdentityImageShowTo"
:params [id]
(rf/merge cofx
{::json-rpc/call [{:method "wakuext_changeIdentityImageShowTo"
:params [id]
:on-success #(log/debug "picture settings changed successfully")}]}
(multiaccounts.update/optimistic :profile-pictures-show-to id)))
(fx/defn switch-appearance-profile
(rf/defn switch-appearance-profile
{:events [:multiaccounts.ui/appearance-profile-switched]}
[cofx id]
(multiaccounts.update/multiaccount-update cofx :profile-pictures-visibility id {}))
(defn clean-path [path]
(defn clean-path
[path]
(if path
(string/replace-first path #"file://" "")
(log/warn "[native-module] Empty path was provided")))
(fx/defn save-profile-picture
(rf/defn save-profile-picture
{:events [::save-profile-picture]}
[cofx path ax ay bx by]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(fx/merge cofx
(rf/merge cofx
{::json-rpc/call [{:method "multiaccounts_storeIdentityImage"
:params [key-uid (clean-path path) ax ay bx by]
;; NOTE: In case of an error we can show a toast error
:on-success #(re-frame/dispatch [::update-local-picture %])}]}
(bottom-sheet/hide-bottom-sheet))))
(fx/defn save-profile-picture-from-url
(rf/defn save-profile-picture-from-url
{:events [::save-profile-picture-from-url]}
[cofx url]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(fx/merge cofx
(rf/merge cofx
{::json-rpc/call [{:method "multiaccounts_storeIdentityImageFromURL"
:params [key-uid url]
:on-error #(log/error "::save-profile-picture-from-url error" %)
@@ -218,32 +230,37 @@
(bottom-sheet/hide-bottom-sheet))))
(comment
(re-frame/dispatch [::save-profile-picture-from-url "https://lh3.googleusercontent.com/XuKjNm3HydsaxbPkbpGs9YyCKhn5QQk5oDC8XF2jzmPyYXeZofxFtfUDZuQ3EVmacS_BlBKzbX2ypm37YNX3n1fDJA3WndeFcPsp7Z0=w600"]))
(re-frame/dispatch
[::save-profile-picture-from-url
"https://lh3.googleusercontent.com/XuKjNm3HydsaxbPkbpGs9YyCKhn5QQk5oDC8XF2jzmPyYXeZofxFtfUDZuQ3EVmacS_BlBKzbX2ypm37YNX3n1fDJA3WndeFcPsp7Z0=w600"]))
(fx/defn delete-profile-picture
(rf/defn delete-profile-picture
{:events [::delete-profile-picture]}
[cofx name]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
(fx/merge cofx
(rf/merge cofx
{::json-rpc/call [{:method "multiaccounts_deleteIdentityImage"
:params [key-uid]
;; NOTE: In case of an error we could fallback to previous image in UI with a toast error
;; NOTE: In case of an error we could fallback to previous image in UI
;; with a toast error
:on-success #(log/info "[multiaccount] Delete profile image" %)}]}
(multiaccounts.update/optimistic :images nil)
(bottom-sheet/hide-bottom-sheet))))
(fx/defn get-profile-picture
(rf/defn get-profile-picture
[cofx]
(let [key-uid (get-in cofx [:db :multiaccount :key-uid])]
{::json-rpc/call [{:method "multiaccounts_getIdentityImages"
:params [key-uid]
:on-success #(re-frame/dispatch [::update-local-picture %])}]}))
(fx/defn store-profile-picture
(rf/defn store-profile-picture
{:events [::update-local-picture]}
[cofx pics]
(multiaccounts.update/optimistic cofx :images pics))
(comment
;; Test seed for Dim Venerated Yaffle, it's not here by mistake, this is just a test account
(native-module/validate-mnemonic "rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo" prn))
(native-module/validate-mnemonic
"rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo"
prn))
+96 -86
View File
@@ -1,5 +1,6 @@
(ns status-im.multiaccounts.create.core
(:require [re-frame.core :as re-frame]
(:require [quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.data-store.settings :as data-store.settings]
[status-im.ethereum.core :as ethereum]
@@ -7,26 +8,27 @@
[status-im.i18n.i18n :as i18n]
[status-im.native-module.core :as status]
[status-im.node.core :as node]
[quo.design-system.colors :as colors]
[status-im.utils.config :as config]
[status-im.utils.fx :as fx]
[status-im.utils.security :as security]
[status-im.utils.signing-phrase.core :as signing-phrase]
[status-im.utils.types :as types]))
[status-im.utils.types :as types]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn normalize-derived-data-keys [derived-data]
(defn normalize-derived-data-keys
[derived-data]
(->> derived-data
(map (fn [[path {:keys [publicKey] :as data}]]
[path (cond-> (-> data
(dissoc :publicKey)
(assoc :public-key publicKey)))]))
[path
(cond-> (-> data
(dissoc :publicKey)
(assoc :public-key publicKey)))]))
(into {})))
(defn normalize-multiaccount-data-keys
[{:keys [publicKey keyUid derived] :as data}]
(cond-> (-> data
(dissoc :keyUid :publicKey)
(assoc :key-uid keyUid
(assoc :key-uid keyUid
:public-key publicKey))
derived
(update :derived normalize-derived-data-keys)))
@@ -49,7 +51,7 @@
hashed-password
callback)))
(fx/defn create-multiaccount
(rf/defn create-multiaccount
{:events [:create-multiaccount]}
[{:keys [db]} key-code]
(let [{:keys [selected-id]} (:intro-wizard db)]
@@ -63,14 +65,14 @@
(ethereum/sha3 (security/safe-unmask-data key-code))
(fn [result]
(let [derived-data (normalize-derived-data-keys (types/json->clj result))
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
(status/gfycat-identicon-async
public-key
(fn [name identicon]
(let [derived-whisper (derived-data constants/path-whisper-keyword)
(let [derived-whisper (derived-data constants/path-whisper-keyword)
derived-data-extended (assoc-in derived-data
[constants/path-whisper-keyword]
(merge derived-whisper {:name name :identicon identicon}))]
[constants/path-whisper-keyword]
(merge derived-whisper {:name name :identicon identicon}))]
(re-frame/dispatch [::store-multiaccount-success key-code derived-data-extended]))))))]}))
(re-frame/reg-fx
@@ -86,32 +88,36 @@
(mapv normalize-multiaccount-data-keys
(types/json->clj %))]))))
(fx/defn multiaccount-generate-and-derive-addresses-success
(rf/defn multiaccount-generate-and-derive-addresses-success
{:events [:multiaccount-generate-and-derive-addresses-success]}
[{:keys [db]} result]
{:db (update db :intro-wizard
(fn [data]
(-> data
(dissoc :processing?)
(assoc :multiaccounts result
:selected-storage-type :default
:selected-id (-> result first :id)
:step :choose-key))))
{:db (update db
:intro-wizard
(fn [data]
(-> data
(dissoc :processing?)
(assoc :multiaccounts result
:selected-storage-type :default
:selected-id (-> result first :id)
:step :choose-key))))
:navigate-to-fx :choose-name})
(fx/defn generate-and-derive-addresses
(rf/defn generate-and-derive-addresses
{:events [:generate-and-derive-addresses]}
[{:keys [db]}]
{:db (-> db
(update :intro-wizard #(-> % (assoc :processing? true) (dissoc :recovering?)))
(dissoc :recovered-account?))
{:db (-> db
(update :intro-wizard
#(-> %
(assoc :processing? true)
(dissoc :recovering?)))
(dissoc :recovered-account?))
:multiaccount-generate-and-derive-addresses nil})
(fx/defn prepare-intro-wizard
(rf/defn prepare-intro-wizard
[{:keys [db]}]
{:db (assoc db :intro-wizard {})})
(fx/defn save-multiaccount-and-login-with-keycard
(rf/defn save-multiaccount-and-login-with-keycard
[_ args]
{:keycard/save-multiaccount-and-login args})
@@ -126,7 +132,7 @@
config
accounts-data)))
(fx/defn save-account-and-login
(rf/defn save-account-and-login
[_ key-uid multiaccount-data password settings node-config accounts-data]
{::save-account-and-login [key-uid
(types/clj->json multiaccount-data)
@@ -150,53 +156,57 @@
{:public-key public-key
:address (eip55/address->checksum address)
:name name
:identicon identicon
:identicon identicon
:path constants/path-whisper
:chat true})])
(fx/defn on-multiaccount-created
(rf/defn on-multiaccount-created
[{:keys [signing-phrase random-guid-generator db] :as cofx}
{:keys [address chat-key keycard-instance-uid key-uid
keycard-pairing keycard-paired-on mnemonic recovered]
:as multiaccount}
:as multiaccount}
password
{:keys [save-mnemonic? login?] :or {login? true save-mnemonic? false}}]
(let [[wallet-account {:keys [public-key identicon name]} :as accounts-data] (prepare-accounts-data multiaccount)
multiaccount-data {:name name
:address address
:identicon identicon
:key-uid key-uid
(let [[wallet-account {:keys [public-key identicon name]} :as accounts-data] (prepare-accounts-data
multiaccount)
multiaccount-data {:name name
:address address
:identicon identicon
:key-uid key-uid
:keycard-pairing keycard-pairing}
keycard-multiaccount? (boolean keycard-pairing)
eip1581-address (get-in multiaccount [:derived
constants/path-eip1581-keyword
:address])
eip1581-address (get-in multiaccount
[:derived
constants/path-eip1581-keyword
:address])
new-multiaccount
(cond-> (merge
{;; address of the master key
:address address
;; sha256 of master public key
:key-uid key-uid
;; The address from which we derive any wallet
:wallet-root-address
(get-in multiaccount [:derived
constants/path-wallet-root-keyword
:address])
:name name
:identicon identicon
;; public key of the chat account
:public-key public-key
;; default address for Dapps
:dapps-address (:address wallet-account)
:latest-derived-path 0
:signing-phrase signing-phrase
:send-push-notifications? true
:backup-enabled? true
:installation-id (random-guid-generator)
;; default mailserver (history node) setting
:use-mailservers? true
:recovered recovered}
config/default-multiaccount)
(cond->
(merge
{;; address of the master key
:address address
;; sha256 of master public key
:key-uid key-uid
;; The address from which we derive any wallet
:wallet-root-address
(get-in multiaccount
[:derived
constants/path-wallet-root-keyword
:address])
:name name
:identicon identicon
;; public key of the chat account
:public-key public-key
;; default address for Dapps
:dapps-address (:address wallet-account)
:latest-derived-path 0
:signing-phrase signing-phrase
:send-push-notifications? true
:backup-enabled? true
:installation-id (random-guid-generator)
;; default mailserver (history node) setting
:use-mailservers? true
:recovered recovered}
config/default-multiaccount)
;; The address from which we derive any chat
;; account/encryption keys
eip1581-address
@@ -205,23 +215,23 @@
(assoc :mnemonic mnemonic)
keycard-multiaccount?
(assoc :keycard-instance-uid keycard-instance-uid
:keycard-pairing keycard-pairing
:keycard-paired-on keycard-paired-on))
:keycard-pairing keycard-pairing
:keycard-paired-on keycard-paired-on))
db (assoc db
:multiaccounts/login {:key-uid key-uid
:name name
:identicon identicon
:password password
:creating? true
:processing true}
:multiaccount new-multiaccount
:multiaccount/accounts [wallet-account]
:multiaccounts/login {:key-uid key-uid
:name name
:identicon identicon
:password password
:creating? true
:processing true}
:multiaccount new-multiaccount
:multiaccount/accounts [wallet-account]
:networks/current-network config/default-network
:networks/networks (data-store.settings/rpc->networks config/default-networks))
:networks/networks (data-store.settings/rpc->networks config/default-networks))
settings (assoc new-multiaccount
:networks/current-network config/default-network
:networks/networks config/default-networks)]
(fx/merge cofx
:networks/networks config/default-networks)]
(rf/merge cofx
{:db db}
(if keycard-multiaccount?
(save-multiaccount-and-login-with-keycard
@@ -240,26 +250,26 @@
(node/get-new-config db)
accounts-data)))))
(fx/defn store-multiaccount-success
{:events [::store-multiaccount-success]
(rf/defn store-multiaccount-success
{:events [::store-multiaccount-success]
:interceptors [(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx ::get-signing-phrase)]}
[{:keys [db] :as cofx} password derived]
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :intro-wizard)}
(on-multiaccount-created (assoc (let [{:keys [selected-id multiaccounts]} (:intro-wizard db)]
(some #(when (= selected-id (:id %)) %) multiaccounts))
:derived derived
:derived derived
:recovered (get-in db [:intro-wizard :recovering?]))
password
{:save-mnemonic? true})))
(fx/defn on-key-selected
(rf/defn on-key-selected
{:events [:intro-wizard/on-key-selected]}
[{:keys [db]} id]
{:db (assoc-in db [:intro-wizard :selected-id] id)})
(fx/defn on-key-storage-selected
(rf/defn on-key-storage-selected
{:events [:intro-wizard/on-key-storage-selected]}
[{:keys [db]} storage-type]
{:db (assoc-in db [:intro-wizard :selected-storage-type] storage-type)})
@@ -1,24 +1,24 @@
(ns status-im.multiaccounts.key-storage.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.mnemonic :as mnemonic]
[status-im.i18n.i18n :as i18n]
[status-im.keycard.backup-key :as keycard.backup]
[status-im.keycard.common :as common]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.multiaccounts.logout.core :as multiaccounts.logout]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.multiaccounts.recover.core :as multiaccounts.recover]
[status-im.native-module.core :as native-module]
[status-im2.navigation.events :as navigation]
[status-im.popover.core :as popover]
[status-im.utils.fx :as fx]
[status-im.utils.security :as security]
[status-im.ethereum.core :as ethereum]
[status-im.i18n.i18n :as i18n]
[status-im.utils.types :as types]
[status-im.keycard.backup-key :as keycard.backup]
[status-im.bottom-sheet.core :as bottom-sheet]))
[status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(fx/defn key-and-storage-management-pressed
(rf/defn key-and-storage-management-pressed
"This event can be dispatched before login and from profile and needs to redirect accordingly"
{:events [::key-and-storage-management-pressed]}
[cofx]
@@ -29,52 +29,57 @@
:actions-not-logged-in)
nil))
(fx/defn move-keystore-checked
(rf/defn move-keystore-checked
{:events [::move-keystore-checked]}
[{:keys [db] :as cofx} checked?]
{:db (assoc-in db [:multiaccounts/key-storage :move-keystore-checked?] checked?)})
(fx/defn reset-db-checked
(rf/defn reset-db-checked
{:events [::reset-db-checked]}
[{:keys [db] :as cofx} checked?]
{:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] checked?)})
(fx/defn navigate-back
(rf/defn navigate-back
{:events [::navigate-back]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(dissoc :recovered-account?)
(update :keycard dissoc :from-key-storage-and-migration? :creating-backup? :factory-reset-card?))}
(update :keycard
dissoc
:from-key-storage-and-migration?
:creating-backup?
:factory-reset-card?))}
(navigation/navigate-back)))
(fx/defn enter-seed-pressed
(rf/defn enter-seed-pressed
"User is logged out and probably wants to move multiaccount to Keycard. Navigate to enter seed phrase screen"
{:events [::enter-seed-pressed]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (assoc db :recovered-account? true)}
(navigation/navigate-to-cofx :seed-phrase nil)))
(fx/defn seed-phrase-input-changed
(rf/defn seed-phrase-input-changed
{:events [::seed-phrase-input-changed]}
[{:keys [db] :as cofx} masked-seed-phrase]
(let [seed-phrase (security/safe-unmask-data masked-seed-phrase)]
{:db (update db :multiaccounts/key-storage assoc
:seed-phrase (when seed-phrase
(string/lower-case seed-phrase))
:seed-shape-invalid? (or (empty? seed-phrase)
(not (mnemonic/valid-length? seed-phrase)))
:seed-word-count (mnemonic/words-count seed-phrase))}))
{:db (update db
:multiaccounts/key-storage assoc
:seed-phrase (when seed-phrase
(string/lower-case seed-phrase))
:seed-shape-invalid? (or (empty? seed-phrase)
(not (mnemonic/valid-length? seed-phrase)))
:seed-word-count (mnemonic/words-count seed-phrase))}))
(fx/defn key-uid-seed-mismatch
(rf/defn key-uid-seed-mismatch
{:events [::show-seed-key-uid-mismatch-error-popup]}
[cofx _]
(popover/show-popover cofx {:view :seed-key-uid-mismatch}))
(fx/defn key-uid-matches
(rf/defn key-uid-matches
{:events [::key-uid-matches]}
[{:keys [db] :as cofx} _]
(let [backup? (get-in db [:keycard :creating-backup?])]
@@ -100,27 +105,32 @@
::validate-seed-against-key-uid
(partial validate-seed-against-key-uid
{:import-mnemonic-fn native-module/multiaccount-import-mnemonic
:on-success #(re-frame/dispatch [::key-uid-matches])
:on-error #(re-frame/dispatch [::show-seed-key-uid-mismatch-error-popup])}))
:on-success #(re-frame/dispatch [::key-uid-matches])
:on-error #(re-frame/dispatch [::show-seed-key-uid-mismatch-error-popup])}))
(fx/defn seed-phrase-validated
(rf/defn seed-phrase-validated
{:events [::seed-phrase-validated]}
[{:keys [db] :as cofx} validation-error]
(let [error? (-> validation-error
types/json->clj
:error
string/blank?
not)
(let [error? (-> validation-error
types/json->clj
:error
string/blank?
not)
onboarding? (not (or (:multiaccounts/login db) (:multiaccount db)))]
(if error?
(popover/show-popover cofx {:view :custom-seed-phrase})
{::validate-seed-against-key-uid {:seed-phrase (-> db :multiaccounts/key-storage :seed-phrase)
;; Unique key-uid of the account for which we are going to move keys
:key-uid (or (-> db :multiaccounts/login :key-uid)
(-> db :multiaccount :key-uid)
(and onboarding? (-> db :keycard :application-info :key-uid)))}})))
;; Unique key-uid of the account for which we are going to move
;; keys
:key-uid (or (-> db :multiaccounts/login :key-uid)
(-> db :multiaccount :key-uid)
(and onboarding?
(-> db
:keycard
:application-info
:key-uid)))}})))
(fx/defn choose-storage-pressed
(rf/defn choose-storage-pressed
{:events [::choose-storage-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [seed-phrase]} (:multiaccounts/key-storage db)]
@@ -128,7 +138,7 @@
[(mnemonic/sanitize-passphrase seed-phrase)
#(re-frame/dispatch [::seed-phrase-validated %])]}))
(fx/defn keycard-storage-pressed
(rf/defn keycard-storage-pressed
{:events [::keycard-storage-pressed]}
[{:keys [db]} selected?]
{:db (assoc-in db [:multiaccounts/key-storage :keycard-storage-selected?] selected?)})
@@ -161,55 +171,56 @@ The exact events dispatched for this flow if consumed from the UI are:
We don't need to take the exact steps, just set the required state and redirect to correct screen
"
(fx/defn import-multiaccount
(rf/defn import-multiaccount
[{:keys [db] :as cofx}]
{:dispatch [:bottom-sheet/hide]
{:dispatch [:bottom-sheet/hide]
::multiaccounts.recover/import-multiaccount
{:passphrase (get-in db [:multiaccounts/key-storage :seed-phrase])
:password nil
:success-event ::import-multiaccount-success}})
(fx/defn delete-multiaccount-and-init-keycard-onboarding
(rf/defn delete-multiaccount-and-init-keycard-onboarding
{:events [::delete-multiaccount-and-init-keycard-onboarding]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
{:dispatch [:bottom-sheet/hide]
:db (assoc-in db [:multiaccounts/key-storage :reset-db-checked?] true)}
(import-multiaccount)))
(fx/defn storage-selected
(rf/defn storage-selected
{:events [::storage-selected]}
[{:keys [db] :as cofx}]
(if (get-in db [:multiaccounts/key-storage :reset-db-checked?])
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning})
(bottom-sheet/show-bottom-sheet cofx {:view :migrate-account-password})))
(fx/defn skip-password-pressed
(rf/defn skip-password-pressed
{:events [::skip-password-pressed]}
[cofx]
(popover/show-popover cofx {:view :transfer-multiaccount-to-keycard-warning}))
(fx/defn password-changed
(rf/defn password-changed
{:events [::password-changed]}
[{db :db} password]
(let [unmasked-pass (security/safe-unmask-data password)]
{:db (update db :keycard assoc
:migration-password password
:migration-password-error nil
{:db (update db
:keycard assoc
:migration-password password
:migration-password-error nil
:migration-password-valid? (and unmasked-pass (> (count unmasked-pass) 5)))}))
(fx/defn verify-password-result
(rf/defn verify-password-result
{:events [::verify-password-result]}
[{:keys [db] :as cofx} result]
(let [{:keys [error]} (types/json->clj result)]
(if (string/blank? error)
(fx/merge
(rf/merge
cofx
{:db (update db :keycard dissoc :migration-password-error :migration-password-valid?)}
(import-multiaccount))
{:db (assoc-in db [:keycard :migration-password-error] (i18n/label :t/wrong-password))})))
(fx/defn verify-password
(rf/defn verify-password
{:events [::verify-password]}
[{:keys [db] :as cofx}]
(native-module/verify-database-password
@@ -217,42 +228,43 @@ We don't need to take the exact steps, just set the required state and redirect
(ethereum/sha3 (security/safe-unmask-data (get-in db [:keycard :migration-password])))
#(re-frame/dispatch [::verify-password-result %])))
(fx/defn handle-multiaccount-import
(rf/defn handle-multiaccount-import
{:events [::import-multiaccount-success]}
[{:keys [db] :as cofx} root-data derived-data]
(fx/merge cofx
{:db (-> db
(update :intro-wizard
assoc
:root-key root-data
:derived derived-data
:recovering? true
:selected-storage-type :advanced)
(assoc-in [:keycard :flow] :recovery)
(assoc-in [:keycard :from-key-storage-and-migration?] true)
(assoc-in [:keycard :converting-account?] (not (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
(assoc-in [:keycard :delete-account?]
(true? (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
(dissoc :multiaccounts/key-storage))}
(rf/merge cofx
{:db (-> db
(update :intro-wizard
assoc
:root-key root-data
:derived derived-data
:recovering? true
:selected-storage-type :advanced)
(assoc-in [:keycard :flow] :recovery)
(assoc-in [:keycard :from-key-storage-and-migration?] true)
(assoc-in [:keycard :converting-account?]
(not (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
(assoc-in [:keycard :delete-account?]
(true? (get-in db [:multiaccounts/key-storage :reset-db-checked?])))
(dissoc :multiaccounts/key-storage))}
(popover/hide-popover)
(common/listen-to-hardware-back-button)
(navigation/navigate-to-cofx :keycard-onboarding-intro nil)))
(fx/defn goto-multiaccounts-screen
(rf/defn goto-multiaccounts-screen
{:events [::hide-popover-and-goto-multiaccounts-screen]}
[cofx _]
(fx/merge cofx
(rf/merge cofx
(popover/hide-popover)
(navigation/navigate-to-cofx :multiaccounts nil)))
(fx/defn confirm-logout-and-goto-key-storage
(rf/defn confirm-logout-and-goto-key-storage
{:events [::confirm-logout-and-goto-key-storage]}
[{:keys [db] :as cofx}]
(fx/merge cofx
(rf/merge cofx
{:db (assoc db :goto-key-storage? true)}
(multiaccounts.logout/logout)))
(fx/defn logout-and-goto-key-storage
(rf/defn logout-and-goto-key-storage
{:events [::logout-and-goto-key-storage]}
[_]
{:ui/show-confirmation
@@ -264,9 +276,11 @@ We don't need to take the exact steps, just set the required state and redirect
(comment
;; check import mnemonic output
(native-module/multiaccount-import-mnemonic "rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo" nil
(fn [result]
(prn (types/json->clj result))))
(native-module/multiaccount-import-mnemonic
"rocket mixed rebel affair umbrella legal resemble scene virus park deposit cargo"
nil
(fn [result]
(prn (types/json->clj result))))
;; check delete account output
(native-module/delete-multiaccount "0x3831d0f22996a65970a214f0a94bfa9a63a21dac235d8dadb91be8e32e7d3ab7"
(fn [result]
@@ -2,7 +2,7 @@
(:require [cljs.test :refer-macros [deftest is testing]]
[clojure.string :as string]
[status-im.multiaccounts.key-storage.core :as models]
[status-im.utils.security :as security]))
[utils.security.core :as security]))
(deftest move-keystore-checked
(testing "Checks checkbox on-press"
+211 -180
View File
@@ -1,48 +1,48 @@
(ns status-im.multiaccounts.login.core
(:require [re-frame.core :as re-frame]
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.async-storage.core :as async-storage]
[status-im.chat.models.link-preview :as link-preview]
[status-im.communities.core :as communities]
[status-im.contact.core :as contact]
[status-im.utils.config :as config]
[status-im.data-store.chats :as data-store.chats]
[status-im.data-store.invitations :as data-store.invitations]
[status-im.data-store.settings :as data-store.settings]
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.transactions.core :as transactions]
[status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.keycard.common :as keycard.common]
[status-im.ethereum.tokens :as tokens]
[status-im.ethereum.transactions.core :as transactions]
[status-im.fleet.core :as fleet]
[status-im.i18n.i18n :as i18n]
[status-im.keycard.common :as keycard.common]
[status-im.mobile-sync-settings.core :as mobile-network]
[status-im.multiaccounts.biometric.core :as biometric]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.native-module.core :as status]
[status-im.node.core :as node]
[status-im.notifications.core :as notifications]
[status-im.popover.core :as popover]
[status-im.communities.core :as communities]
[status-im.signing.eip1559 :as eip1559]
[status-im.transport.core :as transport]
[status-im.mobile-sync-settings.core :as mobile-network]
[status-im.utils.fx :as fx]
[status-im.ui.components.react :as react]
[status-im.utils.config :as config]
[status-im.utils.keychain.core :as keychain]
[status-im2.setup.log :as logging]
[status-im.utils.security :as security]
[status-im.utils.mobile-sync :as utils.mobile-sync]
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[status-im.wallet.core :as wallet]
[status-im.wallet-connect-legacy.core :as wallet-connect-legacy]
[status-im.wallet.prices :as prices]
[taoensso.timbre :as log]
[status-im.data-store.invitations :as data-store.invitations]
[status-im.chat.models.link-preview :as link-preview]
[status-im.utils.mobile-sync :as utils.mobile-sync]
[status-im.async-storage.core :as async-storage]
[status-im.activity-center.core :as activity-center]
[status-im2.navigation.events :as navigation]
[status-im.signing.eip1559 :as eip1559]
[status-im.data-store.chats :as data-store.chats]
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
[status-im.ui.components.react :as react]
[status-im.utils.platform :as platform]
[status-im.ethereum.tokens :as tokens]
[clojure.string :as string]
[status-im.utils.wallet-connect :as wallet-connect]
[status-im.node.core :as node]))
[status-im.wallet-connect-legacy.core :as wallet-connect-legacy]
[status-im.wallet.core :as wallet]
[status-im.wallet.prices :as prices]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[status-im2.setup.log :as logging]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(re-frame/reg-fx
::initialize-communities-enabled
@@ -89,11 +89,13 @@
#(re-frame/dispatch [:wallet-connect/client-init %])
#(log/error "[wallet-connect]" %))))
(defn rpc->accounts [accounts]
(defn rpc->accounts
[accounts]
(reduce (fn [acc {:keys [chat type wallet] :as account}]
(if chat
acc
(let [account (cond-> (update account :address
(let [account (cond-> (update account
:address
eip55/address->checksum)
type
(update :type keyword))]
@@ -119,25 +121,28 @@
"0x86a12d91c813f69a53349ff640e32af97d5f5c1f8d42d54cf4c8aa8dea231955"
"0x0011a30f5b2023bc228f6dd5608b3e7149646fa83f33350926ceb1925af78f08"})
(fx/defn check-invalid-ens [{:keys [db]}]
(rf/defn check-invalid-ens
[{:keys [db]}]
(async-storage/get-item
:invalid-ens-name-seen
(fn [already-seen]
(when (and (not already-seen)
(boolean (get invalid-addrr (ethereum/sha3 (string/lower-case (ethereum/default-address db))))))
(boolean (get invalid-addrr
(ethereum/sha3 (string/lower-case (ethereum/default-address db))))))
(utils/show-popup
(i18n/label :t/warning)
(i18n/label :t/ens-username-invalid-name-warning)
#(async-storage/set-item! :invalid-ens-name-seen true)))))
nil)
(fx/defn initialize-wallet
(rf/defn initialize-wallet
{:events [::initialize-wallet]}
[{:keys [db] :as cofx} accounts tokens custom-tokens
favourites scan-all-tokens? new-account?]
(fx/merge
(rf/merge
cofx
{:db (assoc db :multiaccount/accounts
{:db (assoc db
:multiaccount/accounts
(rpc->accounts accounts))
;; NOTE: Local notifications should be enabled only after wallet was started
::enable-local-notifications nil}
@@ -146,16 +151,18 @@
(wallet/initialize-favourites favourites)
(wallet/get-pending-transactions)
(wallet/fetch-collectibles-collection)
(cond (and new-account?
(not scan-all-tokens?))
(wallet/set-zero-balances (first accounts))
(cond
(and new-account?
(not scan-all-tokens?))
(wallet/set-zero-balances (first accounts))
(and new-account? scan-all-tokens?
(not (utils.mobile-sync/cellular? (:network/type db))))
(wallet/set-max-block (get (first accounts) :address) 0)
(and new-account?
scan-all-tokens?
(not (utils.mobile-sync/cellular? (:network/type db))))
(wallet/set-max-block (get (first accounts) :address) 0)
:else
(wallet/get-cached-balances scan-all-tokens?))
:else
(wallet/get-cached-balances scan-all-tokens?))
(when-not (get db :wallet/new-account)
(wallet/restart-wallet-service nil))
(when (or (not (utils.mobile-sync/syncing-allowed? cofx))
@@ -166,21 +173,21 @@
(prices/update-prices)
(wallet-connect-legacy/get-connector-session-from-db)))
(fx/defn login
(rf/defn login
{:events [:multiaccounts.login.ui/password-input-submitted]}
[{:keys [db]}]
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
{:db (-> db
(assoc-in [:multiaccounts/login :processing] true)
(dissoc :intro-wizard :recovered-account?)
(update :keycard dissoc :flow))
{:db (-> db
(assoc-in [:multiaccounts/login :processing] true)
(dissoc :intro-wizard :recovered-account?)
(update :keycard dissoc :flow))
::login [key-uid
(types/clj->json {:name name
:key-uid key-uid
:identicon identicon})
(types/clj->json {:name name
:key-uid key-uid
:identicon identicon})
(ethereum/sha3 (security/safe-unmask-data password))]}))
(fx/defn export-db-submitted
(rf/defn export-db-submitted
{:events [:multiaccounts.login.ui/export-db-submitted]}
[{:keys [db]}]
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
@@ -192,24 +199,25 @@
(fn [path]
(when platform/ios?
(let [uri (str "file://" path)]
(.share ^js react/sharing (clj->js {:title "Unencrypted database"
:url uri})))))]}))
(.share ^js react/sharing
(clj->js {:title "Unencrypted database"
:url uri})))))]}))
(fx/defn import-db-submitted
(rf/defn import-db-submitted
{:events [:multiaccounts.login.ui/import-db-submitted]}
[{:keys [db]}]
(let [{:keys [key-uid password name identicon]} (:multiaccounts/login db)]
{::import-db [key-uid
(types/clj->json {:name name
:key-uid key-uid
:identicon identicon})
(types/clj->json {:name name
:key-uid key-uid
:identicon identicon})
(ethereum/sha3 (security/safe-unmask-data password))]}))
(fx/defn finish-keycard-setup
(rf/defn finish-keycard-setup
[{:keys [db] :as cofx}]
{:db (update db :keycard dissoc :flow)})
(fx/defn initialize-dapp-permissions
(rf/defn initialize-dapp-permissions
{:events [::initialize-dapp-permissions]}
[{:keys [db]} all-dapp-permissions]
(let [dapp-permissions (reduce (fn [acc {:keys [dapp] :as dapp-permissions}]
@@ -218,7 +226,7 @@
all-dapp-permissions)]
{:db (assoc db :dapps/permissions dapp-permissions)}))
(fx/defn initialize-browsers
(rf/defn initialize-browsers
{:events [::initialize-browsers]}
[{:keys [db]} all-stored-browsers]
(let [browsers (reduce (fn [acc {:keys [browser-id] :as browser}]
@@ -227,7 +235,7 @@
all-stored-browsers)]
{:db (assoc db :browser/browsers browsers)}))
(fx/defn initialize-bookmarks
(rf/defn initialize-bookmarks
{:events [::initialize-bookmarks]}
[{:keys [db]} stored-bookmarks]
(let [bookmarks (reduce (fn [acc {:keys [url] :as bookmark}]
@@ -236,28 +244,30 @@
stored-bookmarks)]
{:db (assoc db :bookmarks/bookmarks bookmarks)}))
(fx/defn initialize-invitations
(rf/defn initialize-invitations
{:events [::initialize-invitations]}
[{:keys [db]} invitations]
{:db (assoc db :group-chat/invitations (reduce (fn [acc {:keys [id] :as inv}]
(assoc acc id (data-store.invitations/<-rpc inv)))
{}
invitations))})
{:db (assoc db
:group-chat/invitations
(reduce (fn [acc {:keys [id] :as inv}]
(assoc acc id (data-store.invitations/<-rpc inv)))
{}
invitations))})
(fx/defn initialize-web3-client-version
(rf/defn initialize-web3-client-version
{:events [::initialize-web3-client-version]}
[{:keys [db]} node-version]
{:db (assoc db :web3-node-version node-version)})
(fx/defn handle-close-app-confirmed
(rf/defn handle-close-app-confirmed
{:events [::close-app-confirmed]}
[_]
{:ui/close-application nil})
(fx/defn check-network-version
(rf/defn check-network-version
[_ network-id]
{::json-rpc/call
[{:method "net_version"
[{:method "net_version"
:on-success
(fn [fetched-network-id]
(when (not= network-id (str (int fetched-network-id)))
@@ -270,7 +280,8 @@
:fetched-network-id fetched-network-id})
#(re-frame/dispatch [::close-app-confirmed]))))}]})
(defn normalize-tokens [network-id tokens]
(defn normalize-tokens
[network-id tokens]
(mapv #(-> %
(update :symbol keyword)
((partial tokens/update-icon (ethereum/chain-id->chain-keyword (int network-id)))))
@@ -281,8 +292,8 @@
(fn [[network-id accounts recovered-account?]]
(utils/set-timeout
(fn []
(json-rpc/call {:method "wallet_getTokens"
:params [(int network-id)]
(json-rpc/call {:method "wallet_getTokens"
:params [(int network-id)]
:on-success #(re-frame/dispatch [::initialize-wallet
accounts
(normalize-tokens network-id %)
@@ -299,25 +310,25 @@
(clj->js
[(js/Promise.
(fn [resolve reject]
(json-rpc/call {:method "accounts_getAccounts"
(json-rpc/call {:method "accounts_getAccounts"
:on-success resolve
:on-error reject})))
:on-error reject})))
(js/Promise.
(fn [resolve _]
(json-rpc/call {:method "wallet_getTokens"
:params [(int network-id)]
(json-rpc/call {:method "wallet_getTokens"
:params [(int network-id)]
:on-success resolve
:on-error #(resolve nil)})))
:on-error #(resolve nil)})))
(js/Promise.
(fn [resolve reject]
(json-rpc/call {:method "wallet_getCustomTokens"
(json-rpc/call {:method "wallet_getCustomTokens"
:on-success resolve
:on-error reject})))
:on-error reject})))
(js/Promise.
(fn [resolve reject]
(json-rpc/call {:method "wallet_getSavedAddresses"
(json-rpc/call {:method "wallet_getSavedAddresses"
:on-success resolve
:on-error reject})))]))
:on-error reject})))]))
(.then (fn [[accounts tokens custom-tokens favourites]]
(callback accounts
(normalize-tokens network-id tokens)
@@ -326,7 +337,8 @@
(.catch (fn [_]
(log/error "Failed to initialize wallet"))))))
(fx/defn initialize-browser [_]
(rf/defn initialize-browser
[_]
{::json-rpc/call
[{:method "wakuext_getBrowsers"
:on-success #(re-frame/dispatch [::initialize-browsers %])}
@@ -335,53 +347,57 @@
{:method "permissions_getDappPermissions"
:on-success #(re-frame/dispatch [::initialize-dapp-permissions %])}]})
(fx/defn initialize-appearance [cofx]
(rf/defn initialize-appearance
[cofx]
{:multiaccounts.ui/switch-theme (get-in cofx [:db :multiaccount :appearance])})
(fx/defn get-group-chat-invitations [_]
(rf/defn get-group-chat-invitations
[_]
{::json-rpc/call
[{:method "wakuext_getGroupChatInvitations"
:on-success #(re-frame/dispatch [::initialize-invitations %])}]})
(fx/defn initialize-communities-enabled
(rf/defn initialize-communities-enabled
[cofx]
{::initialize-communities-enabled nil})
(fx/defn initialize-transactions-management-enabled
(rf/defn initialize-transactions-management-enabled
[cofx]
{::initialize-transactions-management-enabled nil})
(fx/defn initialize-wallet-connect
(rf/defn initialize-wallet-connect
[cofx]
{::initialize-wallet-connect nil})
(fx/defn get-node-config-callback
(rf/defn get-node-config-callback
{:events [::get-node-config-callback]}
[{:keys [db] :as cofx} node-config-json]
(let [node-config (types/json->clj node-config-json)]
{:db (assoc-in db [:multiaccount :wakuv2-config]
(get node-config :WakuV2Config))}))
{:db (assoc-in db
[:multiaccount :wakuv2-config]
(get node-config :WakuV2Config))}))
(fx/defn get-node-config
(rf/defn get-node-config
[_]
(status/get-node-config #(re-frame/dispatch [::get-node-config-callback %])))
(fx/defn get-settings-callback
(rf/defn get-settings-callback
{:events [::get-settings-callback]}
[{:keys [db] :as cofx} settings]
(let [{:networks/keys [current-network networks]
:as settings}
(data-store.settings/rpc->settings settings)
multiaccount (dissoc settings :networks/current-network :networks/networks)
;;for some reason we save default networks in db, in case when we want to modify default-networks for
;;for some reason we save default networks in db, in case when we want to modify default-networks
;;for
;; existing accounts we have to merge them again into networks
merged-networks (merge networks config/default-networks-by-id)]
(fx/merge cofx
(rf/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)
(assoc :networks/current-network current-network
:networks/networks merged-networks
:multiaccount multiaccount))}
:networks/networks merged-networks
:multiaccount multiaccount))}
(data-store.chats/fetch-chats-rpc
{:on-success
#(do (re-frame/dispatch [:chats-list/load-success %])
@@ -408,31 +424,32 @@
(when (= stored-key-uid key-uid)
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
(fx/defn check-last-chat
(rf/defn check-last-chat
{:events [::check-last-chat]}
[{:keys [db]}]
{::open-last-chat (get-in db [:multiaccount :key-uid])})
(fx/defn update-wallet-accounts
(rf/defn update-wallet-accounts
[{:keys [db]} accounts]
(let [existing-accounts (into {} (map #(vector (:address %1) %1) (:multiaccount/accounts db)))
reduce-fn (fn [existing-accs new-acc]
(let [address (:address new-acc)]
(if (:removed new-acc)
(dissoc existing-accs address)
(assoc existing-accs address new-acc))))
new-accounts (reduce reduce-fn existing-accounts (rpc->accounts accounts))]
reduce-fn (fn [existing-accs new-acc]
(let [address (:address new-acc)]
(if (:removed new-acc)
(dissoc existing-accs address)
(assoc existing-accs address new-acc))))
new-accounts (reduce reduce-fn existing-accounts (rpc->accounts accounts))]
{:db (assoc db :multiaccount/accounts (vals new-accounts))}))
(fx/defn get-chats-callback
(rf/defn get-chats-callback
{:events [::get-chats-callback]}
[{:keys [db] :as cofx}]
(let [{:networks/keys [current-network networks]} db
notifications-enabled? (get-in db [:multiaccount :notifications-enabled?])
network-id (str (get-in networks [current-network :config :NetworkId]))
notifications-enabled? (get-in db [:multiaccount :notifications-enabled?])
network-id (str (get-in networks
[current-network :config :NetworkId]))
remote-push-notifications-enabled?
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
(fx/merge cofx
(rf/merge cofx
(cond-> {::eip1559/check-eip1559-activation
{:network-id network-id
:on-enabled #(log/info "eip1550 is activated")
@@ -442,7 +459,7 @@
(fn [accounts tokens custom-tokens favourites]
(re-frame/dispatch [::initialize-wallet
accounts tokens custom-tokens favourites]))]
::open-last-chat (get-in db [:multiaccount :key-uid])}
::open-last-chat (get-in db [:multiaccount :key-uid])}
(or notifications-enabled? remote-push-notifications-enabled?)
(assoc ::notifications/enable remote-push-notifications-enabled?))
(transport/start-messenger)
@@ -457,7 +474,8 @@
(link-preview/request-link-preview-whitelist)
(visibility-status-updates-store/fetch-visibility-status-updates-rpc))))
(defn get-new-auth-method [auth-method save-password?]
(defn get-new-auth-method
[auth-method save-password?]
(when save-password?
(when-not (or (= keychain/auth-method-biometric auth-method)
(= keychain/auth-method-password auth-method))
@@ -472,15 +490,15 @@
(re-frame/dispatch [:init-root (if config/new-ui-enabled? :shell-stack :chat-stack)])
(re-frame/dispatch [:init-root :tos])))
(fx/defn login-only-events
(rf/defn login-only-events
[{:keys [db] :as cofx} key-uid password save-password?]
(let [auth-method (:auth-method db)
new-auth-method (get-new-auth-method auth-method save-password?)]
(log/debug "[login] login-only-events"
"auth-method" auth-method
"auth-method" auth-method
"new-auth-method" new-auth-method)
(fx/merge cofx
{:db (assoc db :chats/loading? true)
(rf/merge cofx
{:db (assoc db :chats/loading? true)
::json-rpc/call
[{:method "settings_getSettings"
:on-success #(do (re-frame/dispatch [::get-settings-callback %])
@@ -488,24 +506,26 @@
(notifications/load-notification-preferences)
(when save-password?
(keychain/save-user-password key-uid password))
(keychain/save-auth-method key-uid (or new-auth-method auth-method keychain/auth-method-none)))))
(keychain/save-auth-method key-uid
(or new-auth-method auth-method keychain/auth-method-none)))))
(fx/defn create-only-events
(rf/defn create-only-events
[{:keys [db] :as cofx} recovered-account?]
(let [{:keys [multiaccount
:multiaccounts/multiaccounts
:multiaccount/accounts]} db
{:keys [creating?]} (:multiaccounts/login db)
first-account? (and creating?
(empty? multiaccounts))
tos-accepted? (get db :tos/accepted?)
:multiaccount/accounts]}
db
{:keys [creating?]} (:multiaccounts/login db)
first-account? (and creating?
(empty? multiaccounts))
tos-accepted? (get db :tos/accepted?)
{:networks/keys [current-network networks]} db
network-id (str (get-in networks [current-network :config :NetworkId]))]
(fx/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)
(assoc :tos/next-root :onboarding-notification :chats/loading? false)
(assoc-in [:multiaccount :multiaccounts/first-account] first-account?))
(rf/merge cofx
{:db (-> db
(dissoc :multiaccounts/login)
(assoc :tos/next-root :onboarding-notification :chats/loading? false)
(assoc-in [:multiaccount :multiaccounts/first-account] first-account?))
::get-tokens [network-id accounts recovered-account?]}
(finish-keycard-setup)
(transport/start-messenger)
@@ -525,14 +545,16 @@
(navigation/init-root :onboarding-notification)
(navigation/init-root :tos))))))
(defn- keycard-setup? [cofx]
(defn- keycard-setup?
[cofx]
(boolean (get-in cofx [:db :keycard :flow])))
(defn on-login-update-db [db login-only? now]
(defn on-login-update-db
[db login-only? now]
(-> db
(dissoc :connectivity/ui-status-properties)
(update :keycard dissoc :from-key-storage-and-migration?)
(update :keycard dissoc
(update :keycard dissoc
:on-card-read
:card-read-in-progress?
:pin
@@ -544,23 +566,25 @@
(assoc :logged-in-since now)
(assoc :view-id :home)))
(fx/defn multiaccount-login-success
(rf/defn multiaccount-login-success
[{:keys [db now] :as cofx}]
(let [{:keys [key-uid password save-password? creating?]}
(:multiaccounts/login db)
multiaccounts (:multiaccounts/multiaccounts db)
recovered-account? (get db :recovered-account?)
login-only? (not (or creating?
recovered-account?
(keycard-setup? cofx)))
from-migration? (get-in db [:keycard :from-key-storage-and-migration?])
nodes nil]
multiaccounts (:multiaccounts/multiaccounts db)
recovered-account? (get db :recovered-account?)
login-only? (not (or creating?
recovered-account?
(keycard-setup? cofx)))
from-migration? (get-in db
[:keycard
:from-key-storage-and-migration?])
nodes nil]
(log/debug "[multiaccount] multiaccount-login-success"
"login-only?" login-only?
"login-only?" login-only?
"recovered-account?" recovered-account?)
(fx/merge cofx
{:db (on-login-update-db db login-only? now)
(rf/merge cofx
{:db (on-login-update-db db login-only? now)
::json-rpc/call
[{:method "web3_clientVersion"
:on-success #(re-frame/dispatch [::initialize-web3-client-version %])}]}
@@ -571,7 +595,8 @@
(not recovered-account?))
(wallet/set-initial-blocks-range))
(when from-migration?
(utils/show-popup (i18n/label :t/migration-successful) (i18n/label :t/migration-successful-text)))
(utils/show-popup (i18n/label :t/migration-successful)
(i18n/label :t/migration-successful-text)))
(if login-only?
(login-only-events key-uid password save-password?)
(create-only-events recovered-account?)))))
@@ -582,7 +607,7 @@
;; are alreayd in `multiaccounts/login` and should not be overriden, as they come from
;; the keychain (save-password), this is not very explicit and we should probably
;; make it clearer
(fx/defn open-login
(rf/defn open-login
[{:keys [db]} override-multiaccount]
{:db (-> db
(update :multiaccounts/login
@@ -593,23 +618,26 @@
:error
:password))})
(fx/defn open-login-callback
(rf/defn open-login-callback
{:events [:multiaccounts.login.callback/get-user-password-success]}
[{:keys [db] :as cofx} password]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
keycard-account? (boolean (get-in db [:multiaccounts/multiaccounts
key-uid
:keycard-pairing]))
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
keycard-account? (boolean (get-in db
[:multiaccounts/multiaccounts
key-uid
:keycard-pairing]))
goto-key-storage? (:goto-key-storage? db)]
(if password
(fx/merge
(rf/merge
cofx
{:db (update-in db [:multiaccounts/login] assoc
:password password
:save-password? true)
{:db (update-in db
[:multiaccounts/login]
assoc
:password password
:save-password? true)
:init-root-fx :progress}
login)
(fx/merge
(rf/merge
cofx
{:db (dissoc db :goto-key-storage?)}
(when keycard-account?
@@ -622,25 +650,28 @@
#(when goto-key-storage?
(navigation/navigate-to-cofx % :actions-not-logged-in nil))))))
(fx/defn get-credentials
(rf/defn get-credentials
[{:keys [db] :as cofx} key-uid]
(let [keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
(let [keycard-multiaccount? (boolean (get-in db
[:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
(log/debug "[login] get-credentials"
"keycard-multiacc?" keycard-multiaccount?)
"keycard-multiacc?"
keycard-multiaccount?)
(if keycard-multiaccount?
(keychain/get-keycard-keys cofx key-uid)
(keychain/get-user-password cofx key-uid))))
(fx/defn get-auth-method-success
(rf/defn get-auth-method-success
"Auth method: nil - not supported, \"none\" - not selected, \"password\", \"biometric\", \"biometric-prepare\""
{:events [:multiaccounts.login/get-auth-method-success]}
[{:keys [db] :as cofx} auth-method]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
keycard-multiaccount? (boolean (get-in db
[:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
(log/debug "[login] get-auth-method-success"
"auth-method" auth-method
"auth-method" auth-method
"keycard-multiacc?" keycard-multiaccount?)
(fx/merge
(rf/merge
cofx
{:db (assoc db :auth-method auth-method)}
#(cond
@@ -653,7 +684,7 @@
(keycard.common/get-application-info % nil))
(open-login-callback nil))))
(fx/defn biometric-auth-done
(rf/defn biometric-auth-done
{:events [:biometric-auth-done]}
[{:keys [db] :as cofx} {:keys [bioauth-success bioauth-message bioauth-code]}]
(let [key-uid (get-in db [:multiaccounts/login :key-uid])
@@ -661,28 +692,28 @@
(log/debug "[biometric] biometric-auth-done"
"bioauth-success" bioauth-success
"bioauth-message" bioauth-message
"bioauth-code" bioauth-code)
"bioauth-code" bioauth-code)
(if bioauth-success
(get-credentials cofx key-uid)
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db
[:multiaccounts/login :save-password?]
(= auth-method keychain/auth-method-biometric))}
[:multiaccounts/login :save-password?]
(= auth-method keychain/auth-method-biometric))}
(when-not (= auth-method keychain/auth-method-biometric)
(keychain/save-auth-method key-uid keychain/auth-method-none))
(biometric/show-message bioauth-message bioauth-code)
(open-login-callback nil)))))
(fx/defn save-password
(rf/defn save-password
{:events [:multiaccounts/save-password]}
[{:keys [db] :as cofx} save-password?]
(let [bioauth-supported? (boolean (get db :supported-biometric-auth))
previous-auth-method (get db :auth-method)]
(log/debug "[login] save-password"
"save-password?" save-password?
"bioauth-supported?" bioauth-supported?
"save-password?" save-password?
"bioauth-supported?" bioauth-supported?
"previous-auth-method" previous-auth-method)
(fx/merge
(rf/merge
cofx
{:db (cond-> db
(not= previous-auth-method
@@ -700,54 +731,54 @@
(when-not (= previous-auth-method keychain/auth-method-none)
(popover/show-popover {:view :disable-password-saving})))))))
(fx/defn welcome-lets-go
(rf/defn welcome-lets-go
{:events [:welcome-lets-go]}
[_]
{:init-root-fx :chat-stack})
(fx/defn multiaccount-selected
(rf/defn multiaccount-selected
{:events [:multiaccounts.login.ui/multiaccount-selected]}
[{:keys [db] :as cofx} key-uid]
;; We specifically pass a bunch of fields instead of the whole multiaccount
;; as we want store some fields in multiaccount that are not here
(let [multiaccount (get-in db [:multiaccounts/multiaccounts key-uid])
(let [multiaccount (get-in db [:multiaccounts/multiaccounts key-uid])
keycard-multiaccount? (boolean (:keycard-pairing multiaccount))]
(fx/merge
(rf/merge
cofx
{:db (update db :keycard dissoc :application-info)
{:db (update db :keycard dissoc :application-info)
:navigate-to-fx (if keycard-multiaccount? :keycard-login-pin :login)}
(open-login (select-keys multiaccount [:key-uid :name :public-key :identicon :images])))))
(fx/defn hide-keycard-banner
(rf/defn hide-keycard-banner
{:events [:hide-keycard-banner]}
[{:keys [db]}]
{:db (assoc db :keycard/banner-hidden true)
::async-storage/set! {:keycard-banner-hidden true}})
(fx/defn get-keycard-banner-preference-cb
(rf/defn get-keycard-banner-preference-cb
{:events [:get-keycard-banner-preference-cb]}
[{:keys [db]} {:keys [keycard-banner-hidden]}]
{:db (assoc db :keycard/banner-hidden keycard-banner-hidden)})
(fx/defn get-keycard-banner-preference
(rf/defn get-keycard-banner-preference
{:events [:get-keycard-banner-preference]}
[_]
{::async-storage/get {:keys [:keycard-banner-hidden]
:cb #(re-frame/dispatch [:get-keycard-banner-preference-cb %])}})
(fx/defn get-opted-in-to-new-terms-of-service-cb
(rf/defn get-opted-in-to-new-terms-of-service-cb
{:events [:get-opted-in-to-new-terms-of-service-cb]}
[{:keys [db]} {:keys [new-terms-of-service-accepted]}]
{:db (assoc db :tos/accepted? new-terms-of-service-accepted)})
(fx/defn get-opted-in-to-new-terms-of-service
(rf/defn get-opted-in-to-new-terms-of-service
"New TOS sprint https://github.com/status-im/status-mobile/pull/12240"
{:events [:get-opted-in-to-new-terms-of-service]}
[{:keys [db]}]
{::async-storage/get {:keys [:new-terms-of-service-accepted]
:cb #(re-frame/dispatch [:get-opted-in-to-new-terms-of-service-cb %])}})
(fx/defn hide-terms-of-services-opt-in-screen
(rf/defn hide-terms-of-services-opt-in-screen
{:events [:hide-terms-of-services-opt-in-screen]}
[{:keys [db]}]
{::async-storage/set! {:new-terms-of-service-accepted true}
@@ -2,8 +2,8 @@
(:require [cljs.test :as test]
[status-im.multiaccounts.biometric.core :as biometric]
[status-im.multiaccounts.login.core :as login]
[status-im.utils.fx :as fx]
[status-im.utils.keychain.core :as keychain]))
[status-im.utils.keychain.core :as keychain]
[utils.re-frame :as rf]))
(test/deftest save-password-test
(test/testing "check save password, biometric unavailable"
@@ -44,7 +44,7 @@
"uncheck save password")
(let [initial-cofx {:db {:auth-method keychain/auth-method-none
:supported-biometric-auth true}}
{:keys [db]} (login/save-password (fx/merge
{:keys [db]} (login/save-password (rf/merge
initial-cofx
(login/save-password true)
(biometric/enable)
+17 -15
View File
@@ -1,19 +1,19 @@
(ns status-im.multiaccounts.logout.core
(:require [re-frame.core :as re-frame]
[status-im.i18n.i18n :as i18n]
[status-im.native-module.core :as status]
[status-im.utils.fx :as fx]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.utils.keychain.core :as keychain]
[status-im.native-module.core :as status]
[status-im.notifications.core :as notifications]
[status-im.utils.keychain.core :as keychain]
[status-im.wallet.core :as wallet]
[status-im2.setup.events :as init]))
[status-im2.setup.events :as init]
[utils.re-frame :as rf]))
(fx/defn logout-method
(rf/defn logout-method
{:events [::logout-method]}
[{:keys [db] :as cofx} {:keys [auth-method logout?]}]
(let [key-uid (get-in db [:multiaccount :key-uid])]
(fx/merge cofx
(let [key-uid (get-in db [:multiaccount :key-uid])]
(rf/merge cofx
{:init-root-fx :progress
:chat.ui/clear-inputs nil
:chat.ui/clear-inputs-old nil
@@ -22,24 +22,26 @@
::logout nil
::multiaccounts/webview-debug-changed false
:keychain/clear-user-password key-uid
:setup/open-multiaccounts #(re-frame/dispatch [:setup/initialize-multiaccounts % {:logout? logout?}])}
:setup/open-multiaccounts #(re-frame/dispatch [:setup/initialize-multiaccounts
% {:logout? logout?}])}
(keychain/save-auth-method key-uid auth-method)
(wallet/clear-timeouts)
(init/initialize-app-db))))
(fx/defn logout
{:events [:logout :multiaccounts.logout.ui/logout-confirmed :multiaccounts.update.callback/save-settings-success]}
(rf/defn logout
{:events [:logout :multiaccounts.logout.ui/logout-confirmed
:multiaccounts.update.callback/save-settings-success]}
[cofx]
;; we need to disable notifications before starting the logout process
(fx/merge cofx
{:dispatch [:wallet-connect-legacy/clean-up-sessions]
(rf/merge cofx
{:dispatch [:wallet-connect-legacy/clean-up-sessions]
:dispatch-later [{:ms 100
:dispatch [::logout-method
{:auth-method keychain/auth-method-none
:logout? true}]}]}
(notifications/logout-disable)))
(fx/defn show-logout-confirmation
(rf/defn show-logout-confirmation
{:events [:multiaccounts.logout.ui/logout-pressed]}
[_]
{:ui/show-confirmation
@@ -49,10 +51,10 @@
:on-accept #(re-frame/dispatch [:multiaccounts.logout.ui/logout-confirmed])
:on-cancel nil}})
(fx/defn biometric-logout
(rf/defn biometric-logout
{:events [:biometric-logout]}
[cofx]
(fx/merge cofx
(rf/merge cofx
(logout-method {:auth-method keychain/auth-method-biometric-prepare
:logout? false})
(fn [{:keys [db]}]
+85 -68
View File
@@ -1,49 +1,52 @@
(ns status-im.multiaccounts.recover.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.mnemonic :as mnemonic]
[status-im.keycard.nfc :as nfc]
[status-im.i18n.i18n :as i18n]
[status-im.keycard.nfc :as nfc]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.multiaccounts.create.core :as multiaccounts.create]
[status-im.native-module.core :as status]
[status-im.popover.core :as popover]
[status-im2.navigation.events :as navigation]
[status-im.utils.fx :as fx]
[status-im.utils.security :as security]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[status-im.bottom-sheet.core :as bottom-sheet]
[taoensso.timbre :as log]))
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.re-frame :as rf]
[utils.security.core :as security]))
(defn existing-account?
[multiaccounts key-uid]
{:pre [(not (nil? key-uid))]}
(contains? multiaccounts key-uid))
(defn check-phrase-warnings [recovery-phrase]
(defn check-phrase-warnings
[recovery-phrase]
(cond (string/blank? recovery-phrase) :t/required-field))
(fx/defn set-phrase
(rf/defn set-phrase
{:events [:multiaccounts.recover/passphrase-input-changed]}
[{:keys [db]} masked-recovery-phrase]
(let [recovery-phrase (security/safe-unmask-data masked-recovery-phrase)]
(fx/merge
{:db (update db :intro-wizard assoc
:passphrase (string/lower-case recovery-phrase)
:passphrase-error nil
(rf/merge
{:db (update db
:intro-wizard assoc
:passphrase (string/lower-case recovery-phrase)
:passphrase-error nil
:next-button-disabled? (or (empty? recovery-phrase)
(not (mnemonic/valid-length? recovery-phrase))))})))
(fx/defn validate-phrase-for-warnings
(rf/defn validate-phrase-for-warnings
[{:keys [db]}]
(let [recovery-phrase (get-in db [:intro-wizard :passphrase])]
{:db (update db :intro-wizard assoc
{:db (update db
:intro-wizard assoc
:passphrase-error (check-phrase-warnings recovery-phrase))}))
(fx/defn on-store-multiaccount-success
(rf/defn on-store-multiaccount-success
{:events [::store-multiaccount-success]
:interceptors [(re-frame/inject-cofx :random-guid-generator)
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
@@ -54,29 +57,32 @@
:content (i18n/label :t/multiaccount-exists-title)
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :multiaccounts])}}
(let [{:keys [key-uid] :as multiaccount} (get-in db [:intro-wizard :root-key])
keycard-multiaccount? (boolean (get-in db [:multiaccounts/multiaccounts key-uid :keycard-pairing]))]
keycard-multiaccount? (boolean (get-in db
[:multiaccounts/multiaccounts key-uid
:keycard-pairing]))]
(if keycard-multiaccount?
;; trying to recover multiaccount created with keycard
{:db (-> db
(update :intro-wizard assoc
:processing? false
:passphrase-error :recover-keycard-multiaccount-not-supported)
(update :intro-wizard dissoc
:passphrase-valid?))}
{:db (-> db
(update :intro-wizard assoc
:processing? false
:passphrase-error :recover-keycard-multiaccount-not-supported)
(update :intro-wizard
dissoc
:passphrase-valid?))}
(let [multiaccount (assoc multiaccount :derived (get-in db [:intro-wizard :derived]))]
(multiaccounts.create/on-multiaccount-created cofx
multiaccount
password
{})))))))
(fx/defn store-multiaccount
(rf/defn store-multiaccount
{:events [::recover-multiaccount-confirmed]}
[{:keys [db]} password]
(let [{:keys [root-key]} (:intro-wizard db)
(let [{:keys [root-key]} (:intro-wizard db)
{:keys [id key-uid]} root-key
callback #(re-frame/dispatch [::store-multiaccount-success % password])
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
{:db (assoc-in db [:intro-wizard :processing?] true)
callback #(re-frame/dispatch [::store-multiaccount-success % password])
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
{:db (assoc-in db [:intro-wizard :processing?] true)
::multiaccounts.create/store-multiaccount [id key-uid hashed-password callback]}))
(re-frame/reg-fx
@@ -99,17 +105,18 @@
(fn [result]
(let [derived-data (multiaccounts.create/normalize-derived-data-keys
(types/json->clj result))
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
public-key (get-in derived-data [constants/path-whisper-keyword :public-key])]
(status/gfycat-identicon-async
public-key
(fn [name identicon]
(let [derived-data-extended
(update derived-data
constants/path-whisper-keyword
merge {:name name :identicon identicon})]
merge
{:name name :identicon identicon})]
(re-frame/dispatch [success-event root-data derived-data-extended]))))))))))))
(fx/defn show-existing-multiaccount-alert
(rf/defn show-existing-multiaccount-alert
[_ key-uid]
{:utils/show-confirmation
{:title (i18n/label :t/multiaccount-exists-title)
@@ -121,24 +128,26 @@
[:multiaccounts.login.ui/multiaccount-selected key-uid]))
:on-cancel #(re-frame/dispatch [:pop-to-root-tab :multiaccounts])}})
(fx/defn on-import-multiaccount-success
(rf/defn on-import-multiaccount-success
{:events [::import-multiaccount-success]}
[{:keys [db] :as cofx} {:keys [key-uid] :as root-data} derived-data]
(let [multiaccounts (:multiaccounts/multiaccounts db)]
(fx/merge
(rf/merge
cofx
{:db (update db :intro-wizard
assoc :root-key root-data
:derived derived-data
:step :recovery-success)}
{:db (update db
:intro-wizard
assoc
:root-key root-data
:derived derived-data
:step :recovery-success)}
(when (existing-account? multiaccounts key-uid)
(show-existing-multiaccount-alert key-uid))
(navigation/navigate-to-cofx :recover-multiaccount-success nil))))
(fx/defn enter-phrase-pressed
(rf/defn enter-phrase-pressed
{:events [::enter-phrase-pressed]}
[{:keys [db] :as cofx}]
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc :intro-wizard
@@ -153,7 +162,7 @@
(bottom-sheet/hide-bottom-sheet)
(navigation/navigate-to-cofx :recover-multiaccount-enter-phrase nil)))
(fx/defn proceed-to-import-mnemonic
(rf/defn proceed-to-import-mnemonic
{:events [:multiaccounts.recover/phrase-validated]}
[{:keys [db] :as cofx} phrase-warnings]
(let [{:keys [password passphrase]} (:intro-wizard db)]
@@ -165,37 +174,41 @@
(security/safe-unmask-data password))
:success-event ::import-multiaccount-success}}))))
(fx/defn seed-phrase-next-pressed
(rf/defn seed-phrase-next-pressed
{:events [:multiaccounts.recover/enter-phrase-next-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [passphrase]} (:intro-wizard db)]
{::multiaccounts/validate-mnemonic [passphrase #(re-frame/dispatch [:multiaccounts.recover/phrase-validated %])]}))
{::multiaccounts/validate-mnemonic [passphrase
#(re-frame/dispatch [:multiaccounts.recover/phrase-validated
%])]}))
(fx/defn continue-to-import-mnemonic
(rf/defn continue-to-import-mnemonic
{:events [::continue-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [password passphrase]} (:multiaccounts/recover db)]
(fx/merge cofx
(rf/merge cofx
{::import-multiaccount {:passphrase passphrase
:password password
:success-event ::import-multiaccount-success}}
(popover/hide-popover))))
(fx/defn dec-step
(rf/defn dec-step
{:events [:multiaccounts.recover/dec-step]}
[{:keys [db] :as cofx}]
(let [step (get-in db [:intro-wizard :step])]
(if (= step :enter-phrase)
{:db (dissoc db :intro-wizard)}
{:db (update db :intro-wizard assoc :step
{:db (update db
:intro-wizard assoc
:step
(case step
:recovery-success :enter-phrase
:recovery-success :enter-phrase
:select-key-storage :recovery-success
:create-code :select-key-storage)
:create-code :select-key-storage)
:confirm-failure? false
:key-code nil)})))
:key-code nil)})))
(fx/defn cancel-pressed
(rf/defn cancel-pressed
{:events [:multiaccounts.recover/cancel-pressed]}
[{:keys [db] :as cofx} skip-alert?]
;; Workaround for multiple Cancel button clicks
@@ -207,11 +220,11 @@
(i18n/label :t/are-you-sure-to-cancel)
(i18n/label :t/you-will-start-from-scratch)
#(re-frame/dispatch [:multiaccounts.recover/cancel-pressed true]))
(fx/merge cofx
(rf/merge cofx
dec-step
navigation/navigate-back)))))
(fx/defn select-storage-next-pressed
(rf/defn select-storage-next-pressed
{:events [:multiaccounts.recover/select-storage-next-pressed]
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
[{:keys [db] :as cofx}]
@@ -219,51 +232,55 @@
(if (= storage-type :advanced)
;;TODO: fix circular dependency to remove dispatch here
{:dispatch [:recovery.ui/keycard-option-pressed]}
(fx/merge cofx
(rf/merge cofx
{:db (update db :intro-wizard assoc :step :create-code)}
(navigation/navigate-to-cofx :create-password nil)))))
(fx/defn re-encrypt-pressed
(rf/defn re-encrypt-pressed
{:events [:multiaccounts.recover/re-encrypt-pressed]}
[{:keys [db] :as cofx}]
(fx/merge cofx
{:db (update db :intro-wizard
assoc :step :select-key-storage
(rf/merge cofx
{:db (update db
:intro-wizard
assoc
:step :select-key-storage
:selected-storage-type :default)}
(if (nfc/nfc-supported?)
(navigation/navigate-to-cofx :select-key-storage nil)
(select-storage-next-pressed))))
(fx/defn confirm-password-next-button-pressed
{:events [:multiaccounts.recover/enter-password-next-pressed]
(rf/defn confirm-password-next-button-pressed
{:events [:multiaccounts.recover/enter-password-next-pressed]
:interceptors [(re-frame/inject-cofx :random-guid-generator)]}
[cofx key-code]
(store-multiaccount cofx key-code))
(fx/defn count-words
(rf/defn count-words
[{:keys [db]}]
(let [passphrase (get-in db [:intro-wizard :passphrase])]
{:db (assoc-in db [:intro-wizard :passphrase-word-count]
(mnemonic/words-count passphrase))}))
{:db (assoc-in db
[:intro-wizard :passphrase-word-count]
(mnemonic/words-count passphrase))}))
(fx/defn run-validation
(rf/defn run-validation
[{:keys [db] :as cofx}]
(let [passphrase (get-in db [:intro-wizard :passphrase])]
(when (= (last passphrase) " ")
(fx/merge cofx
(rf/merge cofx
(validate-phrase-for-warnings)))))
(fx/defn enter-phrase-input-changed
(rf/defn enter-phrase-input-changed
{:events [:multiaccounts.recover/enter-phrase-input-changed]}
[cofx input]
(fx/merge cofx
(rf/merge cofx
(set-phrase input)
(count-words)
(run-validation)))
(fx/defn enter-passphrase-input-changed
(rf/defn enter-passphrase-input-changed
{:events [:multiaccounts.recover/enter-passphrase-input-changed]}
[{:keys [db]} masked-passphrase]
{:db (update db :intro-wizard assoc
:password masked-passphrase
{:db (update db
:intro-wizard assoc
:password masked-passphrase
:password-error nil)})

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