Compare commits

...
Author SHA1 Message Date
ibrkhalil 5cd8f9aa45 fix selectable text input repeating 2023-01-08 11:53:01 +02:00
ibrkhalil d6ce375b8e Clean 2023-01-08 11:26:34 +02:00
ibrkhalil 9d1bb5e3c0 Fix children warning 2023-01-08 11:25:31 +02:00
ibrkhalil 4f64982654 remove repeating mentions 2023-01-08 10:09:17 +02:00
ibrkhalil d2e5c955bf Remove warning from iOS 2023-01-08 08:45:25 +02:00
ibrkhalil 1695003d2e Remove react warning 2023-01-08 08:43:06 +02:00
Ibrahem Khalil 4cdc166e41 Add accessibility labels for chat long press (#14685) 2023-01-06 14:39:14 +02:00
Alexander b358a23060 Adjusted border color on outline button (#14711) 2023-01-05 23:35:48 +01:00
Churikova Tetiana b158310057 e2e: workarounds 2023-01-05 18:01:57 +01:00
Parvesh Monu d6159ac269 Persist switcher cards (#14701)
https://github.com/status-im/status-go/compare/b4bdfd3d...d40290a6
2023-01-05 21:50:09 +05:30
Icaro Motta 7cf17b5d34 Move unit test helper namespace to src/test_helpers/ (#14716) 2023-01-05 11:58:37 -03:00
Icaro Motta bad796db90 Fix clojure.set and clojure.walk inconsistent namespace aliases (#14715) 2023-01-05 10:54:32 -03:00
Omar Basem 951fd43d10 Images Album (#14635)
* feat: images album
2023-01-05 16:31:32 +04:00
Siddarth Kumar bb4a4207df abstract running code in separate thread for native java modules (#14690)
This commit adds a new helper method `executeRunnableStatusGoMethod`
The helper method accepts arguments and calls the status go method in a new thread.
2023-01-05 14:42:39 +05:30
Mohamed Javid e30f895fe9 [Feature] Implement replies notification in Activity Center (#14656)
* [Feature][#14550] Added Replies UI in Activity Center

* [Fix][#14550] Removed underlay color from touchables in Replies UI in Activity Center

* [Fix][#14550] Comments from review

* [Fix][#14550] Comments from review

* [Feature][#14550] Added community support on tags in AC

* [Feature][#14550] Date utils test
2023-01-04 21:31:37 +08:00
Siddarth Kumar ec15232af8 Make sure mobile understands community share link by Desktop (#14679)
* we are now able to navigate to desktop communities

https://github.com/status-im/status-go/compare/b4bdfd3d...d2e95eee

In this commit we add support for various status-go methods in mobile :
- `multiformatSerializePublicKey`
- `multiformatDeserializePublicKey`
- `compressPublicKey`
- `decompressPublicKey`
- and my personal favourite `deserializeAndCompressKey`

When someone pastes a community joining share url into chat and taps on it, we check whether the community was generated on a desktop or mobile.
We need to do this because currently both the clients have different urls for joining a community.

Once we have identified that the url is generated via desktop we then convert that url to something that the mobile client is used to.
This enables the mobile client to view this community and interact with it.

However more work needs to be done in the future to ensure that mobile implements these compressed keys end to end, we need to get this feature in so that
by the time RC1 is released mobile client is able to join communities created by Desktop.
2023-01-04 18:24:11 +05:30
Churikova Tetiana 590c0629b6 e2e: new groups 2023-01-04 12:33:02 +01:00
Jinho Jang 944bfe2655 Update translation (#14483) 2023-01-04 12:18:26 +01:00
Parvesh Monu 63ace4da76 Improve switcher last content (#14626) 2023-01-04 03:32:51 +05:30
Matias Grote 697aa1c394 Add profile ui to quo_preview (#14652)
Add profile ui to quo_preview (#14652)
2023-01-03 20:23:16 +01:00
flexsurfer 228c596a9b cleanup and i18n revert (#14694) 2023-01-03 19:19:21 +01:00
Siddarth Kumar 3fa6112669 PR for to ensure native modules are compiled with java version 8 (#14693)
* explicitly mentioning which version of java to use
* fix indentation of closing bracket
2023-01-03 21:30:34 +05:30
Ibrahem Khalil 894be3e4e2 Reply showing unknown (#14682) 2023-01-02 22:08:40 +02:00
Omar Basem 8d08de3d4b Move photo selector to status-im2 (#14661)
* Move photo selector to status-im2
2023-01-02 08:04:03 +04:00
Churikova Tetiana 0a0b70c633 e2e: workarounds 2022-12-30 15:34:25 +01:00
Omar Basem b85eb4184a feat: group details screen (3.3) (#14654)
* feat: group details screen (3)
2022-12-30 18:14:24 +04:00
Ibrahem Khalil 13e59635c7 Add accessibility labels to mentions (#14667) 2022-12-30 15:25:49 +02:00
Ulises Manuel Cárdenas 5493d059b9 UI Component - Account (#14643)
* Implement accounts component
2022-12-30 10:44:21 +01:00
Parvesh Monu 110debc4c4 fix home stack height (#14639) 2022-12-30 09:04:37 +05:30
Jamie Caprani 1677574a6a migrate datetime to utils and finish i18n migration (#14604)
chore move datetime to common and update imports

 chore: move i18n tests and update imports, adjust i18n so translations are loading correctly
2022-12-29 13:56:11 -08:00
Ibrahem Khalil ef21312162 New chat flow (#14607) 2022-12-29 15:57:42 +02:00
Churikova Tetiana 8dac11544e e2e: activity centre 2022-12-29 14:49:35 +01:00
Ibrahem Khalil 77629fa7e1 Edit message issues (#14638) 2022-12-29 14:52:05 +02: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
511 changed files with 11029 additions and 8559 deletions
+13 -11
View File
@@ -1,16 +1,18 @@
{: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}
{: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
test-helpers.unit/deftest-sub clojure.core/defn
taoensso.tufte/defnp clojure.core/defn}
:linters {:consistent-alias {:level :error
:aliases {clojure.string string
clojure.set set
clojure.walk walk
taoensso.timbre log}}
:invalid-arity {:skip-args [status-im.utils.fx/defn utils.re-frame/defn]}
;; TODO remove number when this is fixed
+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}}
+5 -6
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
+28 -12
View File
@@ -364,7 +364,7 @@ actually subscribing to them, so reframe's signal graph gets validated too.
(is (= expected (recipes [current-user all-recipes location]))))))
;; good
(require '[status-im.test-helpers :as h])
(require '[test-helpers.unit :as h])
(re-frame/reg-sub
:user/recipes
@@ -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.
@@ -19,6 +19,11 @@ def getStatusGoSHA1 = { ->
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
@@ -59,8 +59,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.Map;
import java.util.Stack;
import java.util.zip.ZipEntry;
@@ -527,45 +531,33 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void verify(final String address, final String password, final Callback callback) {
Log.d(TAG, "verify");
private void executeRunnableStatusGoMethod(Supplier<String> method, Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable runnableTask = () -> {
String res = method.get();
callback.invoke(res);
};
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void verify(final String address, final String password, final Callback callback) throws JSONException {
Activity currentActivity = getCurrentActivity();
final String absRootDirPath = this.getNoBackupDirectory();
final String newKeystoreDir = pathCombine(absRootDirPath, "keystore");
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.verifyAccountPassword(newKeystoreDir, address, password);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
executeRunnableStatusGoMethod(() -> Statusgo.verifyAccountPassword(newKeystoreDir, address, password), callback);
}
@ReactMethod
public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) {
Log.d(TAG, "verifyDatabasePassword");
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.verifyDatabasePassword(keyUID, password);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.verifyDatabasePassword(keyUID, password), callback);
}
public String getKeyStorePath(String keyUID) {
@@ -735,209 +727,59 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void addPeer(final String enode, final Callback callback) {
Log.d(TAG, "addPeer");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.addPeer(enode);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void addPeer(final String enode, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.addPeer(enode), callback);
}
@ReactMethod
public void multiAccountStoreAccount(final String json, final Callback callback) {
Log.d(TAG, "multiAccountStoreAccount");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountStoreAccount(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountStoreAccount(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreAccount(json), callback);
}
@ReactMethod
public void multiAccountLoadAccount(final String json, final Callback callback) {
Log.d(TAG, "multiAccountLoadAccount");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountLoadAccount(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountLoadAccount(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountLoadAccount(json), callback);
}
@ReactMethod
public void multiAccountReset(final Callback callback) {
Log.d(TAG, "multiAccountReset");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountReset();
public void multiAccountReset(final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountReset(), callback);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
public void multiAccountDeriveAddresses(final String json, final Callback callback) {
Log.d(TAG, "multiAccountDeriveAddresses");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountDeriveAddresses(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountDeriveAddresses(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountDeriveAddresses(json), callback);
}
@ReactMethod
public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) {
Log.d(TAG, "multiAccountGenerateAndDeriveAddresses");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountGenerateAndDeriveAddresses(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountGenerateAndDeriveAddresses(json), callback);
}
@ReactMethod
public void multiAccountStoreDerived(final String json, final Callback callback) {
Log.d(TAG, "multiAccountStoreDerived");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountStoreDerivedAccounts(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountStoreDerived(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreDerivedAccounts(json), callback);
}
@ReactMethod
public void multiAccountImportMnemonic(final String json, final Callback callback) {
Log.d(TAG, "multiAccountImportMnemonic");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountImportMnemonic(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountImportMnemonic(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportMnemonic(json), callback);
}
@ReactMethod
public void multiAccountImportPrivateKey(final String json, final Callback callback) {
Log.d(TAG, "multiAccountImportPrivateKey");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.multiAccountImportPrivateKey(json);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void multiAccountImportPrivateKey(final String json, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportPrivateKey(json), callback);
}
@ReactMethod
public void hashTransaction(final String txArgsJSON, final Callback callback) {
Log.d(TAG, "hashTransaction");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashTransaction(txArgsJSON);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.hashTransaction(txArgsJSON), callback);
}
@ReactMethod
public void hashMessage(final String message, final Callback callback) {
Log.d(TAG, "hashMessage");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashMessage(message);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void hashMessage(final String message, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.hashMessage(message), callback);
}
@ReactMethod
@@ -947,20 +789,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
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);
executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback);
}
@ReactMethod
@@ -969,6 +798,11 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
final String keyStorePath = pathCombine(this.getNoBackupDirectory(), "/keystore");
jsonConfig.put("keystorePath", keyStorePath);
executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback);
}
@ReactMethod
public void multiformatSerializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
@@ -977,7 +811,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.inputConnectionStringForBootstrapping(connectionString,jsonConfig.toString());
String res = Statusgo.multiformatSerializePublicKey(multiCodecKey,base58btc);
callback.invoke(res);
}
};
@@ -985,157 +819,117 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void hashTypedData(final String data, final Callback callback) {
Log.d(TAG, "hashTypedData");
public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashTypedData(data);
String res = Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void hashTypedDataV4(final String data, final Callback callback) {
Log.d(TAG, "hashTypedDataV4");
public void compressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.hashTypedDataV4(data);
String res = Statusgo.compressPublicKey(multiCodecKey);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) {
Log.d(TAG, "sendTransactionWithSignature");
public void decompressPublicKey(final String multiCodecKey, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.sendTransactionWithSignature(txArgsJSON, signature);
String res = Statusgo.decompressPublicKey(multiCodecKey);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) {
Log.d(TAG, "sendTransaction");
public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException {
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
Runnable runnableTask = new Runnable() {
@Override
public void run() {
String res = Statusgo.sendTransaction(txArgsJSON, password);
String res = Statusgo.deserializeAndCompressKey(desktopKey);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
StatusThreadPoolExecutor.getInstance().execute(runnableTask);
}
@ReactMethod
public void signMessage(final String rpcParams, final Callback callback) {
Log.d(TAG, "signMessage");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.signMessage(rpcParams);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void hashTypedData(final String data, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.hashTypedData(data), callback);
}
@ReactMethod
public void recover(final String rpcParams, final Callback callback) {
Log.d(TAG, "recover");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.recover(rpcParams);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void hashTypedDataV4(final String data, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.hashTypedDataV4(data), callback);
}
@ReactMethod
public void signTypedData(final String data, final String account, final String password, final Callback callback) {
Log.d(TAG, "signTypedData");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.signTypedData(data, account, password);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.sendTransactionWithSignature(txArgsJSON, signature), callback);
}
@ReactMethod
public void signTypedDataV4(final String data, final String account, final String password, final Callback callback) {
Log.d(TAG, "signTypedDataV4");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.sendTransaction(txArgsJSON, password), callback);
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.signTypedDataV4(data, account, password);
callback.invoke(res);
}
};
@ReactMethod
public void signMessage(final String rpcParams, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.signMessage(rpcParams), callback);
}
@ReactMethod
public void recover(final String rpcParams, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.recover(rpcParams), callback);
}
@ReactMethod
public void signTypedData(final String data, final String account, final String password, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.signTypedData(data, account, password), callback);
}
@ReactMethod
public void signTypedDataV4(final String data, final String account, final String password, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.signTypedDataV4(data, account, password), callback);
StatusThreadPoolExecutor.getInstance().execute(r);
}
@ReactMethod
@@ -1240,29 +1034,13 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void callRPC(final String payload, final Callback callback) {
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.callRPC(payload);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void callRPC(final String payload, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.callRPC(payload), callback);
}
@ReactMethod
public void callPrivateRPC(final String payload, final Callback callback) {
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.callPrivateRPC(payload);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void callPrivateRPC(final String payload, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.callPrivateRPC(payload), callback);
}
@ReactMethod
@@ -1325,105 +1103,30 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void extractGroupMembershipSignatures(final String signaturePairs, final Callback callback) {
Log.d(TAG, "extractGroupMembershipSignatures");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.extractGroupMembershipSignatures(signaturePairs);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void extractGroupMembershipSignatures(final String signaturePairs, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.extractGroupMembershipSignatures(signaturePairs), callback);
}
@ReactMethod
public void signGroupMembership(final String content, final Callback callback) {
Log.d(TAG, "signGroupMembership");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.signGroupMembership(content);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void signGroupMembership(final String content, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.signGroupMembership(content), callback);
}
@ReactMethod
public void getNodeConfig(final Callback callback) {
Log.d(TAG, "getNodeConfig");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.getNodeConfig();
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void getNodeConfig(final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.getNodeConfig(), callback);
}
@ReactMethod
public void deleteMultiaccount(final String keyUID, final Callback callback) {
Log.d(TAG, "deleteMultiaccount");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
public void deleteMultiaccount(final String keyUID, final Callback callback) throws JSONException {
final String keyStoreDir = this.getKeyStorePath(keyUID);
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.deleteMultiaccount(keyUID, keyStoreDir);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback);
}
@ReactMethod
public void deleteImportedKey(final String keyUID, final String address, final String password, final Callback callback) {
Log.d(TAG, "deleteImportedKey");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
public void deleteImportedKey(final String keyUID, final String address, final String password, final Callback callback) throws JSONException {
final String keyStoreDir = this.getKeyStorePath(keyUID);
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.deleteImportedKey(address, password, keyStoreDir);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
executeRunnableStatusGoMethod(() -> Statusgo.deleteImportedKey(address, password, keyStoreDir), callback);
}
@ReactMethod(isBlockingSynchronousMethod = true)
@@ -1432,24 +1135,8 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void generateAliasAsync(final String seed, final Callback callback) {
Log.d(TAG, "generateAliasAsync");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.generateAlias(seed);
Log.d(TAG, res);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void generateAliasAsync(final String seed, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.generateAlias(seed), callback);
}
@ReactMethod(isBlockingSynchronousMethod = true)
@@ -1513,47 +1200,33 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void identiconAsync(final String seed, final Callback callback) {
Log.d(TAG, "identiconAsync");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String res = Statusgo.identicon(seed);
Log.d(TAG, res);
callback.invoke(res);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void identiconAsync(final String seed, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.identicon(seed), callback);
}
@ReactMethod
public void generateAliasAndIdenticonAsync(final String seed, final Callback callback) {
Log.d(TAG, "generateAliasAndIdenticonAsync");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String resIdenticon = Statusgo.identicon(seed);
String resAlias = Statusgo.generateAlias(seed);
Log.d(TAG, "generateAliasAndIdenticonAsync");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Log.d(TAG, resIdenticon);
Log.d(TAG, resAlias);
callback.invoke(resAlias, resIdenticon);
}
};
Runnable r = new Runnable() {
@Override
public void run() {
String resIdenticon = Statusgo.identicon(seed);
String resAlias = Statusgo.generateAlias(seed);
Log.d(TAG, resIdenticon);
Log.d(TAG, resAlias);
callback.invoke(resAlias, resIdenticon);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
StatusThreadPoolExecutor.getInstance().execute(r);
}
@Override
@@ -1575,24 +1248,8 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void validateMnemonic(final String seed, final Callback callback) {
Log.d(TAG, "validateMnemonic");
if (!checkAvailability()) {
callback.invoke(false);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
String resValidateMnemonic = Statusgo.validateMnemonic(seed);
Log.d(TAG, resValidateMnemonic);
callback.invoke(resValidateMnemonic);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void validateMnemonic(final String seed, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.validateMnemonic(seed), callback);
}
@ReactMethod
@@ -1643,35 +1300,14 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
}
@ReactMethod
public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) {
Log.d(TAG, "reEncryptDbAndKeyStore");
Runnable r = new Runnable() {
@Override
public void run() {
// changes db password and re-encrypts keystore
String result = Statusgo.changeDatabasePassword(keyUID, password, newPassword);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.changeDatabasePassword(keyUID, password, newPassword), callback);
}
@ReactMethod
public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String password, final String newPassword, final Callback callback) {
Log.d(TAG, "convertToKeycardAccount");
public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String password, final String newPassword, final Callback callback) throws JSONException {
final String keyStoreDir = this.getKeyStorePath(keyUID);
Runnable r = new Runnable() {
@Override
public void run() {
String result = Statusgo.convertToKeycardAccount(keyStoreDir, accountData, options, password, newPassword);
callback.invoke(result);
}
};
StatusThreadPoolExecutor.getInstance().execute(r);
executeRunnableStatusGoMethod(() -> Statusgo.convertToKeycardAccount(keyStoreDir, accountData, options, password, newPassword), callback);
}
}
@@ -339,6 +339,38 @@ RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
callback(@[result]);
}
RCT_EXPORT_METHOD(multiformatSerializePublicKey:(NSString *)multiCodecKey
base58btc:(NSString *)base58btc
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoMultiformatSerializePublicKey(multiCodecKey,base58btc);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey
base58btc:(NSString *)base58btc
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoMultiformatDeserializePublicKey(multiCodecKey,base58btc);
callback(@[result]);
}
RCT_EXPORT_METHOD(decompressPublicKey:(NSString *)multiCodecKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoDecompressPublicKey(multiCodecKey);
callback(@[result]);
}
RCT_EXPORT_METHOD(compressPublicKey:(NSString *)multiCodecKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoCompressPublicKey(multiCodecKey);
callback(@[result]);
}
RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoDeserializeAndCompressKey(desktopKey);
callback(@[result]);
}
RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
+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
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

+2 -1
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"]]
@@ -82,7 +83,7 @@
:optimizations :simple
:target :node-test
;; When running tests without a REPL you can uncomment below line to `make test-watch` a specific file
;; :ns-regexp "status-im.chat.models-test$"
;;:ns-regexp "status-im2.subs.subs-test$"
:main
status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl
+1 -1
View File
@@ -3,7 +3,7 @@
[clojure.string :as string]
[status-im.goog.i18n :as goog.i18n]))
(defn init
(defn setup
[default-device-language translations-by-locale]
(set! (.-fallbacks i18n) true)
(set! (.-defaultSeparator i18n) "/")
+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)
})
}
+2
View File
@@ -342,6 +342,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def shell-worklets #js {})
(def bottom-sheet #js {})
(def record-audio-worklets #js {})
;; Update i18n_resources.cljs
@@ -392,6 +393,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
"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
@@ -1,13 +1,8 @@
(ns quo2.components.avatars.account-avatar
(:require [quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(def icon-color-value
{:dark (get-in colors/customization [:dark :purple])
:light (get-in colors/customization [:light :purple])})
(defn get-border-radius
[size]
(case size
@@ -27,12 +22,11 @@
20 11))
(defn account-avatar
[{:keys [size icon]
:or {size 80
icon :main-icons/placeholder}}]
(let [icon-color (if (theme/dark?)
(:dark icon-color-value)
(:light icon-color-value))
[{:keys [size icon color]
:or {size 80
icon :i/placeholder
color :purple}}]
(let [icon-color (colors/custom-color-by-theme color 50 60)
avatar-border-radius (get-border-radius size)
inner-icon-size (get-inner-icon-sizes size)]
[rn/view
@@ -24,7 +24,9 @@
:align-items :center
:justify-content :center
:border-radius (/ container-size 2)
:background-color (colors/custom-color-by-theme color 50 60)}
;:background-color (colors/custom-color-by-theme color 50 60) ; TODO: this is temporary only.
;Issue: https://github.com/status-im/status-mobile/issues/14566
:background-color color}
[icon/icon :i/group
{:size icon-size
:color colors/white-opa-70}]])))
+1 -1
View File
@@ -141,7 +141,7 @@
(if profile-picture
;; display image
[fast-image/fast-image
{:source {:uri profile-picture}
{:source profile-picture
:style (container-styling inner-dimensions outer-dimensions)}]
;; else display initials
[container inner-dimensions outer-dimensions
@@ -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)))))
+4 -3
View File
@@ -32,9 +32,9 @@
:outline {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
:border-color {:default colors/neutral-20
:border-color {:default colors/neutral-30
:pressed colors/neutral-40
:disabled colors/neutral-20}}
:disabled colors/neutral-30}}
:ghost {:icon-color colors/neutral-50
:icon-secondary-color colors/neutral-50
:label-color colors/neutral-100
@@ -138,7 +138,8 @@
(defn shape-style-container
[type icon size]
{:border-radius (if (and icon (#{:primary :secondary :danger} type))
{:height size
:border-radius (if (and icon (#{:primary :secondary :danger} type))
24
(case size
56 12
@@ -31,7 +31,7 @@
:notification-up :i/arrow-up
:search-with-label :i/search
:search :i/search
:bottom :i/arrow-down)
:scroll-to-bottom :i/arrow-down)
{:size 12
:color (get-icon-and-text-color type)
:container-style {:margin-top 6
@@ -43,7 +43,7 @@
:notification-up 2
:search-with-label 8
:search 6
:bottom 6)
:scroll-to-bottom 6)
:margin-right (case type
:jump-to 8
:mention 2
@@ -51,12 +51,12 @@
:notification-up 8
:search-with-label 4
:search 6
:bottom 6)}}])
:scroll-to-bottom 6)}}])
(defn dynamic-button
"[dynamic-button opts]
opts
{:type :jump-to/:mention/:notification-down/:notification-up/:search/:search-with-label/:bottom
{:type :jump-to/:mention/:notification-down/:notification-up/:search/:search-with-label/:scroll-to-bottom
:on-press fn
:count mentions or notifications count
:customization-color customize jump-to and mention button color}"
@@ -77,7 +77,7 @@
:border-radius 12
:background-color (get-button-color type @pressed? (or customization-color :primary))}
style)}
(when (#{:mention :search :search-with-label :bottom} type)
(when (#{:mention :search :search-with-label :scroll-to-bottom} type)
[icon-view type])
(when (#{:jump-to :mention :notification-down :notification-up :search-with-label} type)
[text/text
@@ -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}}]))
@@ -7,7 +7,7 @@
[quo2.components.markdown.text :as text]
[quo2.components.tags.token-tag :as token-tag]
[quo2.foundations.colors :as colors]
[status-im.i18n.i18n :as i18n]
[i18n.i18n :as i18n]
[status-im.ui.components.fast-image :as fast-image]))
(def ^:private token-tag-horizontal-spacing 7)
@@ -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))))
+2 -1
View File
@@ -41,4 +41,5 @@
(get-icons 16)
(get-icons 20)
(get-icons 24)
(get-icons 32)))
(get-icons 32)
(get-icons 120)))
+24 -13
View File
@@ -15,22 +15,24 @@
:text-color (theme-colors colors/danger-50 colors/danger-60)}))
(defn menu-item
[{:keys [type title accessibility-label icon on-press]
[{:keys [type title accessibility-label icon on-press style-props subtitle subtitle-color]
:or {type :main}}]
(let [{:keys [icon-color text-color background]} (themes type)]
[rn/touchable-opacity
(merge {:accessibility-label accessibility-label
:style {:background-color background
:height 48
:flex-direction :row
:align-items :center}}
:style (merge style-props
{:background-color background
:height 48
:flex-direction :row
:align-items :center})}
(when on-press
{:on-press on-press}))
[rn/view
{:style {:flex-direction :row
:flex-grow 0
:flex-shrink 1
:padding-horizontal 20}}
:padding-horizontal 20
:align-items :center}}
[rn/view
{:style {:width 20
:height 20
@@ -38,10 +40,19 @@
:justify-content :center
:margin-right 12}}
[icons/icon icon {:color icon-color}]]
[text/text
{:weight :medium
:style {:color text-color}
:ellipsize-mode :tail
:number-of-lines 1
:size :paragraph-1}
title]]]))
[rn/view
[text/text
{:weight :medium
:style {:color text-color}
:ellipsize-mode :tail
:number-of-lines 1
:size :paragraph-1}
title]
(when subtitle
[text/text
{:weight :medium
:style {:color subtitle-color}
:ellipsize-mode :tail
:number-of-lines 1
:size :paragraph-1}
subtitle])]]]))
@@ -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]]))])
@@ -50,4 +50,4 @@
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :bottom dynamic-buttons {:margin-left 8}]]]]))]))
[dynamic-button-view :scroll-to-bottom dynamic-buttons {:margin-left 8}]]]]))]))
+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))])
@@ -9,7 +9,7 @@
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.i18n.i18n :as i18n]))
[i18n.i18n :as i18n]))
(def ^:private max-reply-length
280)
@@ -81,19 +81,21 @@
context))))
(defn- activity-message
[{:keys [title body]}]
[{:keys [title body title-number-of-lines body-number-of-lines]}]
[rn/view {:style style/message-container}
(when title
[text/text
{:size :paragraph-2
:accessibility-label :activity-message-title
:style style/message-title}
:style style/message-title
:number-of-lines title-number-of-lines}
title])
(if (string? body)
[text/text
{:style style/message-body
:accessibility-label :activity-message-body
:size :paragraph-1}
:size :paragraph-1
:number-of-lines body-number-of-lines}
body]
body)])
@@ -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,40 @@
(ns quo2.components.profile.profile-card.style
(:require [quo2.foundations.colors :as colors]))
(defn card-container
[customization-color]
{:flex-direction :column
:padding 12
:flex 1
:border-radius 16
:background-color (colors/custom-color customization-color 50 40)})
(def card-header
{:flex-direction :row
:justify-content :space-between})
(def name-container
{:flex-direction :row
:margin-top 8
:margin-bottom 2
:align-items :center
:padding-right 12})
(def user-name
{:margin-right 4
:color colors/white})
(def emoji-hash
{:margin-top 10})
(def user-hash
{:color colors/white-opa-60})
(def sign-button
{:margin-top 14})
(def keycard-icon
{:color colors/white-opa-40})
(def option-button
{:background-color colors/white-opa-5})
@@ -0,0 +1,64 @@
(ns quo2.components.profile.profile-card.view
(:require
[quo2.components.profile.profile-card.style :as style]
[quo2.foundations.colors :as colors]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.buttons.button :as button]
[react-native.core :as rn]))
(defn profile-card
[{:keys [show-sign-profile? key-card? profile-picture name hash customization-color sign-label
emoji-hash on-press-dots on-press-sign show-emoji-hash?]
:or {show-sign-profile? false
show-emoji-hash? false
customization-color :turquoise
key-card? false}}]
[rn/view
{:style (style/card-container customization-color)}
[rn/view
{:style style/card-header}
[user-avatar/user-avatar
{:full-name name
:profile-picture profile-picture
:override-theme :dark
:size :medium
:status-indicator? false
:ring? true}]
[button/button
{:size 32
:type :blur-bg
:icon true
:override-theme :dark
:style style/option-button
:on-press on-press-dots}
:i/options]]
[rn/view
{:style style/name-container}
[text/text
{:size :heading-2
:weight :semi-bold
:number-of-lines 1
:style style/user-name} name]
(when key-card?
(icon/icon
:i/keycard
style/keycard-icon))]
[text/text
{:weight :monospace
:number-of-lines 1
:style style/user-hash} hash]
(when (and show-emoji-hash? emoji-hash)
[text/text
{:weight :monospace
:number-of-lines 1
:style style/emoji-hash} emoji-hash])
(when show-sign-profile?
[button/button
{:on-press on-press-sign
:type :community
:community-color (colors/custom-color customization-color 60)
:community-text-color colors/white
:style style/sign-button} sign-label])])
+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))))
@@ -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}]]]])))
+39 -4
View File
@@ -2,7 +2,9 @@
(:require [quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]))
[reagent.core :as reagent]
[quo2.components.selectors.styles :as style]))
(defn- get-color
[checked? disabled? blurred-background?]
@@ -66,6 +68,7 @@
(colors/alpha colors/neutral-100 (if disabled? 0.3 1))
(colors/alpha colors/white (if disabled? 0.3 1)))}]])]])))
(defn checkbox
[{:keys [default-checked?]}]
(let [checked? (reagent/atom (or default-checked? false))]
@@ -107,6 +110,34 @@
{:size 20
:color colors/white}]])]]])))
;; TODO (Omar): issue https://github.com/status-im/status-mobile/issues/14681
;(defn checkbox
; [{:keys [default-checked?]}]
; (let [checked? (reagent/atom (or default-checked? false))]
; @(reagent/track
; (fn [{:keys [on-change disabled? blurred-background? container-style]}]
; [rn/touchable-without-feedback
; {:on-press (handle-press disabled? on-change checked?)}
; [rn/view
; {:style (merge
; container-style
; {:height 20
; :width 20})}
; [rn/view
; {:style (style/checkbox-toggle checked? disabled? blurred-background?)
; :accessibility-label (str "checkbox-" (if @checked? "on" "off"))
; :accessibility-role :checkbox
; :testID "checkbox-component"}
; (when @checked?
; [rn/view
; {:style
; {:height 20
; :width 20}}
; [icons/icon :i/check-small
; {:size 20
; :color colors/white}]])]]])
; checked?)))
(defn radio
[{:keys [default-checked?]}]
(let [checked? (reagent/atom (or default-checked? false))]
@@ -120,7 +151,9 @@
:width 20
:border-radius 20
:border-width 1
:border-color (get-color @checked? disabled? blurred-background?)
:border-color (style/get-color @checked?
disabled?
blurred-background?)
:background-color (when-not blurred-background?
(colors/theme-colors colors/white
(colors/alpha colors/neutral-80
@@ -134,7 +167,7 @@
{:margin-left :auto
:height 14
:width 14
:background-color (when @checked? (get-color @checked? disabled? blurred-background?))
:background-color (when @checked? (style/get-color @checked? disabled? blurred-background?))
:border-radius 20
:margin-right :auto
:margin-top :auto
@@ -152,7 +185,9 @@
{:height 20
:width 30
:border-radius 20
:background-color (get-color @checked? disabled? blurred-background?)})
:background-color (style/get-color @checked?
disabled?
blurred-background?)})
:accessibility-label (str "toggle-" (if @checked? "on" "off"))
:accessibility-role :checkbox
:testID "toggle-component"}
+41
View File
@@ -0,0 +1,41 @@
(ns quo2.components.selectors.styles
(:require [quo2.foundations.colors :as colors]))
(defn get-color
[checked? disabled? blurred-background?]
(cond
checked?
(colors/custom-color-by-theme
:primary
50
60
(when disabled? 30)
(when disabled? 30))
blurred-background?
(colors/theme-colors
(colors/alpha colors/neutral-80 (if disabled? 0.05 0.1))
(colors/alpha colors/white (if disabled? 0.05 0.1)))
:else
(colors/theme-colors
(colors/alpha colors/neutral-20 (if disabled? 0.4 1))
(colors/alpha colors/neutral-70 (if disabled? 0.3 1)))))
(defn checkbox-toggle
[checked? disabled? blurred-background?]
{:flex 1
:border-radius 6
:border-width (if @checked? 0 1)
:background-color (cond
@checked?
(get-color @checked? disabled? blurred-background?)
blurred-background?
(colors/theme-colors
colors/white-opa-5
colors/white-opa-10)
:else
(colors/theme-colors
colors/white
colors/neutral-80-opa-40))
:border-color (if @checked?
:none
(get-color @checked? disabled? blurred-background?))})
@@ -0,0 +1,71 @@
(ns quo2.components.settings.accounts.style
(:require [quo2.foundations.colors :as colors]))
(def card
{:position :relative
:padding 8
:border-radius 16
:height 160
:width 160})
(defn background-top
[custom-color]
{:position :absolute
:top 0
:border-top-left-radius 16
:border-top-right-radius 16
:width 160
:height 64
:background-color (-> colors/customization
(get-in [custom-color 50])
(colors/alpha 0.2))})
(defn background-bottom
[]
{:position :absolute
:top 40
:border-radius 16
:width 160
:height 120
:background-color (colors/theme-colors
colors/white
colors/neutral-90)})
(defn avatar-border
[]
{:margin 2
:justify-content :center
:align-items :center
:width 52
:height 52
:border-radius 14
:border-width 2
:border-color (colors/theme-colors
colors/white
colors/neutral-90)})
(def menu-button-container
{:justify-content :center
:align-items :center
:align-self :flex-start})
(defn menu-button-color
[]
{:background-color (colors/theme-colors
colors/white-opa-40
colors/neutral-80-opa-40)})
(defn address-text
[]
{:color (colors/theme-colors
colors/neutral-50
colors/neutral-40)})
(def card-top
{:flex-direction :row
:align-items :center
:justify-content :space-between})
(def card-bottom
{:flex 1
:margin-horizontal 4
:margin-top 4})
@@ -0,0 +1,46 @@
(ns quo2.components.settings.accounts.view
(:require [quo2.components.avatars.account-avatar :as account-avatar]
[quo2.components.buttons.button :as button]
[quo2.components.markdown.text :as text]
[quo2.components.settings.accounts.style :as style]
[react-native.core :as rn]))
(defn card-background
[{:keys [custom-color]}]
[:<>
[rn/view {:style (style/background-top custom-color)}]
[rn/view {:style (style/background-bottom)}]])
(defn avatar
[avatar-props]
[rn/view {:style (style/avatar-border)}
[account-avatar/account-avatar (assoc avatar-props :size 48)]])
(defn menu-button
[{:keys [on-press]}]
[rn/view {:style style/menu-button-container}
[button/button
{:style (style/menu-button-color)
:type :gray
:icon true
:size 24
:on-press on-press}
:i/more]])
(defn account
[{:keys [account-name account-address avatar-icon custom-color on-press-menu]}]
[rn/view {:style style/card}
[card-background {:custom-color custom-color}]
[rn/view {:style style/card-top}
[avatar
{:color custom-color
:icon avatar-icon}]
[menu-button {:on-press on-press-menu}]]
[rn/view {:style style/card-bottom}
[text/text {:size :paragraph-1 :weight :semi-bold}
account-name]
[text/text
{:style (style/address-text)
:size :paragraph-2
:weight :medium}
account-address]]])
+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
+49 -13
View File
@@ -6,12 +6,6 @@
[quo2.theme :as quo2.theme]
[react-native.core :as rn]))
(defn padding-left-for-type
[type]
(case type
:group-avatar 3
8))
(defn trim-public-key
[pk]
(str (subs pk 0 6) "..." (subs pk (- (count pk) 3))))
@@ -30,7 +24,7 @@
:padding-left 8
:background-color (if (= theme :light)
colors/neutral-10
colors/neutral-80)}
colors/neutral-90)}
style)]
children))))
@@ -40,7 +34,8 @@
[base-tag
(-> opts
(select-keys [:override-theme :style])
(assoc-in [:style :padding-left] 3))
(assoc-in [:style :padding-left] 3)
(assoc-in [:style :padding-vertical] 2))
[group-avatar/group-avatar opts]
[text/text
{:weight :medium
@@ -67,13 +62,13 @@
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}
{:style {:width 20
:border-radius 10
:background-color :red
:height 20}
:source photo}]
[rn/view
{:style {:align-items :center
{:style {:align-items :center
:flex-direction :row}}
[text/text text-params (str " " name)]
(when channel-name
@@ -88,3 +83,44 @@
[]
(fn [params username photo]
[context-tag params {:uri photo} username]))
(defn audio-tag
[duration params]
[base-tag
(merge
{:style {:padding-left 2
:padding-vertical 2}}
params)
[rn/view
{:width 20
:height 20
:border-radius 10
:align-items :center
:justify-content :center
:background-color colors/primary-50}
[icons/icon
:i/play
{:color colors/white
:size 12}]]
[text/text
{:weight :medium
:size :paragraph-2
:style {:margin-left 4
:color (colors/theme-colors
colors/neutral-100
colors/white
(:override-theme params))}}
duration]])
(defn community-tag
[avatar community-name params]
[context-tag
(merge
{:style {:padding-vertical 2}
:text-style {:margin-left 2
:color (colors/theme-colors
colors/neutral-100
colors/white
(:override-theme params))}}
params)
avatar community-name])
+22 -2
View File
@@ -1,4 +1,5 @@
(ns quo2.core
(:refer-clojure :exclude [filter])
(:require
quo2.components.avatars.account-avatar
quo2.components.avatars.channel-avatar
@@ -6,12 +7,14 @@
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
@@ -28,6 +31,7 @@
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
@@ -38,14 +42,17 @@
quo2.components.notifications.notification-dot
quo2.components.notifications.toast
quo2.components.reactions.reaction
quo2.components.selectors.disclaimer
quo2.components.selectors.disclaimer.view
quo2.components.selectors.filter.view
quo2.components.selectors.selectors
quo2.components.separator
quo2.components.settings.accounts.view
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.profile.profile-card.view
quo2.components.tags.tags))
(def toast quo2.components.notifications.toast/toast)
@@ -63,19 +70,24 @@
(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)
(def group-avatar-tag quo2.components.tags.context-tags/group-avatar-tag)
(def audio-tag quo2.components.tags.context-tags/audio-tag)
(def community-tag quo2.components.tags.context-tags/community-tag)
(def tabs quo2.components.tabs.tabs/tabs)
(def scrollable-tabs quo2.components.tabs.tabs/scrollable-tabs)
(def account-selector quo2.components.tabs.account-selector/account-selector)
(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)
@@ -85,6 +97,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)
@@ -97,6 +112,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)
@@ -114,5 +130,9 @@
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
(def count-down-circle quo2.components.notifications.count-down-circle/circle-timer)
;;;; PROFILE
(def profile-card quo2.components.profile.profile-card.view/profile-card)
;;;; SETTINGS
(def privacy-option quo2.components.settings.privacy-option/card)
(def account quo2.components.settings.accounts.view/account)
+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]))
+1
View File
@@ -85,6 +85,7 @@
;;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))
+2
View File
@@ -67,6 +67,8 @@
(def status-bar (.-StatusBar ^js react-native))
(def style-sheet (.-StyleSheet ^js react-native))
(defn status-bar-height
[]
(.-currentHeight ^js status-bar))
+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)}))
+7 -7
View File
@@ -7,10 +7,10 @@
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.stateofus :as stateofus]
[status-im.i18n.i18n :as i18n]
[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 %])}]})
+15 -15
View File
@@ -1,9 +1,9 @@
(ns status-im.bootnodes.core
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.i18n.i18n :as i18n]
[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]
[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)
+33 -34
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]
[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"
+93 -94
View File
@@ -8,17 +8,16 @@
[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]
[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.message.delete-message-for-me.events :as delete-for-me]
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
[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
+19 -19
View File
@@ -4,12 +4,12 @@
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.chat.models :as chat]
[status-im.i18n.i18n :as i18n]
[i18n.i18n :as i18n]
[status-im.ui.components.permissions :as permissions]
[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]
@@ -120,7 +120,7 @@
(: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))
@@ -129,24 +129,24 @@
(not (get images uri)))
{::image-selected [uri current-chat-id]})))
(fx/defn on-end-reached
(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])))
(fx/defn camera-roll-get-photos
(rf/defn camera-roll-get-photos
{:events [:chat.ui/camera-roll-get-photos]}
[_ num end-cursor]
{::camera-roll-get-photos [num end-cursor]})
(fx/defn camera-roll-loading-more
(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)})
(fx/defn on-camera-roll-get-photos
(rf/defn on-camera-roll-get-photos
{:events [:on-camera-roll-get-photos]}
[{:keys [db] :as cofx} photos page-info end-cursor]
(let [photos_x (when end-cursor (:camera-roll/photos db))]
@@ -156,34 +156,34 @@
(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))
@@ -191,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))
@@ -204,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))
@@ -221,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})
+58 -58
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]
[i18n.i18n :as i18n]
[utils.datetime :as datetime]
[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,26 +33,25 @@
(let [current-chat-id (or chat-id (:current-chat-id db))]
{:db (assoc-in db [:chat/inputs current-chat-id :input-text] (text->emoji new-input))}))
(fx/defn set-timeline-input-text
(rf/defn set-timeline-input-text
{:events [:chat.ui/set-timeline-input-text]}
[{db :db} new-input]
{:db (assoc-in db
[:chat/inputs (chat/my-profile-chat-topic db) :input-text]
(text->emoji new-input))})
(fx/defn select-mention
(rf/defn select-mention
{:events [:chat.ui/select-mention]}
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
(let [chat-id (:current-chat-id db)
new-text (mentions/new-input-text-with-mention cofx user)
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
cursor (+ at-sign-idx (count name) 2)]
(fx/merge
(rf/merge
cofx
{:db (-> db
(assoc-in [:chats/cursor chat-id] cursor)
(assoc-in [:chats/mention-suggestions chat-id] nil))
:set-text-input-value [chat-id new-text text-input-ref]}
{:db (-> db
(assoc-in [:chats/cursor chat-id] cursor)
(assoc-in [:chats/mention-suggestions chat-id] nil))}
(set-chat-input-text new-text chat-id)
;; NOTE(rasom): Some keyboards do not react on selection property passed to
;; text input (specifically Samsung keyboard with predictive text set on).
@@ -92,7 +90,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 +113,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 +127,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 +143,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 +158,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 +183,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 +203,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 +235,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 +250,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 +260,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 +307,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))
+1 -1
View File
@@ -2,7 +2,7 @@
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.chat.constants :as constants]
[status-im.chat.models.input :as input]
[status-im.utils.datetime :as datetime]))
[utils.datetime :as datetime]))
(deftest text->emoji
(is (nil? (input/text->emoji nil)))
+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
+35 -25
View File
@@ -4,10 +4,9 @@
[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]
[status-im2.contexts.activity-center.events :as activity-center]
[taoensso.timbre :as log]))
[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,52 @@
: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
;; For example, when a user receives a list of 4 image messages while inside the chat screen we
;; shouldn't group the images into albums. When the user exists the chat screen then enters the
;; chat screen again, we now need to group the images into albums (like WhatsApp). The albumize?
;; boolean is used to know whether we need to group these images into albums now or not. The
;; album-id can't be used for this because it will always be there.
(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 +142,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 +164,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 +183,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
@@ -7,14 +7,13 @@
[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.message.delete-message.events :as delete-message]
[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]
+9 -7
View File
@@ -1,17 +1,17 @@
(ns status-im.chat.models.message-list
(: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]
[utils.datetime :as datetime]))
(defn- add-datemark
[{:keys [whisper-timestamp] :as msg}]
;;TODO this is slow
(assoc msg :datemark (time/day-relative whisper-timestamp)))
(assoc msg :datemark (datetime/day-relative whisper-timestamp)))
(defn- add-timestamp
[{:keys [whisper-timestamp] :as msg}]
(assoc msg :timestamp-str (time/timestamp->time whisper-timestamp)))
(assoc msg :timestamp-str (datetime/timestamp->time whisper-timestamp)))
(defn prepare-message
[{:keys [message-id
@@ -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))
@@ -197,7 +199,7 @@
;; NOTE(performance): this is too expensive, probably we could mark message somehow and just hide it in
;; the UI
(fx/defn rebuild-message-list
(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))))
+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 %])}]})
+323 -325
View File
@@ -1,5 +1,5 @@
(ns status-im.communities.core
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as set]
[clojure.string :as string]
[clojure.walk :as walk]
[quo.design-system.colors :as colors]
@@ -7,10 +7,8 @@
[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]
@@ -30,10 +28,10 @@
(defn <-request-to-join-community-rpc
[r]
(clojure.set/rename-keys r
{:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(set/rename-keys r
{:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(defn <-requests-to-join-community-rpc
[requests]
@@ -66,12 +64,12 @@
(defn <-rpc
[c]
(-> c
(clojure.set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?})
(set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :categories <-categories-rpc)))
@@ -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})]})
+18 -1
View File
@@ -205,9 +205,26 @@
(def ^:const community-member-role-manage-users 2)
(def ^:const community-member-role-moderator 3)
(def local-pairing-connection-string-identifier
(def ^:const 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")
(def ^:const serialization-key
"We pass this serialization key as a parameter to MultiformatSerializePublicKey
function at status-go, This key determines the output base of the serialization.
according to https://specs.status.im/spec/2#public-key-serialization we serialize
keys with base58btc encoding"
"z")
(def ^:const deserialization-key
"We pass this deserialization key as a parameter to MultiformatDeserializePublicKey
function at status-go, This key determines the output base of the deserialization.
according to https://specs.status.im/spec/2#public-key-serialization we deserialize
keys with base16 hexadecimal encoding"
"f")
(def ^:const multi-code-prefix
"We prefix our keys with 0xe701 prior to serialisation them"
"0xe701")
+8 -8
View File
@@ -4,12 +4,12 @@
[status-im.contact.db :as contact.db]
[status-im.data-store.chats :as chats-store]
[status-im.data-store.contacts :as contacts-store]
[status-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,5 +1,5 @@
(ns status-im.contact.db
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as set]
[clojure.string :as string]
[status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
@@ -68,8 +68,8 @@
(let [current-contact (some->
current-account
(select-keys [:name :preferred-name :public-key :identicon :images])
(clojure.set/rename-keys {:name :alias
:preferred-name :name}))
(set/rename-keys {:name :alias
:preferred-name :name}))
all-contacts (cond-> contacts
current-contact
(assoc public-key current-contact))]
+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
+21 -22
View File
@@ -1,9 +1,8 @@
(ns status-im.data-store.chats
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as 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]))
@@ -59,19 +58,19 @@
(defn <-rpc
[chat]
(-> chat
(clojure.set/rename-keys {:id :chat-id
:communityId :community-id
:syncedFrom :synced-from
:syncedTo :synced-to
:membershipUpdateEvents :membership-update-events
:deletedAtClockValue :deleted-at-clock-value
:chatType :chat-type
:unviewedMessagesCount :unviewed-messages-count
:unviewedMentionsCount :unviewed-mentions-count
:lastMessage :last-message
:lastClockValue :last-clock-value
:invitationAdmin :invitation-admin
:profile :profile-public-key})
(set/rename-keys {:id :chat-id
:communityId :community-id
:syncedFrom :synced-from
:syncedTo :synced-to
:membershipUpdateEvents :membership-update-events
:deletedAtClockValue :deleted-at-clock-value
:chatType :chat-type
:unviewedMessagesCount :unviewed-messages-count
:unviewedMentionsCount :unviewed-mentions-count
:lastMessage :last-message
:lastClockValue :last-clock-value
:invitationAdmin :invitation-admin
:profile :profile-public-key})
rpc->type
unmarshal-members
(update :last-message #(when % (messages/<-rpc %)))
@@ -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 %)}]})
+41 -42
View File
@@ -1,13 +1,12 @@
(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]
(:require [clojure.set :as set]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn <-rpc
[contact]
(-> contact
(clojure.set/rename-keys
(set/rename-keys
{:id :public-key
:ensVerifiedAt :ens-verified-at
:displayName :display-name
@@ -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)}]})
+54 -54
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]
(:require [clojure.set :as set]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn ->rpc
@@ -11,39 +10,40 @@
(assoc :text (:text content)
:sticker (:sticker content))
:always
(clojure.set/rename-keys {:chat-id :chat_id
:whisper-timestamp :whisperTimestamp
:community-id :communityId
:clock-value :clock})))
(set/rename-keys {:chat-id :chat_id
:whisper-timestamp :whisperTimestamp
:community-id :communityId
:clock-value :clock})))
(defn <-rpc
[message]
(-> message
(clojure.set/rename-keys {:id :message-id
:whisperTimestamp :whisper-timestamp
:editedAt :edited-at
:contactVerificationState :contact-verification-state
:contactRequestState :contact-request-state
:commandParameters :command-parameters
:gapParameters :gap-parameters
:messageType :message-type
:localChatId :chat-id
:communityId :community-id
:contentType :content-type
:clock :clock-value
:quotedMessage :quoted-message
:outgoingStatus :outgoing-status
:audioDurationMs :audio-duration-ms
:deleted :deleted?
:deletedForMe :deleted-for-me?
:new :new?})
(set/rename-keys {:id :message-id
:whisperTimestamp :whisper-timestamp
:editedAt :edited-at
:contactVerificationState :contact-verification-state
:contactRequestState :contact-request-state
:commandParameters :command-parameters
:gapParameters :gap-parameters
:messageType :message-type
:localChatId :chat-id
:communityId :community-id
:contentType :content-type
:clock :clock-value
:quotedMessage :quoted-message
:outgoingStatus :outgoing-status
:audioDurationMs :audio-duration-ms
:deleted :deleted?
:deletedForMe :deleted-for-me?
:albumId :album-id
:new :new?})
(update :quoted-message
clojure.set/rename-keys
set/rename-keys
{:parsedText :parsed-text :communityId :community-id})
(update :outgoing-status keyword)
(update :command-parameters
clojure.set/rename-keys
set/rename-keys
{:transactionHash :transaction-hash
:commandState :command-state})
(assoc :content {:chat-id (:chatId 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))
+17 -18
View File
@@ -1,16 +1,15 @@
(ns status-im.data-store.pin-messages
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as 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
[message]
(-> message
(merge (messages/<-rpc (message :message)))
(clojure.set/rename-keys {:pinnedAt :pinned-at
:pinnedBy :pinned-by})
(set/rename-keys {:pinnedAt :pinned-at
:pinnedBy :pinned-by})
(dissoc :message)))
(defn pinned-message-by-chat-id-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 (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)}]})
+16 -17
View File
@@ -1,25 +1,24 @@
(ns status-im.data-store.reactions
(:require [clojure.set :as clojure.set]
[status-im.ethereum.json-rpc :as json-rpc]))
(:require [clojure.set :as set]))
(defn ->rpc
[message]
(-> message
(clojure.set/rename-keys {:message-id :messageId
:emoji-id :emojiId
:chat-id :localChatId
:message-type :messageType
:emoji-reaction-id :id})))
(set/rename-keys {:message-id :messageId
:emoji-id :emojiId
:chat-id :localChatId
:message-type :messageType
:emoji-reaction-id :id})))
(defn <-rpc
[message]
(-> message
(dissoc :chat_id)
(clojure.set/rename-keys {:messageId :message-id
:localChatId :chat-id
:emojiId :emoji-id
:messageType :message-type
:id :emoji-reaction-id})))
(set/rename-keys {:messageId :message-id
:localChatId :chat-id
:emojiId :emoji-id
:messageType :message-type
:id :emoji-reaction-id})))
(defn reactions-by-chat-id-rpc
[chat-id
@@ -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}]})
@@ -0,0 +1,41 @@
(ns status-im.data-store.switcher-cards
(:require [clojure.set :as set]
[clojure.walk :as walk]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(defn <-rpc
[switcher-cards]
(walk/postwalk-replace
{:cardId :card-id
:screenId :screen-id}
switcher-cards))
(defn rpc->
[switcher-card]
(set/rename-keys switcher-card
{:card-id :cardId
:screen-id :screenId}))
(rf/defn upsert-switcher-card-rpc
[_ switcher-card]
{:json-rpc/call [{:method "wakuext_upsertSwitcherCard"
:params [(rpc-> switcher-card)]
:on-success #()
:on-error #()}]})
(rf/defn delete-switcher-card-rpc
[_ card-id]
{:json-rpc/call [{:method "wakuext_deleteSwitcherCard"
:params [card-id]
:on-success #()
:on-error #()}]})
(rf/defn fetch-switcher-cards-rpc
[_]
{:json-rpc/call [{:method "wakuext_switcherCards"
:params []
:on-success #(rf/dispatch
[:shell/switcher-cards-loaded
(:switcherCards ^js %)])
:on-error #(log/error "Failed to fetch switcher cards" %)}]})
@@ -1,29 +1,28 @@
(ns status-im.data-store.visibility-status-updates
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as 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
[visibility-status-update]
(clojure.set/rename-keys visibility-status-update
{:publicKey :public-key
:statusType :status-type}))
(set/rename-keys visibility-status-update
{:publicKey :public-key
:statusType :status-type}))
(defn <-rpc-settings
[settings]
(-> settings
(clojure.set/rename-keys
(set/rename-keys
{:current-user-status :current-user-visibility-status})
(update :current-user-visibility-status <-rpc)))
(fx/defn fetch-visibility-status-updates-rpc
(rf/defn fetch-visibility-status-updates-rpc
[_]
{::json-rpc/call [{:method "wakuext_statusUpdates"
:params []
:on-success #(re-frame/dispatch
[:visibility-status-updates/visibility-status-updates-loaded
(:statusUpdates ^js %)])
:on-error #(log/error
"failed to fetch visibility-status-updates"
%)}]})
{: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"
%)}]})
+31 -31
View File
@@ -8,8 +8,8 @@
[status-im.ethereum.ens :as ens]
[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]
[utils.datetime :as datetime]
[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

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