Compare commits

..
Author SHA1 Message Date
Omar Basem b8a84e91d4 refactor 2022-12-29 07:26:24 +04:00
Omar Basem 9a0cb79a2e reformat 2022-12-29 07:07:08 +04:00
Omar Basem cc665a8683 refactor 2022-12-29 07:07:08 +04:00
Omar Basem 30bf4a2d92 refactor 2022-12-29 07:07:07 +04:00
Omar Basem c04cb79085 refactor 2022-12-29 07:07:07 +04:00
Omar Basem fd747614f9 lint 2022-12-29 07:07:07 +04:00
Omar Basem faaecfaa95 feat: album 2022-12-29 07:07:07 +04:00
Omar Basem f201ebc09f feat: images album 2022-12-29 07:07:06 +04:00
Omar Basem 9c0361adef updates
https://github.com/status-im/status-go/compare/b4bdfd3d...6abbe98c
2022-12-29 07:07:06 +04:00
Omar Basem 9d8e6aa224 updates 2022-12-29 07:07:06 +04:00
Omar Basem 599d293f9a updates 2022-12-29 07:07:02 +04:00
Icaro Motta 915b8ebd9a New component Selector > Filter (#14650) 2022-12-28 12:21:15 -03:00
Christoph Pader 6280a6c4d5 feat: implement quo2 bottom sheet component (#14209) 2022-12-28 15:23:58 +01:00
Omar Basem b45261f2e5 Photo selector fix (#14646)
* fix: photo-selector
2022-12-28 14:40:13 +04:00
yqrashawn 4ce71e4d29 refactor: fix make lint and reformat (#14653) 2022-12-28 15:47:55 +08:00
yqrashawn 9ded8bfe97 chore: tweak zprint conf (#14645) 2022-12-28 10:05:24 +08:00
Jamie Caprani aca8c9250f add Non Token Gated - Manual Approval Required flow (#14513)
chore: add flow for closed community overview page
2022-12-26 16:05:03 -08:00
Mohamed Javid 99f7788c22 [Fix] Scroll To Index bug in Scrollable Tabs (#14641) 2022-12-27 00:13:24 +08:00
Volodymyr Kozieiev 9c7b69a2cd status-im/utils/fx replaced with utils/re-frame to avoid unambiguities (#14640) 2022-12-26 15:00:17 +00:00
flexsurfer a39e0f6fbd move messages to status-im2 (#14573)
* move messages to status-im2
2022-12-23 15:33:54 +01:00
Icaro Motta a8d392e4de Redirect user to Activity Center to manage pending contact requests (#14610) 2022-12-23 11:30:46 -03:00
Ibrahem Khalil d9e8fea14b Fix bottom spacing on image selector (#14612) 2022-12-23 10:33:01 +02:00
andrey 8ff32f4fc3 Revert "Group details screen (3) (#14494)"
This reverts commit e21b8d4396.
2022-12-23 07:32:23 +01:00
Omar Basem e21b8d4396 Group details screen (3) (#14494)
* group details screen (3)
2022-12-23 07:18:09 +04:00
Ibrahem Khalil 1af6d925d2 Message input issues (#14571) 2022-12-22 22:38:55 +02:00
Jamie Caprani 9937914594 feat: add banner component to quo2 (#14608) 2022-12-22 05:20:38 -08:00
yqrashawn e9252f5025 refactor: migrate json-rpc to status-im2.common.json-rpc.events (#14614) 2022-12-22 14:03:55 +08:00
Jamie Caprani 2610f27190 chore: add component tests (#14538) 2022-12-21 15:35:27 -08:00
Ibrahem Khalil 3dda878742 Add elevation to show image list (#14609) 2022-12-21 21:32:23 +02:00
pavloburykh 1fb41b2ca0 e2e: nightly fixes 2022-12-21 19:17:14 +02:00
Mohamed Javid 7c2d76d00f Channel name update in Context Tag (#14578)
* [Update][#14555] Channel name update in Context Tag

* [Update][#14555] Changes requested on Context Tag Component

* [Update][#14555] Changes requested on Context Tag Component
2022-12-21 20:03:58 +08:00
flexsurfer 270acefcf1 bump status-go v0.117.1a, fix empty chat (#14596) 2022-12-21 10:47:31 +01:00
Roman Volosovskyi 45e05b3f2b [#14545] Force update wakuv2 default configs 2022-12-21 10:24:37 +01:00
Ajay Sivan 9f1af8a9c2 fix: Chat scroll to bottom (#14570) 2022-12-21 10:14:38 +01:00
yqrashawn 69c90c25ab fix: fx merge error on ::json-rpc/call (#14594) 2022-12-21 16:43:38 +08:00
yqrashawn 388e5fae22 fix: toast component based on review (#14593) 2022-12-21 14:46:57 +08:00
yqrashawnandrefactor-only 0a8993bbf1 refactor: reformat all clojure code with zprint (#14589)
Co-authored-by: refactor-only <auto@status.im>
2022-12-20 22:45:37 +08: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
374 changed files with 9768 additions and 6349 deletions
+21 -20
View File
@@ -1,20 +1,21 @@
{: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
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]}}
: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
+5 -4
View File
@@ -19,15 +19,17 @@
:respect-bl]
:fn-map
{"reg-sub" :arg1-pair
"h/describe" :arg1-body
"h/test" :arg1-body
"global.describe" :arg1-body
"global.test" :arg1-body
"list-comp" :binding
"defview" :arg1-body
"letsubs" :binding
"testing" :arg1-body
"deftest-sub" :arg1-body
"wait-for" :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?]]}]
@@ -39,7 +41,6 @@
: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}}
+14 -7
View File
@@ -289,15 +289,14 @@ 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 | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$ || echo shadow-cljs.edn) && \
zprint '{:search-config? true}' -fc $$TARGETS
ALL_CLOJURE_FILE=$$(git ls-files | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$) && \
zprint '{:search-config? true}' -sfc $$ALL_CLOJURE_FILE
lint-fix: export TARGET := default
lint-fix: ##@test Run code style checks and fix issues
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
ALL_CLOJURE_FILE=$$(git ls-files | grep -e \.clj$$ -e \.cljs$$ -e \.cljc$$ -e \.edn$$) && \
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILE && \
zprint '{:search-config? true}' -sw $$ALL_CLOJURE_FILE
shadow-server: export TARGET := clojure
@@ -309,6 +308,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
@@ -323,7 +330,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.
+27 -11
View File
@@ -399,13 +399,15 @@ src
├── react_native
│ ├── gesture.cljs
│ └── platform.cljs
├── status_im
├── status_im/
├── status_im2
│ ├── common
│ │ └── components
│ │ └── bottom_sheet.cljs
│ ├── contexts/
│ ├── setup/
│ └── subs/
├── test_helpers/
└── utils.cljs
```
@@ -414,17 +416,23 @@ src
- `src/quo2/`: The component library for Status Mobile.
- `src/react_native/`: Contains only low-level constructs to help React Native
work in tandem with Clojure(Script).
- `src/status_im/common/`: Directories named `common` can appear at any level of
the directory tree. Just like directories named `utils`, their directory
- `src/status_im2/`: Directory where we try to be as strict as possible about
our guidelines and where we prefer to write code for the new, redesigned
mobile app.
- `src/status_im/`: Directory containing what we call "old code", not yet
migrated to new guidelines for the new mobile app.
- `src/status_im2/common/`: Directories named `common` can appear at any level
of the directory tree. Just like directories named `utils`, their directory
nesting level communicates their applicable limits.
- `src/status_im/common/components/`: Contains reusable components that are not
- `src/status_im2/common/components/`: Contains reusable components that are not
part of the design system (quo2).
- `src/status_im/contexts/`: Contains [bounded contexts](#glossary), like
- `src/status_im2/contexts/`: Contains [bounded contexts](#glossary), like
`browser/`, `messaging/`, etc. As much as possible, _bounded contexts_ should
not directly require each other's namespaces.
- `src/status_im/setup/`: Contains namespaces that are mostly used to initialize
the application, configure test runners, etc. In general, such namespaces
should not be required from the outside.
- `src/status_im2/setup/`: Contains namespaces that are mostly used to
initialize the application, configure test runners, etc. In general, such
namespaces should not be required from the outside.
- `src/test_helpers/`: Reusable utilities for writing all kinds of tests.
- `src/status_im/subs/`: All subscriptions should live inside it.
Directories named `utils/` can appear at any level of the directory tree. The
@@ -485,18 +493,26 @@ src
[Unit tests](#glossary) should be created alongside their respective source
implementation. We prefer them colocated with the source and not like most
Clojure (JVM) codebases which mirror the sources in a top-level test directory.
Component tests should be created in a separate directory `__tests__`. Example:
```
├── models
│ ├── message.cljs
│ └── message_test.cljs
├── __tests__
│ └── input_bla_test.cljs
├── models.cljs
└── models_test.cljs
```
Component tests should be created in a separate directory `__tests__`, colocated
with the source. When the entire component implementation is isolated under a
single directory, create a test file named `component_spec.cljs` instead.
```
└── filter
├── component_spec.cljs
├── style.cljs
└── view.cljs
```
There's no hard rule on how integration test namespaces should be split, but
we're at least striving to define them under appropriate bounded contexts that
mirror the source code.
@@ -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
{
+1 -1
View File
@@ -18,7 +18,7 @@ in mkShell {
# build specific utilities
clojure maven watchman
# lint specific utilities
clj-kondo zprint clojure-lsp
clj-kondo zprint
# other nice to have stuff
yarn nodejs python27
] # and some special cases
+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

+16 -10
View File
@@ -19,6 +19,7 @@
;; routing
[bidi "2.1.6"]
;; test dependencies
[camel-snake-kebab "0.4.3"]
[day8.re-frame/test "0.1.5"]
[com.taoensso/tufte "2.1.0"]]
@@ -81,20 +82,25 @@
:output-dir "target/test"
:optimizations :simple
:target :node-test
:main status-im.test-runner/main
;; 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
: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}}
: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
+15
View File
@@ -0,0 +1,15 @@
import {useDerivedValue, runOnJS as reaRunOnJS, runOnJS} from "react-native-reanimated";
export function useTranslateY(initialTranslationY, bottomSheetDy, panY) {
return useDerivedValue(() => {
return initialTranslationY - (bottomSheetDy.value - panY.value)
})
}
export function useBackgroundOpacity(translateY, backgroundHeight, windowHeight) {
return useDerivedValue(() => {
const opacity = ((translateY.value - windowHeight) / -backgroundHeight) * 0.5
return Math.max(Math.min(opacity, 0.5), 0)
})
}
+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);
}
);
}
+29 -3
View File
@@ -4,6 +4,22 @@
(: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 {}}})
@@ -122,8 +138,10 @@
(def react-native-share #js {:default {}})
(def react-native-svg
#js
{:SvgUri #js {:render identity}
:SvgXml #js {:render identity}})
{:SvgUri #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 {})
@@ -236,7 +254,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 {}
@@ -321,6 +342,9 @@
(def shell-worklets #js {})
(def bottom-sheet #js {})
(def record-audio-worklets #js {})
;; Update i18n_resources.cljs
(defn mock
[module]
@@ -369,6 +393,8 @@
"react-native-svg" react-native-svg
"../src/js/worklet_factory.js" worklet-factory
"../src/js/shell_worklets.js" shell-worklets
"../src/js/bottom_sheet.js" bottom-sheet
"../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,17 @@
(ns quo2.components.banners.--tests--.banner-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.banners.banner.view :as banner]
[reagent.core :as reagent]))
(defn render-banner
[opts]
(rtl/render (reagent/as-element [banner/banner opts])))
(js/global.test "basic render of banner component"
(fn []
(render-banner {:pins-count "5"
:latest-pin-text "this message"})
(-> (js/expect (rtl/screen.getByText "this message"))
(.toBeTruthy))
(-> (js/expect (rtl/screen.getByText "5"))
(.toBeTruthy))))
@@ -0,0 +1,19 @@
(ns quo2.components.banners.banner.style
(:require [quo2.foundations.colors :as colors]))
(def container
{:width "100%"
:height 50
:background-color colors/primary-50-opa-20
:flex-direction :row
:align-items :center
:padding-horizontal 20
:padding-vertical 10})
(def counter
{:padding-right 22
:height 20
:width 20
:justify-content :center
:align-items :center})
@@ -0,0 +1,24 @@
(ns quo2.components.banners.banner.view
(:require [quo2.components.banners.banner.style :as style]
[quo2.components.counter.counter :as counter]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[react-native.core :as rn]))
(defn banner
[{:keys [show-pin? latest-pin-text pins-count on-press]}]
[rn/touchable-opacity
{:accessibility-label :pinned-banner
:style style/container
:active-opacity 1
:on-press on-press}
(when show-pin? [icons/icon :i/pin {:size 20}])
[text/text
{:number-of-lines 1
:size :paragraph-2
:style {:margin-left 10 :margin-right 50}}
latest-pin-text]
[rn/view
{:accessibility-label :pins-count
:style style/counter}
(when (pos? pins-count) [counter/counter {:type :secondary} pins-count])]])
@@ -0,0 +1,28 @@
(ns quo2.components.buttons.--tests--.buttons-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.buttons.button :as button]
[reagent.core :as reagent]))
(defn render-button
([options label]
(rtl/render (reagent/as-element [button/button options label]))))
(js/global.test "default render of button component"
(fn []
(render-button {:accessibility-label "test-button"} "")
(-> (js/expect (rtl/screen.getByLabelText "test-button"))
(.toBeTruthy))))
(js/global.test "button renders with a label"
(fn []
(render-button {} "test-label")
(-> (js/expect (rtl/screen.getByText "test-label"))
(.toBeTruthy))))
(js/global.test "button on-press works"
(let [event (js/jest.fn)]
(fn []
(render-button {:on-press event} "test-label")
(rtl/fireEvent.press (rtl/screen.getByText "test-label"))
(-> (js/expect event)
(.toHaveBeenCalledTimes 1)))))
@@ -1,12 +1,15 @@
(ns quo2.components.community.community-card-view
(:require [quo2.components.community.community-view :as community-view]
[quo2.components.community.icon :as icon]
[quo2.components.community.style :as style]
[react-native.core :as rn]))
(defn community-card-view-item
[{:keys [name description locked
[{:keys [name description locked images
status tokens cover tags width]} on-press]
[rn/touchable-opacity {:on-press on-press}
[rn/touchable-opacity
{:accessibility-label :community-card-item
:on-press on-press}
[rn/view {:style (style/community-card 20)}
[rn/view
{:style {:width width
@@ -22,9 +25,9 @@
{:flex 1
:border-radius 20}}]]
[rn/view (style/card-view-content-container 12)
[rn/view (style/card-view-chat-icon 48)]
;;TODO new pure component based on quo2 should be implemented without status-im usage
;[communities.icon/community-icon-redesign community 48]]
[rn/view (style/card-view-chat-icon 48)
[icon/community-icon {:images images} 48]]
(when (= status :gated)
[rn/view (style/permission-tag-styles)
[community-view/permission-tag-container
+13
View File
@@ -0,0 +1,13 @@
(ns quo2.components.community.icon
(:require [react-native.core :as rn]))
(defn community-icon
[{:keys [images]} size]
(let [thumbnail-image (get-in images [:thumbnail :uri])]
[rn/image
{:source {:uri thumbnail-image}
:style {:border-radius 50
:border-width 0
:border-color :transparent
:width size
:height size}}]))
@@ -10,25 +10,25 @@
(rtl/render (reagent/as-element [counter/counter opts value]))))
(js/global.test "default render of counter component"
(fn []
(render-counter)
(-> (js/expect (rtl/screen.getByTestId "counter-component"))
(.toBeTruthy))))
(fn []
(render-counter)
(-> (js/expect (rtl/screen.getByTestId "counter-component"))
(.toBeTruthy))))
(js/global.test "renders counter with a string value"
(fn []
(render-counter {} "1")
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(fn []
(render-counter {} "1")
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(js/global.test "renders counter with an integer value"
(fn []
(render-counter {} 1)
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(fn []
(render-counter {} 1)
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(js/global.test "renders counter with value 99+ when the value is greater than 99"
(fn []
(render-counter {} "100")
(-> (js/expect (rtl/screen.getByText "99+"))
(.toBeTruthy))))
(fn []
(render-counter {} "100")
(-> (js/expect (rtl/screen.getByText "99+"))
(.toBeTruthy))))
@@ -0,0 +1,45 @@
(ns quo2.components.dividers.--tests--.divider-label-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.dividers.divider-label :as divider-label]
[reagent.core :as reagent]))
(defn render-divider-label
([]
(render-divider-label {}))
([opts]
(rtl/render (reagent/as-element [divider-label/divider-label opts]))))
(js/global.test "default render of divider-label component"
(fn []
(render-divider-label)
(-> (js/expect (rtl/screen.getByLabelText "divider-label"))
(.toBeTruthy))))
(js/global.test "render divider-label component with a label"
(fn []
(render-divider-label {:label :hello})
(-> (js/expect (rtl/screen.getByText "hello"))
(.toBeTruthy))))
(js/global.test "render divider-label component with a counter-value"
(fn []
(render-divider-label {:label :hello
:counter-value "1"})
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(js/global.test "divider-label chevron icon renders to the left when set"
(fn []
(render-divider-label {:label :hello
:counter-value "1"
:chevron-position :left})
(-> (js/expect (rtl/screen.getByTestId "divider-label-icon-left"))
(.toBeTruthy))))
(js/global.test "divider-label chevron icon renders to the right when set"
(fn []
(render-divider-label {:label :hello
:counter-value "1"
:chevron-position :right})
(-> (js/expect (rtl/screen.getByTestId "divider-label-icon-right"))
(.toBeTruthy))))
+3 -3
View File
@@ -7,9 +7,9 @@
(defn date
[value]
[rn/view
{:margin-vertical 16
:padding-right 8
:padding-left 62}
{:margin-vertical 8
:padding-right 20
:padding-left 60}
[text/text
{:weight :medium
:accessibility-label :divider-date-text
+16 -11
View File
@@ -23,14 +23,18 @@
text-and-icon-color (if dark? colors/neutral-40 colors/neutral-50)
counter-text-color (if dark? colors/white colors/neutral-100)]
[rn/view
{:style {:border-top-width 1
:border-top-color border-and-counter-bg-color
:padding-top padding-top
:padding-horizontal 16
:align-items :center
:flex-direction :row}}
{:accessible true
:accessibility-label :divider-label
:style {:border-top-width 1
:border-top-color border-and-counter-bg-color
:padding-top padding-top
:padding-horizontal 16
:align-items :center
:flex-direction :row}}
(when (= chevron-position :left)
[rn/view {:style {:margin-right 4}}
[rn/view
{:test-ID :divider-label-icon-left
:style {:margin-right 4}}
[icons/icon
:main-icons/chevron-down
{:color text-and-icon-color
@@ -43,10 +47,11 @@
:flex 1}}
label]
(when (= chevron-position :right)
[icons/icon
:main-icons/chevron-down
{:color text-and-icon-color
:size chevron-icon-container-width}])
[rn/view {:test-ID :divider-label-icon-right}
[icons/icon
:main-icons/chevron-down
{:color text-and-icon-color
:size chevron-icon-container-width}]])
(when (pos? counter-value)
[rn/view
{:style {:border-radius 6
@@ -8,56 +8,46 @@
(rtl/render (reagent/as-element [action-drawer/action-drawer options]))))
(js/global.test "action-drawer renders with elements label displaying"
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"}]])
(-> (js/expect (rtl/screen.getByText "a sample label"))
(.toBeTruthy))))
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"}]])
(-> (js/expect (rtl/screen.getByText "a sample label"))
(.toBeTruthy))))
(js/global.test "action-drawer renders with elements sub-label displaying"
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:sub-label "a sample sub label"}]])
(-> (js/expect (rtl/screen.getByText "a sample sub label"))
(.toBeTruthy))))
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:sub-label "a sample sub label"}]])
(-> (js/expect (rtl/screen.getByText "a sample sub label"))
(.toBeTruthy))))
(js/global.test "action-drawer on click action works on element"
(let [event (js/jest.fn)]
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:on-press event}]])
(rtl/fireEvent.press (rtl/screen.getByText "a sample label"))
(-> (js/expect event)
(.toHaveBeenCalled)))))
(let [event (js/jest.fn)]
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:on-press event}]])
(rtl/fireEvent.press (rtl/screen.getByText "a sample label"))
(-> (js/expect event)
(.toHaveBeenCalled)))))
(js/global.test "action-drawer renders two icons when set"
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:right-icon :i/friend
:accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action"))
(.toBeTruthy))
(-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action"))
(.toBeTruthy))))
(js/global.test "action-drawer does not render a divider when the add-divider? prop is false"
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:add-divider? false
:accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getAllByLabelText "divider"))
(.not)
(.toBeTruthy))))
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:right-icon :i/friend
:accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getByLabelText "right-icon-for-action"))
(.toBeTruthy))
(-> (js/expect (rtl/screen.queryByLabelText "left-icon-for-action"))
(.toBeTruthy))))
(js/global.test "action-drawer renders a divider when the add-divider? prop is true"
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:add-divider? true
:accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getAllByLabelText "divider"))
(.toBeTruthy))))
(fn []
(render-action-drawer [[{:icon :i/friend
:label "a sample label"
:add-divider? true
:accessibility-label :first-element}]])
(-> (js/expect (rtl/screen.getAllByLabelText "divider"))
(.toBeTruthy))))
@@ -0,0 +1,14 @@
(ns quo2.components.markdown.--tests--.text-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.markdown.text :as text]
[reagent.core :as reagent]))
(defn render-text
([options value]
(rtl/render (reagent/as-element [text/text options value]))))
(js/global.test "text renders with text"
(fn []
(render-text {} "hello")
(-> (js/expect (rtl/screen.getByText "hello"))
(.toBeTruthy))))
@@ -4,7 +4,6 @@
(def container
{:flex 1
:flex-wrap :wrap
:height 18
:flex-direction :row
:align-items :center})
@@ -40,4 +39,4 @@
(defn time-text
[ens?]
{:color colors/neutral-50
:margin-left (if ens? 8 4)})
:margin-left (if ens? 8 4)})
@@ -93,7 +93,8 @@
:style style/middle-dot-chat-key}
middle-dot])
[text/text
{:monospace true
:size :paragraph-2
:style (style/time-text ens?)}
{:monospace true
:size :paragraph-2
:accessibility-label :message-timestamp
:style (style/time-text ens?)}
time-str]]))])
+2 -3
View File
@@ -146,12 +146,11 @@
[rn/view
{:style (assoc centrify-style
:flex-direction :row
:flex 1
:justify-content :flex-end)}
(let [last-icon-index (-> right-section-buttons count dec)]
(map-indexed (fn [index {:keys [icon on-press type] :or {type :grey}}]
(map-indexed (fn [index {:keys [icon on-press type style] :or {type :grey}}]
^{:key index}
[rn/view {:style {:margin-right (if (not= index last-icon-index) 8 0)}}
[rn/view {:style (merge {:margin-right (if (not= index last-icon-index) 8 0)} style)}
[button/button {:on-press on-press :icon true :type type :size 32}
icon]])
right-section-buttons))])
@@ -0,0 +1,105 @@
(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)}])]])})))
@@ -4,18 +4,23 @@
[react-native.core :as rn]))
(defn info-count
[count style]
(when (> count 0)
[rn/view
{:style (merge {:width 16
:height 16
:position :absolute
:right 22
:border-radius 6
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/primary-50 colors/primary-60)}
style)}
[rn/text
{:style (merge typography/font-medium typography/label {:color colors/white :text-align :center})}
count]]))
([count]
(info-count {} count))
([props count]
(when (> count 0)
[rn/view
(merge props
{:style (merge {:width 16
:height 16
:position :absolute
:right 22
:border-radius 6
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/primary-50 colors/primary-60)}
(:style props))})
[rn/text
{:style (merge typography/font-medium
typography/label
{:color colors/white :text-align :center})}
count]])))
@@ -0,0 +1,81 @@
(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 :t/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)}])
+9 -44
View File
@@ -1,31 +1,18 @@
(ns quo2.components.reactions.reaction
(:require [quo2.components.icon :as icons]
[quo2.components.markdown.text :as quo2.text]
[quo2.components.markdown.text :as text]
[quo2.components.reactions.style :as style]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(def reaction-styling
{:flex-direction :row
:justify-content :center
:align-items :center
:padding-horizontal 8
:border-radius 8
:height 24})
(defn open-reactions-menu
(defn add-reaction
[{:keys [on-press]}]
(let [dark? (theme/dark?)]
[rn/touchable-opacity
{:on-press on-press
:accessibility-label :emoji-reaction-add
:style (merge reaction-styling
{:padding-horizontal 9
:border-width 1
:margin-top 5
:border-color (if dark?
colors/neutral-70
colors/neutral-30)})}
:style (style/add-reaction)}
[icons/icon :i/add
{:size 20
:color (if dark?
@@ -35,41 +22,19 @@
(defn reaction
"Add your emoji as a param here"
[{:keys [emoji clicks neutral? on-press accessibility-label]}]
(let [dark? (theme/dark?)
text-color (if dark?
colors/white
colors/neutral-100)
numeric-value (int clicks)
clicks-positive? (pos? numeric-value)]
(let [numeric-value (int clicks)]
[rn/touchable-opacity
{:on-press on-press
:accessibility-label accessibility-label
:style (merge reaction-styling
(cond->
{:background-color
(if dark?
(if neutral?
colors/neutral-70
:transparent)
(if neutral?
colors/neutral-30
:transparent))}
(and dark? (not neutral?))
(assoc :border-color colors/neutral-70
:border-width 1)
(and (not dark?) (not neutral?))
(assoc :border-color colors/neutral-30
:border-width 1)))}
:style (style/reaction neutral?)}
[icons/icon emoji
{:no-color true
:size 16}]
[quo2.text/text
[text/text
{:size :paragraph-2
:weight :semi-bold
:color text-color
:flex-direction :row
:align-items :center
:justify-content :center}
(if clicks-positive?
(str " " numeric-value)
"")]]))
(when (pos? numeric-value)
(str " " numeric-value))]]))
+34
View File
@@ -0,0 +1,34 @@
(ns quo2.components.reactions.style
(:require [quo2.foundations.colors :as colors]))
(def reaction-styling
{:flex-direction :row
:justify-content :center
:align-items :center
:padding-horizontal 8
:border-radius 8
:height 24})
(defn add-reaction
[]
(merge reaction-styling
{:padding-horizontal 9
:border-width 1
:border-color (colors/theme-colors colors/neutral-30 colors/neutral-70)}))
(defn reaction
[neutral?]
(merge reaction-styling
(cond->
{:background-color (colors/theme-colors (if neutral?
colors/neutral-30
:transparent)
(if neutral?
colors/neutral-70
:transparent))}
(and (colors/dark?) (not neutral?))
(assoc :border-color colors/neutral-70
:border-width 1)
(and (not (colors/dark?)) (not neutral?))
(assoc :border-color colors/neutral-30
:border-width 1))))
@@ -0,0 +1,228 @@
(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,767 @@
(ns quo2.components.record-audio.record-audio.view
(:require [cljs-bean.core :as bean]
[oops.core :as oops]
[quo.react :refer [effect! memo]]
[quo2.components.buttons.button :as button]
[quo2.components.icon :as icons]
[quo2.components.record-audio.record-audio.style :as style]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im.utils.utils :as utils]))
(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?]])))])
@@ -28,57 +28,57 @@
(rtl/render (reagent/as-element [selectors/radio opts]))))
(js/global.test "default render of toggle component"
(fn []
(render-toggle)
(-> (js/expect (rtl/screen.getByTestId "toggle-component"))
(.toBeTruthy))))
(fn []
(render-toggle)
(-> (js/expect (rtl/screen.getByTestId "toggle-component"))
(.toBeTruthy))))
(js/global.test "toggle component on change is working"
(let [mock-fn (js/jest.fn)]
(fn []
(render-toggle {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(let [mock-fn (js/jest.fn)]
(fn []
(render-toggle {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "toggle-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(js/global.test "default render of radio component"
(fn []
(render-radio)
(-> (js/expect (rtl/screen.getByTestId "radio-component"))
(.toBeTruthy))))
(fn []
(render-radio)
(-> (js/expect (rtl/screen.getByTestId "radio-component"))
(.toBeTruthy))))
(js/global.test "radio component on change is working"
(let [mock-fn (js/jest.fn)]
(fn []
(render-radio {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "radio-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(let [mock-fn (js/jest.fn)]
(fn []
(render-radio {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "radio-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(js/global.test "default render of checkbox component"
(fn []
(render-checkbox)
(-> (js/expect (rtl/screen.getByTestId "checkbox-component"))
(.toBeTruthy))))
(fn []
(render-checkbox)
(-> (js/expect (rtl/screen.getByTestId "checkbox-component"))
(.toBeTruthy))))
(js/global.test "checkbox component on change is working"
(let [mock-fn (js/jest.fn)]
(fn []
(render-checkbox {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(let [mock-fn (js/jest.fn)]
(fn []
(render-checkbox {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(js/global.test "default render of checkbox-prefill component"
(fn []
(render-checkbox-prefill)
(-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component"))
(.toBeTruthy))))
(fn []
(render-checkbox-prefill)
(-> (js/expect (rtl/screen.getByTestId "checkbox-prefill-component"))
(.toBeTruthy))))
(js/global.test "checkbox-prefill component on change is working"
(let [mock-fn (js/jest.fn)]
(fn []
(render-checkbox-prefill {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
(let [mock-fn (js/jest.fn)]
(fn []
(render-checkbox-prefill {:on-change mock-fn})
(rtl/fireEvent.press (rtl/screen.getByTestId "checkbox-prefill-component"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
@@ -1,32 +0,0 @@
(ns quo2.components.selectors.disclaimer
(:require [quo2.components.markdown.text :as text]
[quo2.components.selectors.selectors :as selectors]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
(defn disclaimer
[{:keys [on-change accessibility-label container-style]} label]
[rn/view
{:style
(merge
container-style
{:flex 1
:flex-direction :row
:background-color (colors/theme-colors
colors/neutral-5
colors/neutral-80-opa-40)
:padding 11
:align-self :stretch
:border-radius 12
:border-width 1
:border-color (colors/theme-colors
colors/neutral-20
colors/neutral-70)})}
[selectors/checkbox
{:on-change on-change}]
[text/text
{:accessibility-label accessibility-label
:size :paragraph-2
:style {:margin-left 8}}
label]])
@@ -0,0 +1,16 @@
(ns quo2.components.selectors.disclaimer.style
(:require [quo2.foundations.colors :as colors]))
(defn container
[]
{:flex 1
:flex-direction :row
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40)
:padding 11
:align-self :stretch
:border-radius 12
:border-width 1
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-70)})
(def text
{:margin-left 8})
@@ -0,0 +1,17 @@
(ns quo2.components.selectors.disclaimer.view
(:require [quo2.components.markdown.text :as text]
[quo2.components.selectors.disclaimer.style :as style]
[quo2.components.selectors.selectors :as selectors]
[react-native.core :as rn]))
(defn view
[{:keys [on-change accessibility-label container-style]} label]
[rn/view
{:style (merge container-style (style/container))}
[selectors/checkbox
{:accessibility-label accessibility-label
:on-change on-change}]
[text/text
{:size :paragraph-2
:style style/text}
label]])
@@ -0,0 +1,16 @@
(ns quo2.components.selectors.filter.component-spec
(:require [quo2.components.selectors.filter.view :as quo]
[test-helpers.component :as h]))
(h/describe "selector filter component"
(h/test "renders component"
(h/render [quo/view])
(-> (js/expect (h/get-by-label-text :selector-filter))
(.toBeTruthy)))
(h/test "calls custom event handler when on-press-out is triggered"
(let [on-press-out-mock (js/jest.fn)]
(h/render [quo/view {:on-press-out on-press-out-mock}])
(h/fire-event :press-out (h/get-by-label-text :selector-filter))
(-> (js/expect on-press-out-mock)
(.toHaveBeenCalledTimes 1)))))
@@ -0,0 +1,60 @@
(ns quo2.components.selectors.filter.style
(:require [quo2.foundations.colors :as colors]))
(def container-default
{:width 32
:height 32
:border-radius 10
:align-items :center
:justify-content :center
:padding 6})
(defn container-border-color
[pressed? blur? override-theme]
(let [dark? (= :dark override-theme)]
(cond
(and (not pressed?) (not dark?) (not blur?))
colors/neutral-20
(and (not pressed?) dark? (not blur?))
colors/neutral-80
(and pressed? (not dark?) blur?)
colors/neutral-80-opa-20
(or (and pressed? (not dark?) (not blur?))
(and (not pressed?) (not dark?) blur?))
colors/neutral-80-opa-10
(or (and pressed? dark? (not blur?))
(and (not pressed?) dark? blur?)
(and pressed? dark? blur?))
colors/white-opa-10
:else
nil)))
(defn container-background-color
[pressed? override-theme]
(when pressed?
(if (= :dark override-theme)
colors/primary-60
colors/primary-50)))
(defn container-outer
[pressed? override-theme]
(merge container-default
{:background-color (container-background-color pressed? override-theme)}))
(defn container-inner
[pressed? blur? override-theme]
(merge container-default
{:border-width 1
:border-color (container-border-color pressed? blur? override-theme)}))
(defn icon-color
[pressed? override-theme]
(if (and (not pressed?)
(= :light override-theme))
colors/neutral-100
colors/white))
@@ -0,0 +1,23 @@
(ns quo2.components.selectors.filter.view
(:require [quo2.components.icon :as icon]
[quo2.components.selectors.filter.style :as style]
[quo2.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[initial-props]
(let [pressed? (reagent/atom (:pressed? initial-props))]
(fn [{:keys [blur? override-theme on-press-out]
:or {override-theme (theme/get-theme)}}]
[rn/touchable-without-feedback
{:accessibility-label :selector-filter
:on-press-out (fn []
(swap! pressed? not)
(when on-press-out
(on-press-out @pressed?)))}
[rn/view {:style (style/container-outer @pressed? override-theme)}
[rn/view {:style (style/container-inner @pressed? blur? override-theme)}
[icon/icon :i/unread
{:color (style/icon-color @pressed? override-theme)
:size 20}]]]])))
+3 -2
View File
@@ -69,9 +69,10 @@
(defn checkbox
[{:keys [default-checked?]}]
(let [checked? (reagent/atom (or default-checked? false))]
(fn [{:keys [on-change disabled? blurred-background? container-style]}]
(fn [{:keys [on-change disabled? blurred-background? container-style accessibility-label]}]
[rn/touchable-without-feedback
{:on-press (handle-press disabled? on-change checked?)}
{:accessibility-label accessibility-label
:on-press (handle-press disabled? on-change checked?)}
[rn/view
{:style (merge
container-style
@@ -0,0 +1,67 @@
(ns quo2.components.settings.privacy-option
(:require [quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.components.selectors.selectors :as selectors]
[quo2.components.settings.style :as style]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
(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))})
+12 -10
View File
@@ -15,16 +15,17 @@
(defn indicator
[]
[rn/view
{:position :absolute
:z-index 1
:right -2
:top -2
:width 10
:height 10
:border-radius 5
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}
{:accessibility-label :notification-dot
:style {:position :absolute
:z-index 1
:right -2
:top -2
:width 10
:height 10
:border-radius 5
:justify-content :center
:align-items :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}}
[notification-dot]])
(defn tabs
@@ -138,6 +139,7 @@
:shows-horizontal-scroll-indicator false
:data data
:key-fn (comp str :id)
:on-scroll-to-index-failed identity
:on-scroll (fn [^js e]
(when fade-end?
(let [offset-x (oget
+26 -14
View File
@@ -1,5 +1,6 @@
(ns quo2.components.tags.context-tags
(:require [quo2.components.avatars.group-avatar :as group-avatar]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo2.theme]
@@ -57,20 +58,31 @@
(trim-public-key public-key)]]))
(defn context-tag
[params photo name]
(let [text-style (params :text-style)]
[base-tag (assoc-in params [:style :padding-left] 3)
[rn/image
{:style {:width 20
:border-radius 10
:background-color :white
:height 20}
:source photo}]
[text/text
(merge {:weight :medium
:size :paragraph-2}
{:style text-style})
(str " " name)]]))
[_ _]
(fn [params photo name channel-name]
(let [text-style (:text-style params)
text-params {:weight :medium
:size :paragraph-2
:style (assoc text-style :justify-content :center)}
icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)]
[base-tag (assoc-in params [:style :padding-left] 3)
[rn/image
{:style {:width 20
:border-radius 10
:background-color :white
:height 20}
:source photo}]
[rn/view
{:style {:align-items :center
:flex-direction :row}}
[text/text text-params (str " " name)]
(when channel-name
[:<>
[icons/icon
:i/chevron-right
{:color icon-color
:size 16}]
[text/text text-params (str "# " channel-name)]])]])))
(defn user-avatar-tag
[]
+66 -45
View File
@@ -1,49 +1,59 @@
(ns quo2.core
(:require quo2.components.avatars.account-avatar
quo2.components.avatars.channel-avatar
quo2.components.avatars.group-avatar
quo2.components.avatars.icon-avatar
quo2.components.avatars.user-avatar
quo2.components.avatars.wallet-user-avatar
quo2.components.buttons.button
quo2.components.buttons.dynamic-button
quo2.components.community.community-card-view
quo2.components.community.community-list-view
quo2.components.community.community-view
quo2.components.community.discover-card
quo2.components.community.token-gating
quo2.components.counter.counter
quo2.components.dividers.date
quo2.components.dividers.divider-label
quo2.components.dividers.new-messages
quo2.components.drawers.action-drawers
quo2.components.dropdowns.dropdown
quo2.components.header
quo2.components.icon
quo2.components.info.info-message
quo2.components.info.information-box
quo2.components.list-items.channel
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list
quo2.components.loaders.skeleton
quo2.components.markdown.text
quo2.components.messages.gap
quo2.components.messages.system-message
quo2.components.navigation.floating-shell-button
quo2.components.navigation.page-nav
quo2.components.notifications.activity-log.view
quo2.components.notifications.info-count
quo2.components.notifications.notification-dot
quo2.components.reactions.reaction
quo2.components.selectors.disclaimer
quo2.components.selectors.selectors
quo2.components.separator
quo2.components.tabs.account-selector
quo2.components.tabs.tabs
quo2.components.tags.context-tags
quo2.components.tags.status-tags
quo2.components.tags.tags))
(:refer-clojure :exclude [filter])
(:require
quo2.components.avatars.account-avatar
quo2.components.avatars.channel-avatar
quo2.components.avatars.group-avatar
quo2.components.avatars.icon-avatar
quo2.components.avatars.user-avatar
quo2.components.avatars.wallet-user-avatar
quo2.components.banners.banner.view
quo2.components.buttons.button
quo2.components.buttons.dynamic-button
quo2.components.community.community-card-view
quo2.components.community.community-list-view
quo2.components.community.community-view
quo2.components.community.discover-card
quo2.components.community.icon
quo2.components.community.token-gating
quo2.components.counter.counter
quo2.components.dividers.date
quo2.components.dividers.divider-label
quo2.components.dividers.new-messages
quo2.components.drawers.action-drawers
quo2.components.dropdowns.dropdown
quo2.components.header
quo2.components.icon
quo2.components.info.info-message
quo2.components.info.information-box
quo2.components.list-items.channel
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list
quo2.components.loaders.skeleton
quo2.components.markdown.text
quo2.components.messages.author.view
quo2.components.messages.gap
quo2.components.messages.system-message
quo2.components.navigation.floating-shell-button
quo2.components.navigation.page-nav
quo2.components.notifications.activity-log.view
quo2.components.notifications.count-down-circle
quo2.components.notifications.info-count
quo2.components.notifications.notification-dot
quo2.components.notifications.toast
quo2.components.reactions.reaction
quo2.components.selectors.disclaimer.view
quo2.components.selectors.filter.view
quo2.components.selectors.selectors
quo2.components.separator
quo2.components.settings.privacy-option
quo2.components.tabs.account-selector
quo2.components.tabs.tabs
quo2.components.tags.context-tags
quo2.components.tags.status-tags
quo2.components.tags.tags))
(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)
@@ -58,6 +68,7 @@
(def gap quo2.components.messages.gap/gap)
(def system-message quo2.components.messages.system-message/system-message)
(def reaction quo2.components.reactions.reaction/reaction)
(def add-reaction quo2.components.reactions.reaction/add-reaction)
(def tags quo2.components.tags.tags/tags)
(def user-avatar-tag quo2.components.tags.context-tags/user-avatar-tag)
(def context-tag quo2.components.tags.context-tags/context-tag)
@@ -68,9 +79,11 @@
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
(def status-tag quo2.components.tags.status-tags/status-tag)
(def page-nav quo2.components.navigation.page-nav/page-nav)
(def disclaimer quo2.components.selectors.disclaimer/disclaimer)
(def disclaimer quo2.components.selectors.disclaimer.view/view)
(def checkbox quo2.components.selectors.selectors/checkbox)
(def filter quo2.components.selectors.filter.view/view)
(def skeleton quo2.components.loaders.skeleton/skeleton)
(def author quo2.components.messages.author.view/author)
;;;; AVATAR
(def account-avatar quo2.components.avatars.account-avatar/account-avatar)
@@ -80,6 +93,9 @@
(def user-avatar quo2.components.avatars.user-avatar/user-avatar)
(def wallet-user-avatar quo2.components.avatars.wallet-user-avatar/wallet-user-avatar)
;;;; BANNER
(def banner quo2.components.banners.banner.view/banner)
;;;; COMMUNITY
(def community-card-view-item quo2.components.community.community-card-view/community-card-view-item)
(def communities-list-view-item quo2.components.community.community-list-view/communities-list-view-item)
@@ -92,6 +108,7 @@
(def permission-tag-container quo2.components.community.community-view/permission-tag-container)
(def discover-card quo2.components.community.discover-card/discover-card)
(def token-gating quo2.components.community.token-gating/token-gating)
(def community-icon quo2.components.community.icon/community-icon)
;;;; DIVIDERS
(def divider-label quo2.components.dividers.divider-label/divider-label)
@@ -107,3 +124,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)
+7 -2
View File
@@ -1,4 +1,9 @@
(ns quo2.core-spec
(:require [quo2.components.counter.--tests--.counter-component-spec]
(:require [quo2.components.banners.--tests--.banner-component-spec]
[quo2.components.buttons.--tests--.buttons-component-spec]
[quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.drawers.--tests--.action-drawers-component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]))
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.filter.component-spec]))
+27
View File
@@ -14,6 +14,21 @@
(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
@@ -50,6 +65,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))
@@ -68,11 +84,17 @@
(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-10 (alpha neutral-100 0.1))
(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
@@ -92,6 +114,11 @@
(def white-opa-90 (alpha white 0.9))
(def white-opa-95 (alpha white 0.95))
;;;;Black
;;Solid
(def black "#000000")
;;;;Primary
;;Solid
+22
View File
@@ -1,6 +1,9 @@
(ns react-native.core
(:require ["@react-native-community/blur" :as blur]
["react" :as react]
["react-native" :as react-native]
[cljs-bean.core :as bean]
[oops.core :as oops]
[react-native.flat-list :as flat-list]
[react-native.platform :as platform]
[react-native.section-list :as section-list]
@@ -64,6 +67,12 @@
(def status-bar (.-StatusBar ^js react-native))
(def style-sheet (.-StyleSheet ^js react-native))
(defn status-bar-height
[]
(.-currentHeight ^js status-bar))
(defn hw-back-add-listener
[callback]
(.addEventListener (.-BackHandler ^js react-native) "hardwareBackPress" callback))
@@ -80,3 +89,16 @@
(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"))))))
+8
View File
@@ -0,0 +1,8 @@
(ns react-native.hooks
(:require ["@react-native-community/hooks" :as hooks]))
(defn use-keyboard
[]
(let [kb (.useKeyboard hooks)]
{:keyboard-shown (.-keyboardShown ^js kb)
:keyboard-height (.-keyboardHeight ^js kb)}))
+52 -8
View File
@@ -1,11 +1,25 @@
(ns react-native.reanimated
(:require
["react-native" :as rn]
["react-native-linear-gradient" :default LinearGradient]
["react-native-reanimated" :default reanimated :refer
(useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe)]
[clojure.string :as string]
[reagent.core :as reagent]))
(:require ["react-native" :as rn]
["react-native-linear-gradient" :default LinearGradient]
["react-native-reanimated" :default reanimated :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)))
@@ -26,6 +40,7 @@
(def with-spring withSpring)
(def key-frame Keyframe)
(def with-repeat withRepeat)
(def cancel-animation cancelAnimation)
;; Easings
(def bezier (.-bezier ^js Easing))
@@ -60,6 +75,13 @@
;; 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
@@ -94,4 +116,26 @@
(js-obj "duration" duration
"easing" (get easings easing)))
number-of-repetitions
reverse?)))
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
@@ -8,7 +8,7 @@
(defn consumer
[component]
[consumer-raw
(fn [insets]
(fn [^js insets]
(reagent/as-element
[component (js->clj insets :keywordize-keys true)]))])
View File
+6
View File
@@ -0,0 +1,6 @@
(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))
+6 -6
View File
@@ -10,7 +10,7 @@
[status-im.i18n.i18n :as i18n]
[status-im.router.core :as router]
[status-im.utils.db :as utils.db]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.random :as random]
[status-im.utils.utils :as utils]
[status-im2.navigation.events :as navigation]))
@@ -24,7 +24,7 @@
;;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)))]
@@ -61,12 +61,12 @@
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}]
@@ -81,7 +81,7 @@
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))
@@ -93,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)
+11 -12
View File
@@ -1,26 +1,25 @@
(ns status-im.backup.core
(:require [re-frame.core :as re-frame]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(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)
::json-rpc/call [{:method "wakuext_backupData"
:params []
:on-error #(do
(log/error "failed to perfom backup" %)
(re-frame/dispatch [::backup-failed %]))
:on-success #(re-frame/dispatch [::backup-performed %])}]})
{:db (assoc db :backup/performing-backup true)
:json-rpc/call [{:method "wakuext_backupData"
:params []
:on-error #(do
(log/error "failed to perfom backup" %)
(re-frame/dispatch [::backup-failed %]))
:on-success #(re-frame/dispatch [::backup-performed %])}]})
+14 -14
View File
@@ -3,7 +3,7 @@
[re-frame.core :as re-frame]
[status-im.i18n.i18n :as i18n]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))
(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})")
@@ -19,12 +19,12 @@
:id (string/replace id "-" "")
:name bootnode-name})
(fx/defn fetch
(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
@@ -38,14 +38,14 @@
: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
fxs (rf/merge cofx
(set-input :id id)
(set-input :url (str address))
(set-input :name (str name)))]
@@ -56,11 +56,11 @@
(let [network (:networks/current-network db)]
(get-in db [:multiaccount :custom-bootnodes-enabled? network])))
(fx/defn delete
(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
@@ -68,7 +68,7 @@
{:success-event (when (custom-bootnodes-in-use? cofx)
[:multiaccounts.update.callback/save-settings-success])}))))
(fx/defn upsert
(rf/defn upsert
{:events [:bootnodes.ui/save-pressed]
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
[{{:bootnodes/keys [manage] :keys [multiaccount] :as db} :db
@@ -86,7 +86,7 @@
[network (:id bootnode)]
bootnode)]
(fx/merge cofx
(rf/merge cofx
{:db (dissoc db :bootnodes/manage)
:dispatch [:navigate-back]}
(multiaccounts.update/multiaccount-update
@@ -95,7 +95,7 @@
{: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)
@@ -106,14 +106,14 @@
(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]))
(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)
@@ -122,9 +122,9 @@
: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)))
+10 -6
View File
@@ -1,7 +1,7 @@
(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
@@ -9,7 +9,7 @@
: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,12 @@
{: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)})
(rf/defn hide-bottom-sheet-navigation-overlay
{:events [:bottom-sheet/hide-navigation-overlay]}
[{}]
{:hide-bottom-sheet nil})
+116 -114
View File
@@ -1,36 +1,37 @@
(ns status-im.browser.core
(: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-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]
[utils.debounce :as debounce]))
(: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.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]
[utils.re-frame :as rf]
[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]
[utils.debounce :as debounce]
[utils.security.core :as security]))
(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)})
@@ -51,22 +52,22 @@
(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]
:on-success #()}]})
{: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)
::json-rpc/call (for [browser-id (keys (get db :browser/browsers))]
{:method "wakuext_deleteBrowser"
:params [browser-id]
:on-success #()})})
{:db (dissoc db :browser/browsers)
:json-rpc/call (for [browser-id (keys (get db :browser/browsers))]
{:method "wakuext_deleteBrowser"
:params [browser-id]
:on-success #()})})
(defn update-dapp-name
[{:keys [name] :as browser}]
@@ -83,7 +84,7 @@
(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))
@@ -95,69 +96,69 @@
: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])]
:on-success #()}]}))
{: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]
:on-success #()}]})
{: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])
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]}]
(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))
@@ -168,16 +169,16 @@
[{: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)]
@@ -189,14 +190,14 @@
: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
(rf/merge cofx
{:db (-> (update db
:browser/options
assoc
@@ -204,7 +205,7 @@
: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
@@ -212,26 +213,27 @@
: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}))
(when (security/safe-link? 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])
@@ -249,18 +251,18 @@
(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)
@@ -268,12 +270,12 @@
(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"
@@ -283,12 +285,12 @@
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"
@@ -300,7 +302,7 @@
:history [normalized-url]}]
(if (links/universal-link? normalized-url)
{:dispatch [:universal-links/handle-url normalized-url]}
(fx/merge cofx
(rf/merge cofx
{:db (assoc db
:browser/options
{:browser-id (:browser-id browser)})}
@@ -309,12 +311,12 @@
(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
(rf/merge cofx
{:db (assoc db
:browser/options
{:browser-id browser-id})}
@@ -322,7 +324,7 @@
(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
@@ -330,7 +332,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
@@ -359,7 +361,7 @@
(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})
@@ -371,7 +373,7 @@
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])
@@ -431,7 +433,7 @@
:error %1
:result %2}])]}))))
(fx/defn handle-no-permissions
(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
@@ -457,28 +459,28 @@
(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
@@ -555,10 +557,10 @@
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)
@@ -568,38 +570,38 @@
{: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))
+12 -13
View File
@@ -4,14 +4,13 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.network.core :as network]
[status-im.ui.screens.browser.eip3085.sheet :as sheet]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.random :as random]
[taoensso.timbre :as log]))
(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
@@ -20,18 +19,18 @@
: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])
:on-error #(log/error "failed to perform settings_saveSetting" %)}]
:dispatch [:bottom-sheet/hide]})
{: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]})
(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
@@ -40,7 +39,7 @@
: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
+3 -3
View File
@@ -4,9 +4,9 @@
(:require [status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.ui.screens.browser.eip3326.sheet :as sheet]
[status-im.utils.fx :as fx]))
[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
@@ -15,7 +15,7 @@
: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)
+32 -33
View File
@@ -1,9 +1,8 @@
(ns status-im.browser.permissions
(:require [status-im.constants :as constants]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))
(declare process-next-permission)
@@ -21,18 +20,18 @@
: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]
@@ -48,7 +47,7 @@
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]
@@ -59,7 +58,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?
@@ -67,37 +66,37 @@
(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]
:on-success #()}]}))
{: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
{:db (update-in db [:dapps/permissions] dissoc dapp)
::json-rpc/call [{:method "permissions_deleteDappPermissions"
:params [dapp]
:on-success #()}]}))
(rf/merge cofx
{:db (update-in db [:dapps/permissions] dissoc 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)
::json-rpc/call (for [dapp dapp-permissions]
{:method "permissions_deleteDappPermissions"
:params [dapp]
:on-success #()})}))
{:db (dissoc db :dapps/permissions)
:json-rpc/call (for [dapp dapp-permissions]
{:method "permissions_deleteDappPermissions"
: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"
@@ -113,41 +112,41 @@
(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)
(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"
+92 -93
View File
@@ -3,22 +3,21 @@
[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.delete-message :as delete-message]
[status-im.chat.models.delete-message-for-me :as delete-for-me]
[status-im.chat.models.loading :as loading]
[status-im.chat.models.message-list :as message-list]
[status-im.constants :as constants]
[status-im.data-store.chats :as chats-store]
[status-im.data-store.contacts :as contacts-store]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.i18n.i18n :as i18n]
[status-im.mailserver.core :as mailserver]
[status-im.multiaccounts.model :as multiaccounts.model]
[status-im.ui.screens.chat.state :as chat.state]
[status-im.utils.clocks :as utils.clocks]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]
[status-im2.contexts.chat.messages.delete-message-for-me.events :as delete-for-me]
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
@@ -113,14 +112,14 @@
(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}]
(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]}
@@ -137,7 +136,7 @@
:chats-home-list #{}
:removed-chats #{}}
(map (map-chats cofx) chats))]
(fx/merge
(rf/merge
cofx
(merge {:db (-> db
(update :chats merge all-chats)
@@ -150,7 +149,7 @@
(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?
@@ -176,40 +175,40 @@
: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}]
:on-success #(re-frame/dispatch [::history-cleared chat-id %])
:on-error #(log/error "failed to clear history " 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 %)}]}
(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}]
:on-success #(re-frame/dispatch [::chat-deactivated chat-id])
:on-error #(log/error "failed to create public chat" 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 %)}]}
(clear-history chat-id true)))
(fx/defn offload-messages
(rf/defn offload-messages
{:events [:offload-messages]}
[{:keys [db]} chat-id]
(merge {:db (-> db
@@ -219,52 +218,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)
@@ -277,11 +276,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))
@@ -293,13 +292,13 @@
#(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)))
@@ -314,22 +313,22 @@
(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}]
: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 %)}]}))
{: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 %)}]}))
(defn profile-chat-topic
[public-key]
@@ -339,7 +338,7 @@
[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
@@ -347,14 +346,14 @@
(update :chats-home-list conj chat-id))
:dispatch [:chat.ui/navigate-to-chat chat-id]})
(fx/defn create-public-chat-go
(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 %)}]})
{: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 %)}]})
(fx/defn start-public-chat
(rf/defn start-public-chat
"Starts a new public chat"
{:events [:chat.ui/start-public-chat]}
[cofx topic]
@@ -367,10 +366,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
@@ -380,19 +379,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}]
:on-success #(re-frame/dispatch [::profile-chat-created chat-id % navigate-to?])
:on-error #(log/error "failed to create profile chat" chat-id %)}]})))
{: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 %)}]})))
(fx/defn disable-chat-cooldown
(rf/defn disable-chat-cooldown
"Turns off chat cooldown (protection against message spamming)"
{:events [:chat/disable-cooldown]}
[{:keys [db]}]
@@ -406,40 +405,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? %])
:on-success #(re-frame/dispatch [::mute-chat-toggled-successfully chat-id])}]}))
{: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
@@ -450,19 +449,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)
@@ -471,44 +470,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]
:on-success #(re-frame/dispatch [::gaps-filled chat-id gap-ids %])
:on-error #(re-frame/dispatch [::gaps-failed 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 %])}]})
(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]
: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 %])}]})
{: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 %])}]})
(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
@@ -519,7 +518,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
+48 -25
View File
@@ -9,7 +9,7 @@
[status-im.ui.components.react :as react]
[status-im.utils.config :as config]
[status-im.utils.fs :as fs]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.image-processing :as image-processing]
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
@@ -105,16 +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))
@@ -123,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))
@@ -168,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))
@@ -181,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))
@@ -198,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})
+53 -52
View File
@@ -9,10 +9,9 @@
[status-im.chat.models.message :as chat.message]
[status-im.chat.models.message-content :as message-content]
[status-im.constants :as constants]
[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]
[utils.re-frame :as rf]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
@@ -26,7 +25,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,21 +33,21 @@
(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))})
(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)
@@ -92,7 +91,7 @@
:chat/spam-messages-frequency 0
: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
@@ -115,12 +114,12 @@
(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)
@@ -129,7 +128,7 @@
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]
@@ -145,7 +144,7 @@
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}]
@@ -160,7 +159,7 @@
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]}]
@@ -185,17 +184,19 @@
(defn build-image-messages
[{db :db} chat-id]
(let [images (get-in db [:chat/inputs chat-id :metadata :sending-image])]
(let [images (get-in db [:chat/inputs chat-id :metadata :sending-image])
album-id (str (random-uuid))]
(mapv (fn [[_ {:keys [uri]}]]
{:chat-id chat-id
:album-id album-id
:content-type constants/content-type-image
:image-path (utils/safe-replace uri #"file://" "")
:text (i18n/label :t/update-to-see-image {"locale" "en"})})
images)))
(fx/defn clean-input
(rf/defn clean-input
[{:keys [db] :as cofx} current-chat-id]
(fx/merge cofx
(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)
@@ -203,29 +204,29 @@
(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
(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))]
(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}]
@@ -235,11 +236,11 @@
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
@@ -250,7 +251,7 @@
: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
@@ -260,44 +261,44 @@
:pack (int (if (string/blank? packID) pack packID))}
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})})))
(fx/defn send-edited-message
(rf/defn send-edited-message
[{:keys [db] :as cofx} text {:keys [message-id quoted-message]}]
(fx/merge
(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)}]
:js-response true
:on-error #(log/error "failed to edit message " %)
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}
{: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 %])}]}
(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
(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" %)
@@ -307,33 +308,33 @@
(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)))
::json-rpc/call [{:method "stickers_addRecent"
:params [(int (if (string/blank? packID) pack packID)) hash]
:on-success #()}]}
{: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))
+32 -33
View File
@@ -1,15 +1,14 @@
(ns status-im.chat.models.link-preview
(:require [re-frame.core :as re-frame]
[status-im.communities.core :as models.communities]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(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 +16,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?
@@ -40,7 +39,7 @@
[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)})
@@ -49,10 +48,10 @@
[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
@@ -60,29 +59,29 @@
(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)
::json-rpc/call [{:method "wakuext_requestCommunityInfoFromMailserver"
:params [community-id]
:on-success #(re-frame/dispatch [::community-resolved community-id %])
:on-error #(do
(re-frame/dispatch [::community-failed-to-resolve community-id])
(log/error "Failed to request community info from mailserver"))}]})
{:db (community-resolving db community-id)
:json-rpc/call [{:method "wakuext_requestCommunityInfoFromMailserver"
:params [community-id]
:on-success #(re-frame/dispatch [::community-resolved community-id %])
:on-error #(do
(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)}])}]})
{: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)}])}]})
(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
@@ -96,7 +95,7 @@
(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
@@ -105,14 +104,14 @@
(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")}]})
{: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
+31 -26
View File
@@ -1,13 +1,12 @@
(ns status-im.chat.models.loading
(:require [re-frame.core :as re-frame]
[status-im.activity-center.core :as activity-center]
[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.ethereum.json-rpc :as json-rpc]
[status-im.utils.fx :as fx]
[taoensso.timbre :as log]))
[status-im2.contexts.activity-center.events :as activity-center]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(defn cursor->clock-value
[^js cursor]
@@ -19,7 +18,7 @@
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]}
@@ -39,20 +38,20 @@
:chats-home-list chats-home-list
: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]
:on-success #(re-frame/dispatch [:chats-list/load-chat-success %])
:on-error #(log/error "failed to fetch chats" 0 -1 %)}]})
{: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 %)}]})
(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)
@@ -68,41 +67,47 @@
:unviewed-mentions-count 0
: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"
: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"
:json-rpc/call [{:method "wakuext_markAllReadInCommunity"
:params [community-id]
:on-success #(re-frame/dispatch
[::mark-all-read-in-community-successful %])}]}))
(fx/defn messages-loaded
(defn mark-album
[message]
(if (:album-id message)
(assoc message :albumize? true)
message))
(rf/defn messages-loaded
"Loads more messages for current chat"
{:events [::messages-loaded]}
[{db :db} chat-id session-id {:keys [cursor messages]}]
@@ -132,8 +137,8 @@
current-clock-value (get-in db
[:pagination-info chat-id
:cursor-clock-value])
clock-value (when cursor
(cursor->clock-value cursor))]
clock-value (when cursor (cursor->clock-value cursor))
new-messages (map mark-album new-messages)]
{:dispatch [:chat/add-senders-to-chat-users (vals senders)]
:db (-> db
(update-in [:pagination-info chat-id :cursor-clock-value]
@@ -154,7 +159,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?])]
@@ -173,15 +178,15 @@
#(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
(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?])
+14 -14
View File
@@ -7,7 +7,7 @@
[status-im.contact.db :as contact.db]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.native-module.core :as status]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
@@ -526,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)
@@ -573,7 +573,7 @@
[[: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])
@@ -592,7 +592,7 @@
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)
@@ -600,9 +600,9 @@
{:keys [new-text at-idxs start end] :as state}
(get-in db [:chats/mentions chat-id :mentions])
new-text (or new-text text)]
(log/info "[mentions] calculate suggestions"
"state"
state)
(log/debug "[mentions] calculate suggestions"
"state"
state)
(if-not (seq at-idxs)
{:db (-> db
(assoc-in [:chats/mention-suggestions chat-id] nil)
@@ -659,31 +659,31 @@
" "))
(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}
@@ -698,7 +698,7 @@
(<= (dec end) to))
idx))
at-idxs)
(fx/merge
(rf/merge
cofx
{:db (update-in db
[:chats/mentions chat-id :mentions]
@@ -717,7 +717,7 @@
(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]})
+19 -20
View File
@@ -2,19 +2,18 @@
(: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]
[status-im.constants :as constants]
[status-im.data-store.messages :as data-store.messages]
[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]
[utils.re-frame :as rf]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
[taoensso.timbre :as log]))
(defn- message-loaded?
@@ -37,7 +36,7 @@
;; 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]}]
@@ -168,42 +167,42 @@
(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)})))
(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]
:on-success #(log/debug "re-sent message successfully")
:on-error #(log/error "failed to re-send message" %)}]}
(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" %)}]}
(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
@@ -223,7 +222,7 @@
removed-messages)
remove-messages-fx (fn [{:keys [db]}]
{:dispatch [:activity-center.notifications/fetch-unread-count]})]
(apply fx/merge
(apply rf/merge
cofx
(-> mark-as-deleted-fx
(concat mark-as-seen-fx)
@@ -244,7 +243,7 @@
(<= 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]
+8 -5
View File
@@ -2,7 +2,7 @@
(: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}]
@@ -20,7 +20,8 @@
from
outgoing
whisper-timestamp
deleted-for-me?]}]
deleted-for-me?
albumize?]}]
(-> {:whisper-timestamp whisper-timestamp
:from from
:one-to-one? (= constants/message-type-one-to-one message-type)
@@ -32,7 +33,8 @@
:clock-value clock-value
:type :message
:message-id message-id
:outgoing (boolean outgoing)}
:outgoing (boolean outgoing)
:albumize? albumize?}
add-datemark
add-timestamp))
@@ -195,8 +197,9 @@
(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]
+9 -9
View File
@@ -3,7 +3,7 @@
[status-im.constants :as constants]
[status-im.data-store.reactions :as data-store.reactions]
[status-im.transport.message.protocol :as message.protocol]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn update-reaction
@@ -40,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?])]
@@ -56,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
@@ -72,19 +72,19 @@
;; Send reactions
(fx/defn send-emoji-reaction
{:events [::send-emoji-reaction]}
(rf/defn send-emoji-reaction
{:events [:models.reactions/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
{:events [::send-emoji-reaction-retraction]}
(rf/defn send-retract-emoji-reaction
{:events [:models.reactions/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])})
+4 -4
View File
@@ -2,13 +2,13 @@
(ns status-im.chat.models.transport
(:require [status-im.chat.models.message :as chat.message]
[status-im.transport.message.core :as transport.message]
[status-im.utils.fx :as fx]))
[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))))
+6
View File
@@ -1,6 +1,7 @@
(ns status-im.chat.models-test
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.chat.models :as chat]
[status-im.chat.models.images :as images]
[status-im.utils.clocks :as utils.clocks]))
(deftest clear-history-test
@@ -92,3 +93,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)))))
+19 -20
View File
@@ -1,10 +1,9 @@
(ns status-im.commands.core
(: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
@@ -13,33 +12,33 @@
: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]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
{: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 %])}]})
(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]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
{:json-rpc/call [{:method "wakuext_declineRequestAddressForTransaction"
:params [message-id]
:js-response true
: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]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
{:json-rpc/call [{:method "wakuext_declineRequestTransaction"
:params [message-id]
:js-response true
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})
+313 -315
View File
@@ -4,15 +4,13 @@
[clojure.walk :as walk]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[status-im.activity-center.core :as activity-center]
[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.fx :as fx]
[status-im.utils.handlers :refer [>evt]]
[utils.re-frame :as rf]
[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]))
@@ -80,24 +78,24 @@
[{:keys [db]}]
(:communities/community-id-input db))
(fx/defn handle-request-to-join
(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
(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}]
@@ -105,76 +103,76 @@
db
communities)})
(fx/defn handle-response
(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-error #(do
(log/error "failed to export community" community-id %)
(re-frame/dispatch [::failed-to-export %]))}]})
{:json-rpc/call [{:method "wakuext_exportCommunity"
:params [community-id]
: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"
:params [community-key]
:js-response true
:on-success #(re-frame/dispatch [::community-imported %])
:on-error #(do
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
{:json-rpc/call [{:method "wakuext_importCommunity"
:params [community-key]
:js-response true
:on-success #(re-frame/dispatch [::community-imported %])
:on-error #(do
(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"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::joined %])
:on-error #(do
(log/error "failed to join community" community-id %)
(re-frame/dispatch [::failed-to-join %]))}]})
{:json-rpc/call [{:method "wakuext_joinCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::joined %])
:on-error #(do
(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"
:params [{:communityId community-id}]
:js-response true
:on-success #(re-frame/dispatch [::requested-to-join %])
:on-error #(do
(log/error "failed to request to join community" community-id %)
(re-frame/dispatch [::failed-to-request-to-join %]))}]})
{:json-rpc/call [{:method "wakuext_requestToJoinCommunity"
:params [{:communityId community-id}]
:js-response true
:on-success #(re-frame/dispatch [::requested-to-join %])
:on-error #(do
(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 %)
(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_leaveCommunity"
:json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::left %])
@@ -184,30 +182,30 @@
%)
(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 %])
:on-error #(do
(log/error "failed to fetch communities" %)
(re-frame/dispatch [::failed-to-fetch %]))}]})
{:json-rpc/call [{:method "wakuext_communities"
:params []
:on-success #(re-frame/dispatch [::fetched %])
:on-error #(do
(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"
:params [{:chatId user-pk
:text "Upgrade here to see an invitation to community"
:communityId community-id
:contentType constants/content-type-community}]
:js-response true
:on-success
#(re-frame/dispatch [:transport/message-sent %])
:on-error
#(log/error "failed to send a message" %)}]})
{:json-rpc/call [{:method "wakuext_sendChatMessage"
:params [{:chatId user-pk
:text "Upgrade here to see an invitation to community"
:communityId community-id
:contentType constants/content-type-community}]
:js-response true
:on-success
#(re-frame/dispatch [:transport/message-sent %])
: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)
@@ -215,15 +213,15 @@
(conj contacts user-pk)
contacts)]
(when (seq pks)
{::json-rpc/call [{:method "wakuext_inviteUsersToCommunity"
:params [{:communityId community-id
:users pks}]
:js-response true
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
(fx/defn share-community
{:json-rpc/call [{:method "wakuext_inviteUsersToCommunity"
:params [{:communityId community-id
:users pks}]
:js-response true
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
(rf/defn share-community
{:events [::share-community-confirmation-pressed]}
[cofx user-pk contacts]
(let [community-id (fetch-community-id-input cofx)
@@ -231,16 +229,16 @@
(conj contacts user-pk)
contacts)]
(when (seq pks)
{::json-rpc/call [{:method "wakuext_shareCommunity"
:params [{:communityId community-id
:users pks}]
:js-response true
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-share-community %]))}]})))
{:json-rpc/call [{:method "wakuext_shareCommunity"
:params [{:communityId community-id
:users pks}]
:js-response true
:on-success #(re-frame/dispatch [::people-invited %])
:on-error #(do
(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)]
@@ -254,52 +252,52 @@
:imageBx crop-size
:imageBy crop-size}]
{::json-rpc/call [{:method "wakuext_createCommunity"
:params [params]
:js-response true
:on-success #(re-frame/dispatch [::community-created %])
:on-error #(do
(log/error "failed to create community" %)
(re-frame/dispatch [::failed-to-create-community %]))}]})))
{:json-rpc/call [{:method "wakuext_createCommunity"
:params [params]
:js-response true
:on-success #(re-frame/dispatch [::community-created %])
:on-error #(do
(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)]
{::json-rpc/call [{:method "wakuext_editCommunity"
:params [{:communityID id
:name name
:description description
:color color
:image (string/replace-first (str new-image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size
:membership membership}]
:on-success #(re-frame/dispatch [::community-edited %])
:on-error #(do
(log/error "failed to edit community" %)
(re-frame/dispatch [::failed-to-edit-community %]))}]}))
{:json-rpc/call [{:method "wakuext_editCommunity"
:params [{:communityID id
:name name
:description description
:color color
:image (string/replace-first (str new-image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size
:membership membership}]
:on-success #(re-frame/dispatch [::community-edited %])
:on-error #(do
(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)
{:keys [name description color emoji]} (get db :communities/create-channel)]
{::json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:permissions {:access
constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-created %])
:on-error #(do
(log/error "failed to create community channel" %)
(re-frame/dispatch [::failed-to-create-community-channel %]))}]}))
{:json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:permissions {:access
constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-created %])
:on-error #(do
(log/error "failed to create community channel" %)
(re-frame/dispatch [::failed-to-create-community-channel %]))}]}))
(def community-chat-id-length 68)
@@ -307,27 +305,27 @@
[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]}
(get db :communities/create-channel)]
{::json-rpc/call [{:method "wakuext_editCommunityChat"
:params [community-id
edit-channel-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:category_id category-id
:position position
: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 %]))}]}))
{:json-rpc/call [{:method "wakuext_editCommunityChat"
:params [community-id
edit-channel-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:category_id category-id
:position position
: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]
@@ -338,47 +336,47 @@
(let [chat-id (to-community-chat-id local-chat-id)]
(get-in community [:chats chat-id :can-post?])))
(fx/defn reset-community-id-input
(rf/defn reset-community-id-input
[{:keys [db]} id]
{:db (assoc db :communities/community-id-input id)})
(fx/defn reset-channel-info
(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
(rf/merge cofx
{:db (assoc db
:communities/create-channel
{:name chat-name
@@ -391,33 +389,33 @@
: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
(rf/merge cofx
{:db (assoc db
:communities/create
{:id id
@@ -429,264 +427,264 @@
: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"
:params [{:communityId community-id
: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
%)}]})
{:json-rpc/call [{:method "wakuext_banUserFromCommunity"
:params [{:communityId community-id
: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
%)}]})
(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
%)}]})
{: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
%)}]})
(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))})
(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"
:params [community-id]
:on-success #(re-frame/dispatch [::requests-to-join-fetched community-id %])
:on-error #(log/error "failed to fetch requests-to-join" community-id %)}]})
{:json-rpc/call [{:method "wakuext_pendingRequestsToJoinForCommunity"
:params [community-id]
: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]
(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
%)}]})
{: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
%)}]})
(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)}]})
{: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)}]})
(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"
:params [{:communityId community-id
:categoryName category-title
:chatIds (map #(string/replace % community-id "") chat-ids)}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to create community category" %)}]})
{:json-rpc/call [{:method "wakuext_createCommunityCategory"
:params [{:communityId community-id
:categoryName category-title
:chatIds (map #(string/replace % community-id "") chat-ids)}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(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]))))]
{::json-rpc/call [{:method "wakuext_editCommunityCategory"
:params [{:communityId community-id
:categoryId categoryID
:categoryName (:name category)
:chatIds category-chats}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove chat from community" %)}]}))
{:json-rpc/call [{:method "wakuext_editCommunityCategory"
:params [{:communityId community-id
:categoryId categoryID
:categoryName (:name category)
:chatIds category-chats}]
:js-response true
: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"
:params [community-id chat-id]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community chat" %)}]})
{:json-rpc/call [{:method "wakuext_deleteCommunityChat"
:params [community-id chat-id]
:js-response true
: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"
:params [{:communityId community-id
:categoryId category-id}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community category" %)}]})
{:json-rpc/call [{:method "wakuext_deleteCommunityCategory"
:params [{:communityId community-id
:categoryId category-id}]
:js-response true
: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))
{::json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId id
:position position}]
:js-response true
:on-success #(do
(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
{:json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId id
:position position}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to change community category" %)}]}
(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"
:params [{:communityId community-id
:categoryId category-id
:chatId chat-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category chat" %)}]})
{:json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId chat-id
:position new-position}]
:js-response true
: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"
:params [{:communityId community-id
:categoryId category-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category" %)}]})
{:json-rpc/call [{:method "wakuext_reorderCommunityCategories"
:params [{:communityId community-id
:categoryId category-id
:position new-position}]
:js-response true
: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]
(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])
@@ -700,7 +698,7 @@
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])
@@ -720,45 +718,45 @@
: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"
:params [{:communityId community-id
:user public-key
:role role-id}]
:on-success #(re-frame/dispatch [:community.member/role-updated %])
:on-error #(log/error "failed to add role to member"
{:error %
:community-id community-id
:public-key public-key
:role-id role-id})}]})
{:json-rpc/call [{:method "wakuext_addRoleToMember"
:params [{:communityId community-id
:user public-key
:role role-id}]
:on-success #(re-frame/dispatch [:community.member/role-updated %])
:on-error #(log/error "failed to add role to member"
{:error %
:community-id community-id
: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"
:params [{:communityId community-id
: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})]})
{:json-rpc/call [{:method "wakuext_removeRoleFromMember"
:params [{:communityId community-id
: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})]})
+7
View File
@@ -204,3 +204,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")
+9 -9
View File
@@ -1,15 +1,15 @@
(ns status-im.contact.block
(:require [re-frame.core :as re-frame]
[status-im.activity-center.core :as activity-center]
[status-im.chat.models.message-list :as message-list]
[status-im.contact.db :as contact.db]
[status-im.data-store.chats :as chats-store]
[status-im.data-store.contacts :as contacts-store]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]))
(fx/defn clean-up-chat
(rf/defn clean-up-chat
[{:keys [db] :as cofx}
public-key
{:keys [chat-id
@@ -34,14 +34,14 @@
[: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
(apply rf/merge
cofx
{:db (-> db
(update :chats dissoc public-key)
@@ -52,7 +52,7 @@
(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
@@ -61,7 +61,7 @@
(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)
@@ -77,7 +77,7 @@
(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])
@@ -86,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
+5 -5
View File
@@ -2,28 +2,28 @@
(:require [re-frame.core :as re-frame]
[status-im.chat.models :as chat]
[status-im.contact.core :as contact]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))
(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
(rf/defn pinned-messages-pressed
{:events [:contact.ui/pinned-messages-pressed]}
[cofx public-key]
(chat/navigate-to-user-pinned-messages cofx public-key))
+41 -38
View File
@@ -4,13 +4,12 @@
[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-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
(fx/defn load-contacts
(rf/defn load-contacts
{:events [::contacts-loaded]}
[{:keys [db] :as cofx} all-contacts]
(let [contacts-list (map #(vector (:public-key %)
@@ -31,7 +30,7 @@
(= public-key (:public-key multiaccount))
(assoc :name (:name multiaccount))))
(fx/defn ensure-contacts
(rf/defn ensure-contacts
[{:keys [db]} contacts chats]
(let [events
(reduce
@@ -44,6 +43,10 @@
(and added (not was-added))
(conj [:start-profile-chat public-key])
(and (not (:has-added-us contact))
(= constants/contact-request-state-none (:contact-request-state contact)))
(conj [:activity-center/remove-pending-contact-request (:public-key contact)])
(and was-added (not added))
(conj nil)
@@ -71,15 +74,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]
:on-success #(log/debug "contact request sent" public-key)}]}))
{: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]
@@ -93,62 +96,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]
:on-success #(log/debug "contact removed successfully")}
{:method "wakuext_retractContactRequest"
:params [{:contactId public-key}]
:on-success #(log/debug "contact removed successfully")}]
:dispatch [:offload-messages constants/timeline-chat-id]})
{: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}]
:on-success #(log/debug "contact removed successfully")}]
: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}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
{:json-rpc/call [{:method "wakuext_acceptContactRequest"
:params [{:id id}]
:js-response true
: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}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
{:json-rpc/call [{:method "wakuext_dismissContactRequest"
:params [{:id id}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})
(fx/defn initialize-contacts
(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 "")}
(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
@@ -157,7 +160,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)})
+3 -3
View File
@@ -1,16 +1,16 @@
(ns status-im.currency.core
(:require [status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.wallet.prices :as prices]))
(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
+2 -2
View File
@@ -1,8 +1,8 @@
(ns status-im.data-store.activities
(:require [clojure.set :as set]
[status-im.activity-center.notification-types :as notification-types]
[status-im.constants :as constants]
[status-im.data-store.messages :as messages]))
[status-im.data-store.messages :as messages]
[status-im2.contexts.activity-center.notification-types :as notification-types]))
(defn- rpc->type
[{:keys [type name] :as chat}]
@@ -1,8 +1,8 @@
(ns status-im.data-store.activities-test
(:require [cljs.test :refer [deftest is testing]]
[status-im.activity-center.notification-types :as notification-types]
[status-im.constants :as constants]
[status-im.data-store.activities :as store]))
[status-im.data-store.activities :as store]
[status-im2.contexts.activity-center.notification-types :as notification-types]))
(def chat-id
"0x04c66155")
+7 -8
View File
@@ -2,8 +2,7 @@
(: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.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))
@@ -109,10 +108,10 @@
rpc->type
unmarshal-members))
(fx/defn fetch-chats-rpc
(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 %)}]})
{: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 %)}]})
+39 -40
View File
@@ -1,7 +1,6 @@
(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]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn <-rpc
@@ -22,50 +21,50 @@
(and (:added contact)
(:hasAddedUs contact)))))
(fx/defn fetch-contacts-rpc
(rf/defn fetch-contacts-rpc
[_ on-success]
{::json-rpc/call [{:method "wakuext_contacts"
:params []
:on-success #(on-success (map <-rpc %))
:on-error #(log/error "failed to fetch contacts" %)}]})
{:json-rpc/call [{:method "wakuext_contacts"
:params []
:on-success #(on-success (map <-rpc %))
: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}]
: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 %)}]})
{: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 %)}]})
(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}]
: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
%)}]})
{: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
%)}]})
(fx/defn block
(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)}]})
{: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)}]})
(fx/defn unblock
(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)}]})
{: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)}]})
+29 -29
View File
@@ -1,7 +1,6 @@
(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]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn ->rpc
@@ -36,6 +35,7 @@
:audioDurationMs :audio-duration-ms
:deleted :deleted?
:deletedForMe :deleted-for-me?
:albumId :album-id
:new :new?})
(update :quoted-message
@@ -65,54 +65,54 @@
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}]})
{: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}]})
(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" %)}]})
{: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" %)}]})
(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)}]})
{: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)}]})
(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)}]})
{: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)}]})
(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)}]})
{: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)}]})
(fx/defn delete-message
(rf/defn delete-message
[cofx id]
(delete-message-rpc id))
(fx/defn delete-messages-from
(rf/defn delete-messages-from
[cofx author]
(delete-messages-from-rpc author))
(fx/defn mark-messages-seen
(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
(rf/defn delete-messages-by-chat-id
[cofx chat-id]
(delete-messages-by-chat-id-rpc chat-id))
+14 -15
View File
@@ -1,8 +1,7 @@
(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]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn <-rpc
@@ -19,18 +18,18 @@
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})]
(on-success (update result :pinned-messages #(map <-rpc %)))))
:on-error 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})]
(on-success (update result :pinned-messages #(map <-rpc %)))))
:on-error on-error}]})
(fx/defn send-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)}]})
{: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)}]})
+6 -7
View File
@@ -1,6 +1,5 @@
(ns status-im.data-store.reactions
(:require [clojure.set :as clojure.set]
[status-im.ethereum.json-rpc :as json-rpc]))
(:require [clojure.set :as clojure.set]))
(defn ->rpc
[message]
@@ -27,8 +26,8 @@
limit
on-success
on-error]
{::json-rpc/call [{:method "wakuext_emojiReactionsByChatID"
:params [chat-id cursor limit]
:on-success (fn [result]
(on-success (map <-rpc result)))
:on-error on-error}]})
{:json-rpc/call [{:method "wakuext_emojiReactionsByChatID"
:params [chat-id cursor limit]
:on-success (fn [result]
(on-success (map <-rpc result)))
:on-error on-error}]})
@@ -1,8 +1,7 @@
(ns status-im.data-store.visibility-status-updates
(: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]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn <-rpc
@@ -17,13 +16,13 @@
{: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"
%)}]})
{: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"
%)}]})
+30 -30
View File
@@ -9,7 +9,7 @@
[status-im.ethereum.stateofus :as stateofus]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[status-im.utils.datetime :as datetime]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.utils.random :as random]
[status-im2.navigation.events :as navigation]))
@@ -39,7 +39,7 @@
(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
@@ -48,7 +48,7 @@
: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
@@ -58,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
@@ -79,13 +79,13 @@
(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] [])
new-names (conj names name)]
(fx/merge cofx
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:usernames
new-names
@@ -97,7 +97,7 @@
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)
@@ -115,7 +115,7 @@
: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)]
@@ -164,7 +164,7 @@
5 10
1 10))
(fx/defn register-name
(rf/defn register-name
{:events [::register-name-pressed]}
[{:keys [db]} address]
(let [{:keys [username]}
@@ -207,7 +207,7 @@
;;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)
@@ -236,10 +236,10 @@
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
@@ -248,22 +248,22 @@
[: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
@@ -271,24 +271,24 @@
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
@@ -296,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)
@@ -313,20 +313,20 @@
#(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
+2 -2
View File
@@ -1,7 +1,7 @@
(ns status-im.ethereum.ens
(:require [clojure.string :as string]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.native-module.core :as status]))
[status-im.native-module.core :as status]
[status-im2.common.json-rpc.events :as json-rpc]))
;; this is the addresses of ens registries for the different networks
(def ens-registries
+8 -8
View File
@@ -1,19 +1,19 @@
(ns status-im.ethereum.subscriptions
(:require [status-im.ethereum.eip55 :as eip55]
[status-im.ethereum.transactions.core :as transactions]
[status-im.utils.fx :as fx]
[utils.re-frame :as rf]
[status-im.wallet.core :as wallet.core]
[status-im.wallet.db :as wallet]
[taoensso.timbre :as log]))
(fx/defn new-transfers
(rf/defn new-transfers
[cofx block-number accounts]
(log/debug "[wallet-subs] new-transfers"
"accounts" accounts
"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"
@@ -26,7 +26,7 @@
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
@@ -55,18 +55,18 @@
: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)}
(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
+25 -25
View File
@@ -6,10 +6,10 @@
[status-im.ethereum.decode :as decode]
[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]
[utils.re-frame :as rf]
[status-im.utils.mobile-sync :as utils.mobile-sync]
[status-im.wallet.core :as wallet]
[status-im2.common.json-rpc.events :as json-rpc]
[taoensso.timbre :as log]))
(def confirmations-count-threshold 12)
@@ -107,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
@@ -120,7 +120,7 @@
[: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}]
@@ -128,14 +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
(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]}]
@@ -144,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"
@@ -162,7 +162,7 @@
(:type transfer-by-hash))))
id
hash))]
(fx/merge cofx
(rf/merge cofx
{:db (assoc-in db
[:wallet :accounts address :transactions unique-id]
(assoc transfer :hash unique-id))}
@@ -183,7 +183,7 @@
(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)
{:keys [min-block min-block-transfers-count]}
@@ -231,15 +231,15 @@
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
@@ -248,7 +248,7 @@
: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])
@@ -261,7 +261,7 @@
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
@@ -290,9 +290,9 @@
(< (count transfers) limit)
(conj (tx-history-end-reached checksum)))]
(apply fx/merge cofx (tx-fetching-ended [checksum]) effects)))
(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
@@ -310,7 +310,7 @@
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)
@@ -318,17 +318,17 @@
: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"
@@ -371,13 +371,13 @@
[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))
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)
@@ -393,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

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