Compare commits

..
Author SHA1 Message Date
ibrkhalil 2e5db3758a Remove logger 2023-01-12 11:53:10 +02:00
ibrkhalil 47012b8c07 Lint 2023-01-12 11:49:16 +02:00
ibrkhalil 3b46d837ae Use app db for events 2023-01-12 11:47:21 +02:00
ibrahem 94e89f65bc CLean 2023-01-12 11:47:20 +02:00
ibrahem ca04e28df1 Use re-frame events 2023-01-12 11:47:20 +02:00
ibrkhalil 91039e89b0 Lint and add to the invite contact sheet 2023-01-12 11:47:19 +02:00
ibrkhalil 661b6bc4bd Add animation delay to initial chat flow 2023-01-12 11:47:19 +02:00
ibrkhalil 2e4321483a Delay opening of bottom sheet 2023-01-12 11:47:18 +02:00
ibrkhalil b04cddd54c Add reanimated to index.js 2023-01-12 11:47:18 +02:00
ibrkhalil 4b78f7dc8d Reset and dispatch the hiding effec 2023-01-12 11:47:17 +02:00
ibrkhalil 808d06305e Revert changes 2023-01-12 11:47:17 +02:00
ibrkhalil 42acb2997a Lint 2023-01-12 11:47:16 +02:00
ibrkhalil 44df616c45 Test changing the hiding functionality 2023-01-12 11:47:16 +02:00
ibrkhalil 4c6b97093c Fix spacing 2023-01-12 11:47:15 +02:00
ibrahem 9108585f12 Lint 2023-01-12 11:47:15 +02:00
ibrahem 0fed3a2469 Clean 2023-01-12 11:47:14 +02:00
ibrahem 00955fb9a3 Clean 2023-01-12 11:47:14 +02:00
ibrahem 380f24f46b dismiss bottom sheet 2023-01-12 11:47:13 +02:00
ibrahem 875a37290d Remove manual specification of height 2023-01-12 11:47:12 +02:00
ibrkhalil 718bc363ad Lint 2023-01-12 11:47:12 +02:00
ibrkhalil fa22e7fcba Issue 6, Use same function signature for adding and removing hw event listenr on back button 2023-01-12 11:47:11 +02:00
ibrkhalil b49b43298b Issue 4 2023-01-12 11:47:11 +02:00
ibrkhalil 0ce2494246 issue 2 and question 2 2023-01-12 11:47:10 +02:00
ibrkhalil b19788fba2 Issue 1 2023-01-12 11:47:10 +02:00
ibrahem 57d97b6667 Lint 2023-01-12 11:47:09 +02:00
ibrahem 723a911ec2 Lint 2023-01-12 11:47:09 +02:00
ibrahem 89139cf776 Listen for hardware backbutton and dismiss 2023-01-12 11:47:08 +02:00
ibrahem 6632dae48e Lint 2023-01-12 11:47:08 +02:00
ibrahem 4f6a856052 Handle reaction drawer height 2023-01-12 11:47:07 +02:00
ibrahem 9deb5dbf56 Formatting 2023-01-12 11:47:07 +02:00
ibrahem 18252c1be6 Lint 2023-01-12 11:47:06 +02:00
ibrahem 24591328a0 Listen for hardware backbutton and dismiss 2023-01-12 11:47:06 +02:00
ibrahem 05773c06ee Lint 2023-01-12 11:47:05 +02:00
ibrahem 66911f43d4 Use close bottom-sheet fn 2023-01-12 11:47:05 +02:00
ibrkhalil 9c672323f3 Comments 2023-01-12 11:47:04 +02:00
ibrahem cab969647d Typo 2023-01-12 11:47:03 +02:00
ibrahem 904d8cf96a Formatting 2023-01-12 11:47:03 +02:00
ibrkhalil 6660224eb1 Fix reactions sheet 2023-01-12 11:47:02 +02:00
ibrahem 2e953baa67 Clean 2023-01-12 11:47:02 +02:00
ibrahem 4cee364958 Lint 2023-01-12 11:47:01 +02:00
ibrahem a967239d69 Listen for hardware backbutton and dismiss 2023-01-12 11:47:01 +02:00
ibrahem 7593a144c4 Handle too high of a height on start a new chat bottom sheet 2023-01-12 11:47:00 +02:00
ibrahem 02d8209131 dismiss bottom sheet 2023-01-12 11:47:00 +02:00
ibrahem d3193fd958 Remove manual specification of height 2023-01-12 11:46:59 +02:00
ibrkhalil 043b254480 Lint 2023-01-12 11:46:59 +02:00
ibrkhalil 0997fb3ba4 issue 2 and question 2 2023-01-12 11:46:58 +02:00
ibrkhalil c4328e6a30 Issue 1 2023-01-12 11:46:58 +02:00
ibrahem 66664692a6 Lint 2023-01-12 11:46:57 +02:00
ibrahem 03c16dd251 Lint 2023-01-12 11:46:57 +02:00
ibrahem da923fe04e Listen for hardware backbutton and dismiss 2023-01-12 11:46:56 +02:00
ibrahem 2fbf6518e7 Lint 2023-01-12 11:46:55 +02:00
ibrahem a9c0427758 Handle reaction drawer height 2023-01-12 11:46:55 +02:00
ibrahem e9824a28bd Formatting 2023-01-12 11:46:54 +02:00
ibrahem 7f6a5cb31f Lint 2023-01-12 11:46:54 +02:00
ibrahem 1a289d4ec7 Listen for hardware backbutton and dismiss 2023-01-12 11:46:53 +02:00
ibrahem 156d27e8e1 Lint 2023-01-12 11:46:53 +02:00
ibrahem 392ecf7fdd Use close bottom-sheet fn 2023-01-12 11:46:52 +02:00
ibrkhalil a1469f8eb2 Comments 2023-01-12 11:46:52 +02:00
ibrahem edcc107ec3 Add line at EOF 2023-01-12 11:46:51 +02:00
ibrahem d54b5cc080 Formatting 2023-01-12 11:46:51 +02:00
ibrkhalil c188d840c5 Fix reactions sheet 2023-01-12 11:46:50 +02:00
ibrahem dd253af0bb Clean 2023-01-12 11:46:50 +02:00
ibrahem 1c8c8fd7b1 Lint 2023-01-12 11:46:49 +02:00
ibrahem 34f8642fd8 Listen for hardware backbutton and dismiss 2023-01-12 11:46:49 +02:00
ibrahem f40fc9c6f1 Handle too high of a height on start a new chat bottom sheet 2023-01-12 11:46:48 +02:00
ibrahem c9b5496ec9 dismiss bottom sheet 2023-01-12 11:46:48 +02:00
ibrahem 3256feee7c Remove manual specification of height 2023-01-12 11:46:47 +02:00
ibrkhalil 796bd4ac45 Lint 2023-01-12 11:46:46 +02:00
ibrkhalil 873db44f2e issue 7 2023-01-12 11:46:45 +02:00
ibrkhalil 1ffd5a33a4 Issue 6, Use same function signature for adding and removing hw event listenr on back button 2023-01-12 11:44:58 +02:00
ibrkhalil bb13230ba5 Issue 4 2023-01-12 11:44:56 +02:00
ibrkhalil d19514fe09 issue 2 and question 2 2023-01-12 11:44:34 +02:00
ibrkhalil b8d588a0ec Issue 1 2023-01-12 11:43:50 +02:00
ibrahem ccc7b9b324 Lint 2023-01-12 11:43:49 +02:00
ibrahem 86b2cdc76a Formatting 2023-01-12 11:43:49 +02:00
ibrkhalil df58bed557 fix reactions 2023-01-12 11:43:48 +02:00
ibrahem 76c38f4092 Lint 2023-01-12 11:43:47 +02:00
ibrahem c32bf4b827 Listen for hardware backbutton and dismiss 2023-01-12 11:43:47 +02:00
ibrahem ebd4b696f5 Lint 2023-01-12 11:43:46 +02:00
ibrahem 046b5ac9cf Handle reaction drawer height 2023-01-12 11:43:46 +02:00
ibrahem 18aa57fb8e Formatting 2023-01-12 11:43:45 +02:00
ibrkhalil 088f4c2de9 fix reactions 2023-01-12 11:43:45 +02:00
ibrahem 4ac9524398 Lint 2023-01-12 11:43:44 +02:00
ibrahem 5fb3d02921 Listen for hardware backbutton and dismiss 2023-01-12 11:43:44 +02:00
ibrahem a625a35e16 Lint 2023-01-12 11:43:43 +02:00
ibrahem 4ed84b1846 Use close bottom-sheet fn 2023-01-12 11:43:43 +02:00
ibrkhalil 14ea177f9c Comments 2023-01-12 11:43:42 +02:00
ibrahem bc7ef61855 Remove useless var 2023-01-12 11:43:42 +02:00
ibrahem 43b598ee72 Typo 2023-01-12 11:43:41 +02:00
ibrahem 21a4016aa4 Extract expected into a var 2023-01-12 11:43:41 +02:00
ibrahem 5baeffca8e Add line at EOF 2023-01-12 11:43:40 +02:00
ibrahem d0ab22ab7e Formatting 2023-01-12 11:43:37 +02:00
ibrahem b200e90bcc Add subscription tests 2023-01-12 11:41:57 +02:00
ibrahem bcaadc62f1 Fix reactions 2023-01-12 11:41:57 +02:00
ibrahem 44931c642b Fix bottom sheet not closing 2023-01-12 11:41:56 +02:00
ibrahem 5c262bcddb Fix checkbox not updating 2023-01-12 11:41:56 +02:00
ibrkhalil 42739665fc Fix reactions sheet 2023-01-12 11:41:54 +02:00
ibrkhalil 097c16931e fix reactions 2023-01-12 11:41:02 +02:00
ibrkhalil df87828d80 Fix photo selector 2023-01-12 11:39:37 +02:00
ibrahem 889027fffe Clean 2023-01-12 11:39:36 +02:00
ibrahem 8eee5fc318 Remove do 2023-01-12 11:39:36 +02:00
ibrahem 317b54ad69 Lint 2023-01-12 11:39:35 +02:00
ibrahem ada8f35cc3 Listen for hardware backbutton and dismiss 2023-01-12 11:39:35 +02:00
ibrahem 7b12f2acae Lint 2023-01-12 11:39:34 +02:00
ibrahem 06750e92be Handle reaction drawer height 2023-01-12 11:39:34 +02:00
ibrahem d5ca9b6bbe Add dismiss bottom sheet to old chat flow 2023-01-12 11:39:33 +02:00
ibrahem 6635ff42f2 Handle too high of a height on start a new chat bottom sheet 2023-01-12 11:39:33 +02:00
ibrahem 3b22d0fb43 Use close bottom-sheet fn 2023-01-12 11:39:32 +02:00
ibrahem 0702b9af79 Make vars/funs private 2023-01-12 11:39:32 +02:00
ibrahem b26ab3460e Lint 2023-01-12 11:39:31 +02:00
ibrahem bcef86fee2 Reset bottom sheet on subsequent opens 2023-01-12 11:39:30 +02:00
Andrea Maria Piana 7a5871a03f [Fixes: #14623] Enable mutual contacts by default and show banner 2023-01-12 09:16:02 +00:00
Parvesh Monu 5c0bd33697 Improve switcher cards lifecycle (#14751) 2023-01-12 02:37:55 +05:30
Churikova Tetiana 220341e0be e2e: introduced failed due to issues tests in results 2023-01-11 13:58:11 +01:00
yqrashawn ceaa363f08 fix: not using layout animation, causing flickers on android (#14753) 2023-01-11 18:37:42 +08:00
Jamie Caprani 846d628a9d chore: use banner from quo library (#14629) 2023-01-11 00:59:00 -08:00
Alexander 9ed89ac97d Fix for tapping on new contact from contact list (#14737)
* Tapping on new contact from Contact list leads to empty chat with skeleton

* Code style fix

* Small removals of unused stuff
2023-01-10 19:26:23 +01:00
Alexander 43da198c3f Communities join screens - add toast after joining/leaving (#14735)
* Add toast after joining/leaving a community

* leftover removal

* Better code for adding toasts

* Fixes

* Lint fix
2023-01-10 19:10:26 +01:00
Omar Basem 55d11d1a18 New chat fix (#14739)
* new chat fix
2023-01-10 20:19:53 +04:00
frank d2e8c5b52c fix #14733 (#14734) 2023-01-10 23:15:12 +08:00
Parvesh Monu 115fb3f590 fix default shell for -include targets (#14738) 2023-01-10 18:36:38 +05:30
yqrashawn 02a1c3597f feat: undo delete with toast (#14618) 2023-01-10 10:02:23 +08:00
Alexander 6f10ff4d3e Switcher button in chat is back (#14717) 2023-01-09 18:37:54 +01:00
Churikova Tetiana e289ad8968 e2e: fixes + workarounds 2023-01-09 14:46:24 +01:00
John Ngei 043e218320 show selected list item context actions view (#14676)
* show selected list item context actions view

* show selected list item context actions view

* fixed showing thumnails on communities
2023-01-09 16:36:17 +03:00
John Ngei 1cdcd298b0 Scrollable tags (#14182)
* refactored scrollable-tags to share the same logic with scrollable-tabs

* refactored tabs component to support scrollable-behaviour
2023-01-08 22:40:59 +03: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
191 changed files with 6156 additions and 2619 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
+4 -3
View File
@@ -1,4 +1,4 @@
.PHONY: nix-add-gcroots clean nix-clean run-metro test release _list _fix-node-perms _tmpdir-mk _tmpdir-rm _install-hooks
.PHONY: nix-add-gcroots clean nix-clean run-metro test release _list _fix-node-perms _tmpdir-rm
help: SHELL := /bin/sh
help: ##@other Show this help
@@ -118,10 +118,11 @@ _fix-node-perms: ##@prepare Fix permissions so that directory can be cleaned
$(shell test -d node_modules && chmod -R 744 node_modules)
$(shell test -d node_modules.tmp && chmod -R 744 node_modules.tmp)
_tmpdir-mk: SHELL := /bin/sh
_tmpdir-mk: ##@prepare Create a TMPDIR for temporary files
$(TMPDIR): SHELL := /bin/sh
$(TMPDIR): ##@prepare Create a TMPDIR for temporary files
@mkdir -p "$(TMPDIR)"
# Make sure TMPDIR exists every time make is called
_tmpdir-mk: $(TMPDIR)
-include _tmpdir-mk
_tmpdir-rm: SHELL := /bin/sh
+1 -1
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
+1
View File
@@ -1,2 +1,3 @@
import "node-libs-react-native/globals";
import "react-native-reanimated"
import "./app/index.js";
@@ -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
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

+1 -1
View File
@@ -83,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
+5 -78
View File
@@ -1,78 +1,14 @@
(ns i18n.i18n
(:require ["i18n-js" :as i18n]
[clojure.string :as string]
[status-im.goog.i18n :as goog.i18n]
[react-native.languages :as react-native-languages]))
[status-im.goog.i18n :as goog.i18n]))
(def default-device-language (react-native-languages/get-lang-keyword))
(def languages
#{:ar :bn :de :el :en :es :es_419 :es_AR :fil :fr :hi :id :in :it :ja :ko :ms :nl :pl :pt :pt_BR :ru
:tr :vi :zh :zh_Hant :zh_TW})
(defn valid-language
[lang]
(if (contains? languages lang)
(keyword lang)
(let [parts (string/split (name lang) #"[\-\_]")
short-lang (keyword (str (first parts) "_" (second parts)))
shortest-lang (keyword (first parts))]
(if (and (> (count parts) 2) (contains? languages short-lang))
short-lang
(when (contains? languages shortest-lang)
shortest-lang)))))
(defn require-translation
[lang-key]
(when-let [lang (valid-language (keyword lang-key))]
(case lang
:ar (js/require "../translations/ar.json")
:bn (js/require "../translations/bn.json")
:de (js/require "../translations/de.json")
:el (js/require "../translations/el.json")
:en (js/require "../translations/en.json")
:es (js/require "../translations/es.json")
:es_419 (js/require "../translations/es_419.json")
:es_AR (js/require "../translations/es_AR.json")
:fil (js/require "../translations/fil.json")
:fr (js/require "../translations/fr.json")
:hi (js/require "../translations/hi.json")
:id (js/require "../translations/id.json")
:in (js/require "../translations/id.json")
:it (js/require "../translations/it.json")
:ja (js/require "../translations/ja.json")
:ko (js/require "../translations/ko.json")
:ms (js/require "../translations/ms.json")
:nl (js/require "../translations/nl.json")
:pl (js/require "../translations/pl.json")
:pt (js/require "../translations/pt.json")
:pt_BR (js/require "../translations/pt_BR.json")
:ru (js/require "../translations/ru.json")
:tr (js/require "../translations/tr.json")
:vi (js/require "../translations/vi.json")
:zh (js/require "../translations/zh.json")
:zh_Hant (js/require "../translations/zh_hant.json")
:zh_TW (js/require "../translations/zh_TW.json"))))
(def translations-by-locale
(cond-> {:en (require-translation :en)}
(not= :en default-device-language)
(assoc default-device-language
(require-translation (-> (name default-device-language)
(string/replace "-" "_")
keyword)))))
(set! (.-fallbacks i18n) true)
(set! (.-defaultSeparator i18n) "/")
(set! (.-locale i18n) (name default-device-language))
(set! (.-translations i18n) (clj->js translations-by-locale))
(defn init
[]
(defn setup
[default-device-language translations-by-locale]
(set! (.-fallbacks i18n) true)
(set! (.-defaultSeparator i18n) "/")
(set! (.-locale i18n) (name default-device-language))
(set! (.-translations i18n) (clj->js translations-by-locale)))
(set! (.-locale i18n) default-device-language)
(set! (.-translations i18n) translations-by-locale))
(defn get-translations
[]
@@ -134,12 +70,3 @@
(.-locale i18n))
(def format-currency goog.i18n/format-currency)
(defn load-language
[lang loaded-languages]
(when-let [lang-key (valid-language (keyword lang))]
(when-not (contains? @loaded-languages lang-key)
(aset (i18n/get-translations)
lang
(require-translation lang-key))
(swap! loaded-languages conj lang-key))))
+54 -53
View File
@@ -206,59 +206,60 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def react-native-reanimated
#js
{:default #js
{:createAnimatedComponent identity
:eq nil
:greaterOrEq nil
:greaterThan nil
:lessThan nil
:lessOrEq nil
:add nil
:diff nil
:divide nil
:sub nil
:multiply nil
:abs nil
:min nil
:max nil
:neq nil
:and nil
:or nil
:not nil
:set nil
:startClock nil
:stopClock nil
:Value nil
:Clock nil
:debug nil
:log nil
:event nil
:cond nil
:block nil
:interpolateNode nil
:call nil
:timing nil
:onChange nil
:View #js {}
:FlatList #js {}
:Image #js {}
:ScrollView #js {}
:Text #js {}
:Extrapolate #js {:CLAMP nil}
:Code #js {}}
:EasingNode #js
{:bezier identity
:linear identity}
:clockRunning nil
:useSharedValue (fn [])
:useAnimatedStyle (fn [])
:withTiming (fn [])
:withDelay (fn [])
:Easing #js {:bezier identity}
:Keyframe (fn [])
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
{:default #js
{:createAnimatedComponent identity
:eq nil
:greaterOrEq nil
:greaterThan nil
:lessThan nil
:lessOrEq nil
:add nil
:diff nil
:divide nil
:sub nil
:multiply nil
:abs nil
:min nil
:max nil
:neq nil
:and nil
:or nil
:not nil
:set nil
:startClock nil
:stopClock nil
:Value nil
:Clock nil
:debug nil
:log nil
:event nil
:cond nil
:block nil
:interpolateNode nil
:call nil
:timing nil
:onChange nil
:View #js {}
:Image #js {}
:ScrollView #js {}
:Text #js {}
:Extrapolate #js {:CLAMP nil}
:Code #js {}}
:EasingNode #js
{:bezier identity
:linear identity}
:clockRunning nil
:useSharedValue (fn [])
:useAnimatedStyle (fn [])
:withTiming (fn [])
:withDelay (fn [])
:Easing #js {:bezier identity}
:Keyframe (fn [])
:enableLayoutAnimations (fn [])
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
(def react-native-gesture-handler
#js
{:default #js {}
+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
@@ -1,4 +1,4 @@
(ns quo2.components.banners.--tests--.banner-component-spec
(ns quo2.components.banners.banner.component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.banners.banner.view :as banner]
[reagent.core :as reagent]))
@@ -15,3 +15,13 @@
(.toBeTruthy))
(-> (js/expect (rtl/screen.getByText "5"))
(.toBeTruthy))))
(js/global.test "banner component fires an event when pressed"
(let [mock-fn (js/jest.fn)]
(fn []
(render-banner {:on-press mock-fn
:pins-count "5"
:latest-pin-text "this message"})
(rtl/fireEvent.press (rtl/screen.getByText "this message"))
(-> (js/expect mock-fn)
(.toHaveBeenCalledTimes 1)))))
+20 -11
View File
@@ -3,17 +3,26 @@
(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})
{:height 40
:flex 1
:background-color colors/primary-50-opa-20
:flex-direction :row
:align-items :center
:padding-right 22
:padding-left 20
:padding-vertical 10})
(def counter
{:padding-right 22
:height 20
:width 20
{:flex 1
:justify-content :center
:align-items :center})
:align-items :center})
(def icon
{:flex 1
:margin-right 10})
(defn text
[hide-pin?]
{:flex (if hide-pin? 16 15)
:margin-right 10})
+22 -16
View File
@@ -3,22 +3,28 @@
[quo2.components.counter.counter :as counter]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[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])]])
[{:keys [hide-pin? latest-pin-text pins-count on-press]}]
(when (pos? pins-count)
[rn/touchable-opacity
{:accessibility-label :pinned-banner
:style style/container
:active-opacity 1
:on-press on-press}
(when-not hide-pin?
[rn/view {:style style/icon}
[icons/icon :i/pin
{:color (colors/theme-colors colors/neutral-100 colors/white)
:size 20}]])
[rn/view {:style (style/text hide-pin?)}
[text/text
{:number-of-lines 1
:size :paragraph-2}
latest-pin-text]]
[rn/view
{:accessibility-label :pins-count
:style style/counter}
(when (> pins-count 1) [counter/counter {:type :secondary} pins-count])]]))
+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
@@ -5,19 +5,8 @@
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]))
(defn community-icon-view
[community-icon]
[rn/view
{:width 32
:height 32}
[fast-image/fast-image
{:source {:uri community-icon}
:style {:height 32
:border-radius 16
:width 32}}]])
[quo2.components.community.icon :as community-icon]
[react-native.core :as rn]))
(defn notification-view
[{:keys [muted?
@@ -54,27 +43,18 @@
unread-messages?
unread-mentions-count
community-icon
tokens
background-color]}]
tokens]}]
[rn/view
{:style (merge (style/community-card 16)
{:margin-bottom 12
:margin-horizontal 20})}
{:margin-bottom 12})}
[rn/touchable-highlight
(merge {:style {:height 56
:border-radius 16}}
props)
[rn/view {:flex 1}
[rn/view
{:flex-direction :row
:border-radius 16
:padding-horizontal 12
:align-items :center
:padding-vertical 8
:background-color background-color}
[rn/view]
(when community-icon
[community-icon-view community-icon])
[rn/view (style/list-info-container)
[community-icon/community-icon
{:images community-icon} 32]
[rn/view
{:flex 1
:margin-horizontal 12}
@@ -109,39 +89,36 @@
community-icon
tokens
locked?]}]
[rn/view {:margin-bottom 20}
[rn/touchable-highlight
(merge {:underlay-color colors/primary-50-opa-5
:style {:border-radius 12}}
props)
[rn/view {:flex 1}
[rn/touchable-highlight
(merge {:underlay-color (colors/theme-colors
colors/neutral-5
colors/neutral-95)
:style {:border-radius 12}}
props)
[rn/view {:flex 1}
[rn/view (style/membership-info-container)
[community-icon/community-icon
{:images community-icon} 32]
[rn/view
{:flex-direction :row
:border-radius 16
:align-items :center}
{:flex 1
:margin-left 12
:justify-content :center}
[text/text
{:accessibility-label :chat-name-text
:number-of-lines 1
:ellipsize-mode :tail
:weight :semi-bold
:size :paragraph-1}
name]]
(when community-icon
[community-icon-view community-icon])
[rn/view
{:flex 1
:margin-left 12
:justify-content :center}
[text/text
{:accessibility-label :chat-name-text
:number-of-lines 1
:ellipsize-mode :tail
:weight :semi-bold
:size :paragraph-1}
name]]
[rn/view
{:justify-content :center
:margin-right 16}
(if (= status :gated)
[community-view/permission-tag-container
{:locked? locked?
:tokens tokens}]
[notification-view
{:muted? muted?
:unread-mentions-count unread-mentions-count
:unread-messages? unread-messages?}])]]]]])
[rn/view
{:justify-content :center
:margin-right 16}
(if (= status :gated)
[community-view/permission-tag-container
{:locked? locked?
:tokens tokens}]
[notification-view
{:muted? muted?
:unread-mentions-count unread-mentions-count
:unread-messages? unread-messages?}])]]]])
@@ -46,12 +46,12 @@
^{:key id}
[rn/view {:margin-right 8}
[tag/tag
{:id id
:size 24
:label tag-label
:type :emoji
:labelled true
:resource resource}]])])
{:id id
:size 24
:label tag-label
:type :emoji
:labelled? true
:resource resource}]])])
(defn community-title
[{:keys [title description size] :or {size :small}}]
+1 -1
View File
@@ -10,4 +10,4 @@
:border-width 0
:border-color :transparent
:width size
:height size}}]))
:height size}}]))
+12 -11
View File
@@ -77,19 +77,20 @@
colors/white
colors/neutral-90)})
(defn list-view-content-container
(defn list-info-container
[]
{:flex-direction :row
:border-radius 16
:align-items :center
:background-color (colors/theme-colors
colors/white
colors/neutral-90)})
{:flex-direction :row
:border-radius 16
:padding-horizontal 12
:align-items :center
:padding-vertical 8})
(defn list-view-chat-icon
(defn membership-info-container
[]
{:border-radius 32
:padding 12})
{:flex-direction :row
:border-radius 16
:align-items :center
:height 48})
(defn community-title-description-container
[margin-top]
@@ -107,4 +108,4 @@
[]
{:position :absolute
:top 8
:right 8})
:right 8})
@@ -0,0 +1,13 @@
(ns quo2.components.drawers.permission-context.--tests--.permission-context-component-spec
(:require [quo2.components.drawers.permission-context.view :as permission-context]
[react-native.core :as rn]
[test-helpers.component :as h]))
(h/describe "permission context"
(h/test
(h/render [permission-context/view
[rn/text
{:accessibility-label :accessibility-id}
"a sample label"]])
(-> (js/expect (h/get-by-label-text :accessibility-id))
(.toBeTruthy))))
@@ -0,0 +1,16 @@
(ns quo2.components.drawers.permission-context.style
(:require [quo2.foundations.colors :as colors]))
(def radius 20)
(def container
{:padding-top 16
:padding-bottom 48
:padding-horizontal 20
:shadow-offset {:width 0
:height 2}
:shadow-radius radius
:border-top-left-radius radius
:border-top-right-radius radius
:elevation 2
:shadow-opacity 1
:shadow-color colors/shadow})
@@ -0,0 +1,8 @@
(ns quo2.components.drawers.permission-context.view
(:require [react-native.core :as rn]
[quo2.components.drawers.permission-context.style :as style]))
(defn view
[children]
[rn/view {:style style/container}
children])
@@ -7,12 +7,14 @@
(defn themes
[type]
(case type
:main {:icon-color (theme-colors colors/neutral-50 colors/neutral-10)
:background (theme-colors colors/white colors/neutral-90)
:text-color (theme-colors colors/neutral-100 colors/white)}
:danger {:icon-color (theme-colors colors/danger-50 colors/danger-60)
:background (theme-colors colors/white colors/neutral-90)
:text-color (theme-colors colors/danger-50 colors/danger-60)}))
:main {:icon-color (theme-colors colors/neutral-50 colors/neutral-10)
:background (theme-colors colors/white colors/neutral-90)
:text-color (theme-colors colors/neutral-100 colors/white)}
:danger {:icon-color (theme-colors colors/danger-50 colors/danger-60)
:background (theme-colors colors/white colors/neutral-90)
:text-color (theme-colors colors/danger-50 colors/danger-60)}
:transparent {:icon-color (theme-colors colors/neutral-50 colors/neutral-10)
:text-color (theme-colors colors/neutral-100 colors/white)}))
(defn menu-item
[{:keys [type title accessibility-label icon on-press style-props subtitle subtitle-color]
@@ -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)])
+17 -11
View File
@@ -8,14 +8,14 @@
[react-native.core :as rn]))
(def ^:private themes
{:container {:light {:background-color colors/white-opa-70}
:dark {:background-color colors/neutral-80-opa-70}}
:text {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:icon {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:action-container {:light {:background-color :colors/neutral-80-opa-5}
:dark {:background-color :colors/white-opa-5}}})
{:container {:dark {:background-color colors/white-opa-70}
:light {:background-color colors/neutral-80-opa-70}}
:text {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:icon {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:action-container {:dark {:background-color :colors/neutral-80-opa-5}
:light {:background-color :colors/white-opa-5}}})
(defn- merge-theme-style
[component-key styles]
@@ -23,7 +23,9 @@
(defn toast-action-container
[{:keys [on-press style]} & children]
[rn/touchable-highlight {:on-press on-press}
[rn/touchable-highlight
{:on-press on-press
:underlay-color :transparent}
[into
[rn/view
{:style (merge
@@ -40,7 +42,8 @@
(defn toast-undo-action
[duration on-press]
[toast-action-container {:on-press on-press}
[toast-action-container
{:on-press on-press :accessibility-label :toast-undo-action}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[text/text
@@ -63,7 +66,10 @@
[rn/view {:style {:padding 2}} left]
[rn/view {:style {:padding 4 :flex 1}}
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
{:size :paragraph-2
:weight :medium
:style (merge-theme-style :text {})
:accessibility-label :toast-content}
middle]]
(when right right)]])
@@ -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])])
+137 -130
View File
@@ -28,28 +28,6 @@
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)}}
[notification-dot]])
(defn tabs
[{:keys [default-active on-change style]}]
(let [active-tab-id (reagent/atom default-active)]
(fn [{:keys [data size] :or {size default-tab-size}}]
[rn/view (merge {:flex-direction :row} style)
(doall
(for [{:keys [label id notification-dot? accessibility-label]} data]
^{:key id}
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
(when notification-dot?
[indicator])
[tab/tab
{:id id
:size size
:accessibility-label accessibility-label
:active (= id @active-tab-id)
:on-press (fn []
(reset! active-tab-id id)
(when on-change
(on-change id)))}
label]]))])))
(defn- calculate-fade-end-percentage
[{:keys [offset-x content-width layout-width max-fade-percentage]}]
(let [fade-percentage (max max-fade-percentage
@@ -60,30 +38,35 @@
0.99
(utils.number/naive-round fade-percentage 2))))
(defn scrollable-tabs
"Just like the component `tabs`, displays horizontally scrollable tabs with
extra options to control if/how the end of the scroll view fades.
Tabs are rendered using ReactNative's FlatList, which offers the convenient
`scrollToIndex` method. FlatList accepts VirtualizedList and ScrollView props,
and so does this component.
Usage:
[tabs/scrollable-tabs
{:scroll-on-press? true
:fade-end? true
:on-change #(...)
:default-active :tab-a
:data [{:id :tab-a :label \"Tab A\"}
{:id :tab-b :label \"Tab B\"}]}]]
(defn tabs
"Usage:
{:type :icon/:emoji/:label
:component tag/tab
:size 32/24
:on-press fn
:blurred? true/false
:labelled? true/false
:disabled? true/false
:scrollable? false
:scroll-on-press? true
:fade-end? true
:on-change fn
:default-active tag-id
:data [{:id :label \"\" :resource \"url\"}
{:id :label \"\" :resource \"url\"}]}
Opts:
- `size` number
- `scroll-on-press?` When non-nil, clicking on a tab centers it the middle
- `component` this is to determine which component is to be rendered since the
logic in this view is shared between tab and tag component
- `blurred` boolean: use to determine border color if the background is blurred
- `type` can be icon or emoji with or without a tag label
- `labelled` boolean: is true if tag has label else false
- `size` number
- `scroll-on-press?` When non-nil, clicking on a tag centers it the middle
(with animation enabled).
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
- `fade-end-percentage` Percentage where fading starts relative to the total
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
- `fade-end-percentage` Percentage where fading starts relative to the total
layout width of the `flat-list` data."
[{:keys [default-active fade-end-percentage]
:or {fade-end-percentage 0.8}}]
(let [active-tab-id (reagent/atom default-active)
@@ -97,99 +80,123 @@
on-scroll
scroll-event-throttle
scroll-on-press?
scrollable?
style
size
blur?
override-theme]
:or {fade-end-percentage fade-end-percentage
fade-end? false
scroll-event-throttle 64
scrollable? false
scroll-on-press? false
size default-tab-size}
:as props}]
(let [maybe-mask-wrapper (if fade-end?
[masked-view/masked-view
{:mask-element
(reagent/as-element
[linear-gradient/linear-gradient
{:colors [:black :transparent]
:locations [(get @fading :fade-end-percentage) 1]
:start {:x 0 :y 0}
:end {:x 1 :y 0}
:pointer-events :none
:style {:width "100%"
:height "100%"}}])}]
[:<>])]
(conj
maybe-mask-wrapper
[rn/flat-list
(merge
(dissoc props
:default-active
:fade-end-percentage
:fade-end?
:on-change
:scroll-on-press?
:size)
(when scroll-on-press?
{:initial-scroll-index (utils.collection/first-index #(= @active-tab-id (:id %)) data)})
{:ref #(reset! flat-list-ref %)
:extra-data (str @active-tab-id)
:horizontal true
:scroll-event-throttle scroll-event-throttle
: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
e
"nativeEvent.contentOffset.x")
content-width (oget
e
"nativeEvent.contentSize.width")
layout-width
(oget e "nativeEvent.layoutMeasurement.width")
new-percentage
(calculate-fade-end-percentage
{:offset-x offset-x
:content-width content-width
:layout-width layout-width
:max-fade-percentage fade-end-percentage})]
;; Avoid unnecessary re-rendering.
(when (not= new-percentage
(get @fading :fade-end-percentage))
(swap! fading assoc
:fade-end-percentage
new-percentage))))
(when on-scroll
(on-scroll e)))
:render-fn (fn [{:keys [id label]} index]
[rn/view
{:style {:margin-right (if (= size default-tab-size)
12
8)
:padding-right (when (= index
(dec (count data)))
(get-in props
[:style
:padding-left]))}}
[tab/tab
{:id id
:size size
:override-theme override-theme
:blur? blur?
:active (= id @active-tab-id)
:on-press (fn [id]
(reset! active-tab-id id)
(when scroll-on-press?
(.scrollToIndex ^js
@flat-list-ref
#js
{:animated true
:index index
:viewPosition
0.5}))
(when on-change
(on-change id)))}
label]])})])))))
(if scrollable?
(let [maybe-mask-wrapper (if fade-end?
[masked-view/masked-view
{:mask-element
(reagent/as-element
[linear-gradient/linear-gradient
{:colors [:black :transparent]
:locations [(get @fading :fade-end-percentage) 1]
:start {:x 0 :y 0}
:end {:x 1 :y 0}
:pointer-events :none
:style {:width "100%"
:height "100%"}}])}]
[:<>])]
(conj
maybe-mask-wrapper
[rn/flat-list
(merge
(dissoc props
:default-active
:fade-end-percentage
:fade-end?
:on-change
:scroll-on-press?
:size)
(when scroll-on-press?
{:initial-scroll-index (utils.collection/first-index #(= @active-tab-id (:id %)) data)})
{:ref #(reset! flat-list-ref %)
:extra-data (str @active-tab-id)
:horizontal true
:scroll-event-throttle scroll-event-throttle
: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
e
"nativeEvent.contentOffset.x")
content-width
(oget
e
"nativeEvent.contentSize.width")
layout-width
(oget e
"nativeEvent.layoutMeasurement.width")
new-percentage
(calculate-fade-end-percentage
{:offset-x offset-x
:content-width content-width
:layout-width layout-width
:max-fade-percentage fade-end-percentage})]
;; Avoid unnecessary re-rendering.
(when (not= new-percentage
(get @fading :fade-end-percentage))
(swap! fading assoc
:fade-end-percentage
new-percentage))))
(when on-scroll
(on-scroll e)))
:render-fn (fn [{:keys [id label]} index]
[rn/view
{:style {:margin-right (if (= size default-tab-size)
12
8)
:padding-right (when (= index
(dec (count data)))
(get-in props
[:style
:padding-left]))}}
[tab/tab
{:id id
:size size
:override-theme override-theme
:blur? blur?
:active (= id @active-tab-id)
:on-press (fn [id]
(reset! active-tab-id id)
(when scroll-on-press?
(.scrollToIndex
^js
@flat-list-ref
#js
{:animated true
:index index
:viewPosition
0.5}))
(when on-change
(on-change id)))}
label]])})]))
[rn/view (merge {:flex-direction :row} style)
(doall
(for [{:keys [label id notification-dot? accessibility-label]} data]
^{:key id}
[rn/view {:style {:margin-right (if (= size default-tab-size) 12 8)}}
(when notification-dot?
[indicator])
[tab/tab
{:id id
:size size
:accessibility-label accessibility-label
:active (= id @active-tab-id)
:on-press (fn []
(reset! active-tab-id id)
(when on-change
(on-change id)))}
label]]))]))))
+5 -9
View File
@@ -16,25 +16,21 @@
{:width size})))
(defn base-tag
"opts
{:type :icon/:emoji/:label/:permission
:size 32/24}
:labelled true"
[_]
(fn [{:keys [id size disabled border-color border-width background-color on-press
accessibility-label label type]
(fn [{:keys [id size disabled? border-color border-width background-color on-press
accessibility-label labelled? type]
:or {size 32}} children]
[rn/touchable-without-feedback
(merge {:disabled disabled
(merge {:disabled disabled?
:accessibility-label accessibility-label}
(when on-press
{:on-press #(on-press id)}))
[rn/view
{:style (merge (style-container size
disabled
disabled?
border-color
border-width
background-color
label
labelled?
type))}
children]]))
+45 -9
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
@@ -69,7 +64,7 @@
[rn/image
{:style {:width 20
:border-radius 10
:background-color :white
:background-color :red
:height 20}
:source photo}]
[rn/view
@@ -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])
+32 -18
View File
@@ -68,26 +68,40 @@
label])])
(defn tag
"opts
{:type :icon/:emoji/:label
:size 32/24
:on-press fn
:blurred? true/false
:resource icon/image
:labelled? true/false
:disabled? true/false}
opts
- `blurred` boolean: use to determine border color if the background is blurred
- `type` can be icon or emoji with or without a tag label
- `labelled` boolean: is true if tag has label else false"
[_ _]
(fn [{:keys [id on-press disabled size resource active accessibility-label
label type labelled blurred icon-color]
(fn [{:keys [id on-press disabled? size resource active accessibility-label
label type labelled? blurred? icon-color]
:or {size 32}}]
(let [state (cond disabled :disabled
active :active
:else :default)
(let [state (cond disabled? :disabled
active :active
:else :default)
{:keys [border-color blurred-border-color text-color]}
(get-in themes [(theme/get-theme) state])]
[base-tag/base-tag
{:id id
:size size
:border-width 1
:border-color (if blurred
blurred-border-color
border-color)
:on-press on-press
:accessibility-label accessibility-label
:disabled disabled
:type type
:label label}
[tag-resources size type resource icon-color label text-color labelled]])))
[rn/view {:style {:align-items :center}}
[base-tag/base-tag
{:id id
:size size
:border-width 1
:border-color (if blurred?
blurred-border-color
border-color)
:on-press on-press
:accessibility-label accessibility-label
:disabled? disabled?
:type type
:labelled? (if (= type :label) true labelled?)}
[tag-resources size type resource icon-color label text-color labelled?]]])))
+168 -26
View File
@@ -1,29 +1,171 @@
(ns quo2.components.tags.tags
(:require [quo2.components.tags.tag :as tag]
[react-native.core :as rn]
[reagent.core :as reagent]))
(:require [reagent.core :as reagent]
[quo.react-native :as rn]
[oops.core :refer [oget]]
[status-im.ui.components.react :as react]
[status-im.utils.core :as utils]
[quo2.components.tags.tag :as tag]
[utils.number :as number-utils]))
(def default-tab-size 32)
(defn calculate-fade-end-percentage
[{:keys [offset-x content-width layout-width max-fade-percentage]}]
(let [fade-percentage (max max-fade-percentage
(/ (+ layout-width offset-x)
content-width))]
;; Truncate to avoid unnecessary rendering.
(if (> fade-percentage 0.99)
0.99
(number-utils/naive-round fade-percentage 2))))
(defn tags
[{:keys [default-active on-change]}]
(let [active-tab-id (reagent/atom default-active)]
(fn [{:keys [data size type labelled disabled blurred icon-color] :or {size 32}}]
(let [active-id @active-tab-id]
[rn/view {:flex-direction :row}
(for [{:keys [tag-label id resource]} data]
^{:key id}
[rn/view {:margin-right 8}
[tag/tag
(merge {:id id
:size size
:type type
:label (if labelled tag-label (when (= type :label) tag-label))
:active (= id active-id)
:disabled disabled
:blurred blurred
:icon-color icon-color
:labelled (if (= type :label) true labelled)
:resource (if (= type :icon)
:i/placeholder
resource)
:on-press #(do (reset! active-tab-id %)
(when on-change (on-change %)))})]])]))))
"Usage:
{:type :icon/:emoji/:label
:component tag/tab
:size 32/24
:on-press fn
:blurred? true/false
:labelled? true/false
:disabled? true/false
:scroll-on-press? true
:scrollable? false
:fade-end? true
:on-change fn
:default-active tag-id
:data [{:id :label \"\" :resource \"url\"}
{:id :label \"\" :resource \"url\"}]}
Opts:
- `component` this is to determine which component is to be rendered since the
logic in this view is shared between tab and tag component
- `blurred` boolean: use to determine border color if the background is blurred
- `type` can be icon or emoji with or without a tag label
- `labelled` boolean: is true if tag has label else false
- `size` number
- `scroll-on-press?` When non-nil, clicking on a tag centers it the middle
(with animation enabled).
- `fade-end?` When non-nil, causes the end of the scrollable view to fade out.
- `fade-end-percentage` Percentage where fading starts relative to the total
layout width of the `flat-list` data."
[{:keys [default-active fade-end-percentage]
:or {fade-end-percentage 0.8}}]
(let [active-tab-id (reagent/atom default-active)
fading (reagent/atom {:fade-end-percentage fade-end-percentage})
flat-list-ref (atom nil)]
(fn
[{:keys [data
fade-end-percentage
fade-end?
on-change
on-scroll
scroll-event-throttle
scrollable?
scroll-on-press?
size
type
labelled?
disabled?
blurred?
icon-color]
:or {fade-end-percentage fade-end-percentage
fade-end? false
scroll-event-throttle 64
scrollable? false
scroll-on-press? false
size default-tab-size}
:as props}]
(let [maybe-mask-wrapper (if fade-end?
[react/masked-view
{:mask-element (reagent/as-element
[react/linear-gradient
{:colors [:black :transparent]
:locations [(get @fading :fade-end-percentage)
1]
:start {:x 0 :y 0}
:end {:x 1 :y 0}
:pointer-events :none
:style {:width "100%"
:height "100%"}}])}]
[:<>])]
(if scrollable?
(conj
maybe-mask-wrapper
[rn/flat-list
(merge (dissoc props
:default-active
:fade-end-percentage
:fade-end?
:on-change
:scroll-on-press?
:size)
(when scroll-on-press?
{:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)})
{:ref #(reset! flat-list-ref %)
:extra-data (str @active-tab-id)
:horizontal true
:scroll-event-throttle scroll-event-throttle
:shows-horizontal-scroll-indicator false
:data data
:key-fn (comp str :id)
:on-scroll (fn [^js e]
(when fade-end?
(let [offset-x (oget e "nativeEvent.contentOffset.x")
content-width (oget e "nativeEvent.contentSize.width")
layout-width (oget e "nativeEvent.layoutMeasurement.width")
new-percentage (calculate-fade-end-percentage
{:offset-x offset-x
:content-width content-width
:layout-width layout-width
:max-fade-percentage fade-end-percentage})]
;; Avoid unnecessary re-rendering.
(when (not= new-percentage (get @fading :fade-end-percentage))
(swap! fading assoc :fade-end-percentage new-percentage))))
(when on-scroll
(on-scroll e)))
:render-fn (fn [{:keys [id label resource]} index]
[rn/view
{:style {:margin-right (if (= size default-tab-size) 12 8)
:padding-right (when (= index (dec (count data)))
(get-in props [:style :padding-left]))}}
[tag/tag
{:id id
:size size
:active (= id @active-tab-id)
:resource resource
:blurred? blurred?
:icon-color icon-color
:disabled? disabled?
:label label
:type type
:labelled? labelled?
:on-press (fn [id]
(reset! active-tab-id id)
(when scroll-on-press?
(.scrollToIndex @flat-list-ref
#js
{:animated true
:index index
:viewPosition 0.5}))
(when on-change
(on-change id)))}
label]])})])
[rn/view {:style {:flex-direction :row}}
(for [{:keys [label id resource]} data]
^{:key id}
[rn/view {:style {:margin-right 8}}
[tag/tag
(merge {:id id
:size size
:type type
:label (if labelled? label (when (= type :label) label))
:active (= id active-tab-id)
:disabled? disabled?
:blurred? blurred?
:icon-color icon-color
:labelled? (if (= type :label) true labelled?)
:resource (if (= type :icon)
:i/placeholder
resource)
:on-press #(do (reset! active-tab-id %)
(when on-change (on-change %)))})]])])))))
+6 -1
View File
@@ -52,6 +52,7 @@
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)
@@ -74,8 +75,9 @@
(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)
@@ -127,6 +129,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)
+2 -1
View File
@@ -1,9 +1,10 @@
(ns quo2.core-spec
(:require [quo2.components.banners.--tests--.banner-component-spec]
(:require [quo2.components.banners.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.drawers.permission-context.--tests--.permission-context-component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.filter.component-spec]))
+1 -2
View File
@@ -24,7 +24,6 @@
(reagent/adapt-react-class (.-TouchableWithoutFeedback ^js react-native)))
(def flat-list flat-list/flat-list)
(def flat-list-animated flat-list/flat-list-animated)
(def section-list section-list/section-list)
@@ -102,4 +101,4 @@
[f]
(let [fn-ref (use-ref f)]
(oops/oset! fn-ref "current" f)
(use-effect-once (fn [] #((oops/oget fn-ref "current"))))))
(use-effect-once (fn [] (fn [] (oops/ocall! fn-ref "current"))))))
-6
View File
@@ -1,10 +1,8 @@
(ns react-native.flat-list
(:require ["react-native" :as react-native]
["react-native-reanimated" :default reanimated]
[reagent.core :as reagent]))
(def react-native-flat-list (reagent/adapt-react-class (.-FlatList ^js react-native)))
(def react-native-flat-list-animated (reagent/adapt-react-class (.-FlatList ^js reanimated)))
(defn- wrap-render-fn
[f render-data]
@@ -41,7 +39,3 @@
(defn flat-list
[props]
[react-native-flat-list (base-list-props props)])
(defn flat-list-animated
[props]
[react-native-flat-list-animated (base-list-props props)])
+17 -20
View File
@@ -1,29 +1,24 @@
(ns react-native.reanimated
(:require ["react-native" :as react-native]
(:require ["react-native" :as rn]
["react-native-linear-gradient" :default LinearGradient]
["react-native-reanimated" :default reanimated :refer
(Easing
FadeInLeft
FadeOutRight
Keyframe
LinearTransition
SlideInUp
SlideOutUp
cancelAnimation
useAnimatedStyle
useSharedValue
withDelay
withRepeat
withSpring
withTiming)]
(useSharedValue useAnimatedStyle
withTiming
withDelay
withSpring
withRepeat
Easing
Keyframe
cancelAnimation
SlideInUp
SlideOutUp
LinearTransition)]
[clojure.string :as string]
[reagent.core :as reagent]))
;; Animations
(def slide-in-up-animation SlideInUp)
(def slide-out-up-animation SlideOutUp)
(def fade-in-left-animation FadeInLeft)
(def fade-out-right-animation FadeOutRight)
(def linear-transition LinearTransition)
;; Animated Components
@@ -31,7 +26,7 @@
(def view (reagent/adapt-react-class (.-View reanimated)))
(def image (reagent/adapt-react-class (.-Image reanimated)))
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js react-native)))
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
(def linear-gradient (create-animated-component LinearGradient))
@@ -59,11 +54,13 @@
;; Helper functions
(defn get-shared-value
[anim]
(.-value anim))
(when anim
(.-value anim)))
(defn set-shared-value
[anim val]
(set! (.-value anim) val))
(when anim
(set! (.-value anim) val)))
(defn kebab-case->camelCase
[k]
+17 -9
View File
@@ -19,7 +19,8 @@
[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]))
[taoensso.timbre :as log]
status-im2.common.bottom-sheet.view))
(defn chats
[]
@@ -220,11 +221,17 @@
(rf/defn close-chat
{:events [:close-chat]}
[{:keys [db] :as cofx}]
[{:keys [db] :as cofx} navigate-to-shell?]
(when-let [chat-id (:current-chat-id db)]
(chat.state/reset-visible-item)
(rf/merge cofx
{:db (dissoc db :current-chat-id)}
(merge
{:db (dissoc db :current-chat-id)}
(let [community-id (get-in db [:chats chat-id :community-id])]
;; When navigating back from community chat to community, update switcher card
(when (and community-id (not navigate-to-shell?))
{:dispatch [:shell/add-switcher-card
:community {:community-id community-id}]})))
(delete-for-me/sync-all)
(delete-message/send-all)
(offload-messages chat-id))))
@@ -243,7 +250,8 @@
[{:keys [db now] :as cofx} chat-id]
(rf/merge cofx
{:clear-message-notifications
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]
:dispatch [:shell/close-switcher-card chat-id]}
(deactivate-chat chat-id)
(offload-messages chat-id)))
@@ -268,7 +276,7 @@
(navigation/change-tab :chat)
(when-not (= (:view-id db) :community)
(navigation/pop-to-root-tab :chat-stack))
(close-chat)
(close-chat false)
(force-close-chat chat-id)
(fn [{:keys [db]}]
{:db (assoc db :current-chat-id chat-id)})
@@ -284,7 +292,7 @@
{:dispatch [:navigate-to-nav2 :chat chat-id from-shell?]}
(when-not (= (:view-id db) :community)
(navigation/pop-to-root-tab :shell-stack))
(close-chat)
(close-chat false)
(force-close-chat chat-id)
(fn [{:keys [db]}]
{:db (assoc db :current-chat-id chat-id)})
@@ -311,7 +319,7 @@
(assoc-in [:chats chat-id] chat)
:always
(update :chats-home-list conj chat-id))
:dispatch [:chat.ui/navigate-to-chat chat-id]}))
:dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]}))
(rf/defn navigate-to-user-pinned-messages
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
@@ -446,7 +454,7 @@
:content (i18n/label :t/clear-history-confirmation-content)
:confirm-button-text (i18n/label :t/clear-history-action)
:on-accept #(do
(re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
(rf/defn gaps-failed
@@ -515,7 +523,7 @@
:content (i18n/label :t/delete-chat-confirmation)
:confirm-button-text (i18n/label :t/delete)
:on-accept #(do
(re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(re-frame/dispatch [:chat.ui/remove-chat chat-id]))}})
(rf/defn decrease-unviewed-count
+3 -1
View File
@@ -184,9 +184,11 @@
(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"})})
+15 -4
View File
@@ -4,9 +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]
[utils.re-frame :as rf]
[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]
@@ -101,6 +101,17 @@
:on-success #(re-frame/dispatch
[::mark-all-read-in-community-successful %])}]}))
;; 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]}
@@ -131,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]
+8 -4
View File
@@ -1,8 +1,8 @@
(ns status-im.chat.models.message-list
(:require ["functional-red-black-tree" :as rb-tree]
[status-im.constants :as constants]
[utils.re-frame :as rf]
[utils.datetime :as datetime]))
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
(defn- add-datemark
[{:keys [whisper-timestamp] :as msg}]
@@ -20,7 +20,9 @@
from
outgoing
whisper-timestamp
deleted-for-me?]}]
deleted?
deleted-for-me?
albumize?]}]
(-> {:whisper-timestamp whisper-timestamp
:from from
:one-to-one? (= constants/message-type-one-to-one message-type)
@@ -28,11 +30,13 @@
(or
(= constants/message-type-private-group-system-message
message-type)
deleted?
deleted-for-me?))
:clock-value clock-value
:type :message
:message-id message-id
:outgoing (boolean outgoing)}
:outgoing (boolean outgoing)
:albumize? albumize?}
add-datemark
add-timestamp))
+32 -16
View File
@@ -1,9 +1,10 @@
(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]
[re-frame.core :as re-frame]
[i18n.i18n :as i18n]
[status-im.async-storage.core :as async-storage]
[status-im.bottom-sheet.core :as bottom-sheet]
[status-im.constants :as constants]
@@ -11,6 +12,7 @@
[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.common.toasts.events :as toasts]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
@@ -28,10 +30,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]
@@ -64,12 +66,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)))
@@ -110,15 +112,28 @@
(rf/defn left
{:events [::left]}
[cofx response-js]
(rf/merge cofx
(handle-response cofx response-js)
(navigation/pop-to-root-tab :chat-stack)
(activity-center/notifications-fetch-unread-count)))
(let [community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :placeholder
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/left-community {:community community-name})})
(navigation/navigate-back)
(activity-center/notifications-fetch-unread-count))))
(rf/defn joined
{:events [::joined ::requested-to-join]}
[cofx response-js]
(handle-response cofx response-js))
(let [[event-name _] (:event cofx)
community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :placeholder
:icon-color (:positive-01 @colors/theme)
:text (i18n/label (if (= event-name ::joined)
:t/joined-community
:t/requested-to-join-community)
{:community community-name})}))))
(rf/defn export
{:events [::export-pressed]}
@@ -172,6 +187,7 @@
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
:dispatch [:shell/close-switcher-card community-id]
:json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
+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")
+1
View File
@@ -47,6 +47,7 @@
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key :added] false))
:dispatch [:shell/close-switcher-card public-key]
:clear-message-notifications
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
(activity-center/notifications-fetch-unread-count)
-10
View File
@@ -4,7 +4,6 @@
[status-im.contact.block :as contact.block]
[status-im.contact.db :as contact.db]
[status-im.data-store.contacts :as contacts-store]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
@@ -151,15 +150,6 @@
#(re-frame/dispatch [:sanitize-messages-and-process-response %]))
(navigation/navigate-back)))
(rf/defn switch-mutual-contact-requests-enabled
{:events [:multiaccounts.ui/switch-mutual-contact-requests-enabled]}
[cofx enabled?]
(multiaccounts.update/multiaccount-update
cofx
:mutual-contact-enabled?
enabled?
nil))
(rf/defn set-search-query
{:events [:contacts/set-search-query]}
[{:keys [db] :as cofx} value]
+12 -10
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))]
@@ -86,8 +86,9 @@
(get-in db [:contacts/contacts public-key]))
(defn added?
([contact]
(:added contact))
([{:keys [contact-request-state]}]
(or (= constants/contact-request-state-mutual contact-request-state)
(= constants/contact-request-state-sent contact-request-state)))
([db public-key]
(added? (get-in db [:contacts/contacts public-key]))))
@@ -98,27 +99,28 @@
(blocked? (get-in db [:contacts/contacts public-key]))))
(defn active?
"Checks that the user is added to the contact and not blocked"
"Checks that we are mutual contacts"
([contact]
(and (:added contact)
(and (= constants/contact-request-state-mutual
(:contact-request-state contact))
(not (:blocked contact))))
([db public-key]
(active? (get-in db [:contacts/contacts public-key]))))
(defn enrich-contact
([contact] (enrich-contact contact nil nil))
([{:keys [added public-key] :as contact} setting own-public-key]
([{:keys [public-key] :as contact} setting own-public-key]
(cond-> (-> contact
(dissoc :ens-verified-at :ens-verification-retries)
(assoc :blocked? (:blocked contact)
:active? (active? contact)
:added? added)
:added? (added? contact))
(multiaccounts/contact-with-names))
(and setting
(not= public-key own-public-key)
(or (= setting constants/profile-pictures-visibility-none)
(and (= setting constants/profile-pictures-visibility-contacts-only)
(not added))))
(not (added? contact)))))
(dissoc :images))))
(defn enrich-contacts
+14 -14
View File
@@ -1,5 +1,5 @@
(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]
[utils.re-frame :as rf]
@@ -58,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 %)))
+2 -2
View File
@@ -1,12 +1,12 @@
(ns status-im.data-store.contacts
(:require [clojure.set :as clojure.set]
(: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
+26 -25
View File
@@ -1,5 +1,5 @@
(ns status-im.data-store.messages
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as set]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
@@ -10,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)
+6 -6
View File
@@ -1,5 +1,5 @@
(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]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
@@ -8,8 +8,8 @@
[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
@@ -21,9 +21,9 @@
{:json-rpc/call [{:method "wakuext_chatPinnedMessages"
:params [chat-id cursor limit]
:on-success (fn [result]
(let [result (clojure.set/rename-keys result
{:pinnedMessages
:pinned-messages})]
(let [result (set/rename-keys result
{:pinnedMessages
:pinned-messages})]
(on-success (update result :pinned-messages #(map <-rpc %)))))
:on-error on-error}]})
+11 -11
View File
@@ -1,24 +1,24 @@
(ns status-im.data-store.reactions
(:require [clojure.set :as clojure.set]))
(: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
@@ -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,18 +1,18 @@
(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]
[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)))
+56 -1
View File
@@ -58,7 +58,8 @@
status-im.wallet.custom-tokens.core
status-im2.contexts.activity-center.events
status-im2.contexts.shell.events
[status-im2.navigation.events :as navigation]))
[status-im2.navigation.events :as navigation]
[react-native.background-timer :as timer]))
(re-frame/reg-fx
:dismiss-keyboard
@@ -324,3 +325,57 @@
{::async-storage/get {:keys keys
:cb #(re-frame/dispatch
[:information-box-states-loaded hashes %])}}))
(rf/defn reset-bottom-sheet
{:events [:bottom-sheet/reset]}
[{:keys [db]}]
{:db (assoc db
:bottom-sheet/config
{:content-height nil
:show-bottom-sheet? nil
:keyboard-was-shown? false
:expanded? false
:gesture-running? false
:animation-delay 450})})
(re-frame/reg-fx
:dismiss-bottom-sheet-fx
(fn [[on-cancel animation-delay]]
(re-frame/dispatch [:bottom-sheet/show-quo2-bottom-sheet false])
(when (fn? on-cancel) (on-cancel))
(timer/set-timeout
(fn []
(re-frame/dispatch [:bottom-sheet/hide-navigation-overlay])
(re-frame/dispatch [:bottom-sheet/reset]))
(or animation-delay 450))))
(rf/defn dismiss-bottom-sheet
{:events [:dismiss-bottom-sheet]}
[{:keys [db]} on-cancel]
(let [animation-delay (get-in db [:bottom-sheet/config :animation-delay])]
{:dismiss-bottom-sheet-fx [on-cancel animation-delay]}))
(rf/defn update-bottom-sheet-height
{:events [:bottom-sheet/update-height]}
[{:keys [db]} height]
{:db (assoc-in db [:bottom-sheet/config :content-height] height)})
(rf/defn show-bottom-sheet
{:events [:bottom-sheet/show-quo2-bottom-sheet]}
[{:keys [db]} value]
{:db (assoc-in db [:bottom-sheet/config :show-bottom-sheet?] value)})
(rf/defn keyboard-was-shown?
{:events [:bottom-sheet/keyboard-was-shown?]}
[{:keys [db]} value]
{:db (assoc-in db [:bottom-sheet/config :keyboard-was-shown?] value)})
(rf/defn bottom-sheet-did-expand
{:events [:bottom-sheet/did-expand]}
[{:keys [db]} value]
{:db (assoc-in db [:bottom-sheet/config :expanded?] value)})
(rf/defn bottom-sheet-gesture-running?
{:events [:bottom-sheet/gesture-running?]}
[{:keys [db]} value]
{:db (assoc-in db [:bottom-sheet/config :gesture-running?] value)})
+7 -2
View File
@@ -14,7 +14,7 @@
{:events [:navigate-chat-updated]}
[cofx chat-id]
(when (get-in cofx [:db :chats chat-id])
(models.chat/navigate-to-chat cofx chat-id)))
(models.chat/navigate-to-chat-nav2 cofx chat-id nil)))
(rf/defn handle-chat-removed
{:events [:chat-removed]}
@@ -71,7 +71,7 @@
(rf/defn create-from-link
[cofx {:keys [chat-id invitation-admin chat-name]}]
(if (get-in cofx [:db :chats chat-id])
{:dispatch [:chat.ui/navigate-to-chat chat-id]}
{:dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]}
{:json-rpc/call [{:method "wakuext_createGroupChatFromInvitation"
:params [chat-name chat-id invitation-admin]
:js-response true
@@ -208,6 +208,11 @@
[{:keys [db]} id]
{:db (update db :group/selected-contacts conj id)})
(rf/defn clear-contacts
{:events [:clear-contacts]}
[{:keys [db]} id]
{:db (assoc db :group/selected-contacts #{})})
(rf/defn deselect-participant
{:events [:deselect-participant]}
[{:keys [db]} id]
+3 -3
View File
@@ -251,7 +251,7 @@
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
(rf-test/wait-for
[:status-im.chat.models/one-to-one-chat-created]
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
(rf/dispatch-sync [:chat.ui/navigate-to-chat-nav2 chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
@@ -276,7 +276,7 @@
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
(rf-test/wait-for
[:status-im.chat.models/one-to-one-chat-created]
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
(rf/dispatch-sync [:chat.ui/navigate-to-chat-nav2 chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(is @(rf/subscribe [:chats/chat chat-id]))
(rf/dispatch-sync [:chat.ui/remove-chat-pressed chat-id])
@@ -307,7 +307,7 @@
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
(rf-test/wait-for
[:status-im.chat.models/one-to-one-chat-created]
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
(rf/dispatch-sync [:chat.ui/navigate-to-chat-nav2 chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(is @(rf/subscribe [:chats/chat chat-id]))
(rf/dispatch-sync [::chat.models/mute-chat-toggled chat-id true])
+4 -2
View File
@@ -9,6 +9,7 @@
[status-im.data-store.chats :as data-store.chats]
[status-im.data-store.invitations :as data-store.invitations]
[status-im.data-store.settings :as data-store.settings]
[status-im.data-store.switcher-cards :as switcher-cards-store]
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip55 :as eip55]
@@ -423,7 +424,7 @@
:key-uid
(fn [stored-key-uid]
(when (= stored-key-uid key-uid)
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])))))))))
(rf/defn check-last-chat
{:events [::check-last-chat]}
@@ -473,7 +474,8 @@
(multiaccounts/get-profile-picture)
(multiaccounts/switch-preview-privacy-mode-flag)
(link-preview/request-link-preview-whitelist)
(visibility-status-updates-store/fetch-visibility-status-updates-rpc))))
(visibility-status-updates-store/fetch-visibility-status-updates-rpc)
(switcher-cards-store/fetch-switcher-cards-rpc))))
(defn get-new-auth-method
[auth-method save-password?]
+51 -1
View File
@@ -5,7 +5,8 @@
[status-im.utils.platform :as platform]
[status-im.utils.react-native :as react-native-utils]
[status-im.utils.types :as types]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[status-im.constants :as constants]))
(defn status
[]
@@ -278,6 +279,55 @@
:connection-string connection-string})
(.inputConnectionStringForBootstrapping ^js (status) connection-string config-json callback))
(defn deserialize-and-compress-key
"Provides a community id (public key) to status-go which is first deserialized
and then compressed. Example input/output :
input key = zQ3shTAten2v9CwyQD1Kc7VXAqNPDcHZAMsfbLHCZEx6nFqk9 and
output key = 0x025596a7ff87da36860a84b0908191ce60a504afc94aac93c1abd774f182967ce6"
[key callback]
(log/info "[native-module] Deserializing and then compressing public key"
{:fn :deserialize-and-compress-key
:key key})
(.deserializeAndCompressKey ^js (status) key callback))
(defn public-key->compressed-key
"Provides public key to status-go and gets back a compressed key via serialization"
[public-key callback]
(let [serialization-key constants/serialization-key
multi-code-prefix constants/multi-code-prefix
multi-code-key (str multi-code-prefix (subs public-key 2))]
(log/info "[native-module] Serializing public key"
{:fn :public-key->compressed-key
:public-key public-key
:multi-code-key multi-code-key})
(.multiformatSerializePublicKey ^js (status) multi-code-key serialization-key callback)))
(defn compressed-key->public-key
"Provides compressed key to status-go and gets back the uncompressed public key via deserialization"
[public-key callback]
(let [deserialization-key constants/deserialization-key]
(log/info "[native-module] Deserializing compressed key"
{:fn :compressed-key->public-key
:public-key public-key})
(.multiformatDeserializePublicKey ^js (status) public-key deserialization-key callback)))
(defn decompress-public-key
"Provides compressed key to status-go and gets back the uncompressed public key"
[public-key callback]
(log/info "[native-module] Decompressing public key"
{:fn :decompress-public-key
:public-key public-key})
(.decompressPublicKey ^js (status) public-key callback))
(defn compress-public-key
"Provides a public key to status-go and gets back a 33bit compressed key back"
[public-key callback]
(log/info "[native-module] Compressing public key"
{:fn :compress-public-key
:public-key public-key})
(.compressPublicKey ^js (status) public-key callback))
(defn hash-typed-data
"used for keycard"
[data callback]
+2 -2
View File
@@ -2,7 +2,7 @@
(:require ["react-native" :as rn]
["react-native-gesture-handler" :refer (gestureHandlerRootHOC)]
["react-native-navigation" :refer (Navigation)]
[clojure.set :as clojure.set]
[clojure.set :as set]
[quo.components.text-input :as quo.text-input]
[quo.design-system.colors :as quo.colors]
[re-frame.core :as re-frame]
@@ -299,7 +299,7 @@
(fn [^js evn]
(let [selected-tab-index (.-selectedTabIndex evn)
comp (get tab-root-ids selected-tab-index)
tab-key (get (clojure.set/map-invert tab-key-idx) selected-tab-index)]
tab-key (get (set/map-invert tab-key-idx) selected-tab-index)]
(re-frame/dispatch [:set :current-tab tab-key])
(when (= @state/root-comp-id comp)
(when (= :chat tab-key)
+2 -1
View File
@@ -63,7 +63,8 @@
:sticker (js/require "../resources/images/mock/sticker.png")
:user-picture-female2 (js/require "../resources/images/mock/user_picture_female2.png")
:user-picture-male4 (js/require "../resources/images/mock/user_picture_male4.png")
:user-picture-male5 (js/require "../resources/images/mock/user_picture_male5.png")})
:user-picture-male5 (js/require "../resources/images/mock/user_picture_male5.png")
:coinbase (js/require "../resources/images/mock/coinbase.png")})
(defn get-theme-image
[k]
+8 -1
View File
@@ -199,6 +199,12 @@
{:type :wallet-account
:account (when account (string/lower-case account))})
(defn community-route-type
[route-params]
(if (string/starts-with? (:community-id route-params) "z")
:desktop-community
:community))
(defn handle-uri
[chain chats uri cb]
(let [{:keys [handler route-params query-params]} (match-uri uri)]
@@ -229,7 +235,8 @@
(cb {:type handler :community-id (:community-id route-params)})
(= handler :community)
(cb {:type handler :community-id (:community-id route-params)})
(cb {:type (community-route-type route-params)
:community-id (:community-id route-params)})
(= handler :community-chat)
(cb {:type handler :chat-id (:chat-id route-params)})
+2 -2
View File
@@ -1,5 +1,5 @@
(ns status-im.signing.core
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as set]
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
@@ -596,4 +596,4 @@
(sign cofx
{:tx-obj (-> tx
(select-keys [:from :to :value :input :gas :nonce :hash])
(clojure.set/rename-keys {:input :data}))})))
(set/rename-keys {:input :data}))})))
+1 -3
View File
@@ -5,9 +5,7 @@
[shadow.test :as st]
[shadow.test.env :as env]
[utils.re-frame :as rf]
[i18n.i18n :as i18n]))
(i18n/init)
status-im2.setup.i18n-resources))
(defonce repl? (atom false))
@@ -5,6 +5,7 @@
(defn build-message
[{:keys [chat-id
album-id
text
response-to
ens-name
@@ -15,6 +16,7 @@
sticker
content-type]}]
{:chatId chat-id
:albumId album-id
:text text
:responseTo response-to
:ensName ens-name
@@ -4,10 +4,11 @@
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im.chat.models :as chat.models]
[i18n.i18n :as i18n]
[status-im.react-native.resources :as resources]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react])
[status-im.ui.components.react :as react]
[status-im2.setup.i18n-resources :as i18n-resources]
[i18n.i18n :as i18n])
(:require-macros [status-im.utils.views :as views]))
(defn- start-chat
@@ -73,8 +74,8 @@
(defn get-language-topic
[]
(let [lang (subs (name i18n/default-device-language) 0 2)
lang3 (subs (name i18n/default-device-language) 0 3)
(let [lang (subs (name i18n-resources/default-device-language) 0 2)
lang3 (subs (name i18n-resources/default-device-language) 0 3)
lang-name (or (get lang-names lang3) (get lang-names lang))]
(when-not (= lang "en")
(or lang-name (str "status-" lang)))))
@@ -14,8 +14,7 @@
transactions-management-enabled?
wakuv2-flag
current-fleet
webview-debug
mutual-contact-requests-enabled?]}]
webview-debug]}]
(keep
identity
[{:size :small
@@ -115,17 +114,7 @@
#(re-frame/dispatch
[:multiaccounts.ui/waku-bloom-filter-mode-switched (not waku-bloom-filter-mode)])
:accessory :switch
:active waku-bloom-filter-mode}
{:size :small
:title (i18n/label :t/mutual-contact-requests)
:accessibility-label :mutual-contact-requests-switch
:container-margin-bottom 8
:on-press
#(re-frame/dispatch
[:multiaccounts.ui/switch-mutual-contact-requests-enabled
(not mutual-contact-requests-enabled?)])
:accessory :switch
:active mutual-contact-requests-enabled?}]))
:active waku-bloom-filter-mode}]))
(defn- flat-list-data
[options]
@@ -146,8 +135,7 @@
communities-enabled? [:communities/enabled?]
transactions-management-enabled? [:wallet/transactions-management-enabled?]
current-log-level [:log-level/current-log-level]
current-fleet [:fleets/current-fleet]
mutual-contact-requests-enabled? [:mutual-contact-requests/enabled?]]
current-fleet [:fleets/current-fleet]]
[list/flat-list
{:data (flat-list-data
{:network-name network-name
@@ -158,7 +146,6 @@
:dev-mode? false
:wakuv2-flag wakuv2-flag
:waku-bloom-filter-mode waku-bloom-filter-mode
:webview-debug webview-debug
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?})
:webview-debug webview-debug})
:key-fn (fn [_ i] (str i))
:render-fn render-item}]))
@@ -7,11 +7,17 @@
[status-im.ui.screens.multiaccounts.key-storage.views :as key-storage]
[status-im.ui.screens.multiaccounts.recover.views :as recover.views]
[status-im2.common.bottom-sheet.view :as bottom-sheet]
[status-im2.contexts.chat.messages.pin.list.view :as pin.list]))
[status-im2.contexts.chat.messages.pin.list.view :as pin.list]
[reagent.core :as reagent]
[status-im2.contexts.chat.messages.drawers.view :as drawers]
[status-im.ui.components.react :as react]
[status-im.ui.screens.multiaccounts.sheets :as multiaccounts-sheet]))
(defn bottom-sheet
[]
(let [{:keys [show? view options]} @(re-frame/subscribe [:bottom-sheet])
(let [dismiss-bottom-sheet-callback #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
{:keys [show-bottom-sheet?]} @(re-frame/subscribe [:bottom-sheet/config])
{:keys [show? view options]} @(re-frame/subscribe [:bottom-sheet])
{:keys [content]
:as opts}
(cond-> {:visible? show?}
@@ -46,7 +52,22 @@
(merge key-storage/migrate-account-password)
(= view :pinned-messages-list)
(merge {:content pin.list/pinned-messages-list}))]
[bottom-sheet/bottom-sheet opts
(when content
[content (when options options)])]))
(merge {:content pin.list/pinned-messages-list})
(= view :drawer/reactions)
(merge {:content drawers/reactions})
(= view :generate-a-new-key)
(merge {:content multiaccounts-sheet/actions-sheet}))]
(reagent/create-class
{:reagent-render (fn []
[bottom-sheet/bottom-sheet
opts
(when content
[content (when options options)])])
:component-did-mount (fn []
(react/hw-back-add-listener dismiss-bottom-sheet-callback))
:component-will-unmount (fn []
(react/hw-back-remove-listener dismiss-bottom-sheet-callback)
(when show-bottom-sheet?
(re-frame/dispatch [:bottom-sheet/reset])))})))
+58 -61
View File
@@ -6,7 +6,7 @@
[quo.design-system.colors :as colors]
[quo.react :as quo.react]
[quo.react-native :as rn]
[re-frame.core :as re-frame]
[re-frame.core :as rf]
re-frame.db
[reagent.core :as reagent]
[status-im.constants :as constants]
@@ -42,13 +42,13 @@
(defn invitation-requests
[chat-id admins]
(let [current-pk @(re-frame/subscribe [:multiaccount/public-key])
(let [current-pk @(rf/subscribe [:multiaccount/public-key])
admin? (get admins current-pk)]
(when admin?
(let [invitations @(re-frame/subscribe [:group-chat/pending-invitations-by-chat-id chat-id])]
(let [invitations @(rf/subscribe [:group-chat/pending-invitations-by-chat-id chat-id])]
(when (seq invitations)
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:navigate-to :group-chat-invite])
{:on-press #(rf/dispatch [:navigate-to :group-chat-invite])
:accessibility-label :invitation-requests-button}
[react/view {:style (style/add-contact)}
[react/text {:style style/add-contact-text}
@@ -56,11 +56,11 @@
(defn add-contact-bar
[public-key]
(when-not (or @(re-frame/subscribe [:contacts/contact-added? public-key])
@(re-frame/subscribe [:contacts/contact-blocked? public-key]))
(when-not (or @(rf/subscribe [:contacts/contact-added? public-key])
@(rf/subscribe [:contacts/contact-blocked? public-key]))
[react/touchable-highlight
{:on-press
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
#(rf/dispatch [:contact.ui/add-to-contact-pressed public-key])
:accessibility-label :add-to-contacts-button}
[react/view {:style (style/add-contact)}
[icons/icon :main-icons/add
@@ -69,7 +69,7 @@
(defn contact-request
[]
(let [contact-request @(re-frame/subscribe [:chats/sending-contact-request])]
(let [contact-request @(rf/subscribe [:chats/sending-contact-request])]
[react/view {:style style/contact-request}
[react/image
{:source (resources/get-image :hand-wave)
@@ -92,7 +92,7 @@
[quo/button
{:style {:width "100%"}
:accessibility-label :contact-request--button
:on-press #(re-frame/dispatch [:chat.ui/send-contact-request])}
:on-press #(rf/dispatch [:chat.ui/send-contact-request])}
(i18n/label :t/contact-request)]])]))
(defn chat-intro
@@ -101,7 +101,6 @@
chat-type
group-chat
invitation-admin
mutual-contact-requests-enabled?
contact-name
color
loading-messages?
@@ -136,25 +135,23 @@
:no-messages? no-messages?}]
[react/text {:style (assoc style/intro-header-description :margin-bottom 32)}
(str (i18n/label :t/empty-chat-description-one-to-one) contact-name)])
(when (and mutual-contact-requests-enabled?
(= chat-type constants/one-to-one-chat-type)
(or (= contact-request-state constants/contact-request-state-none)
(= contact-request-state constants/contact-request-state-received)
(= contact-request-state constants/contact-request-state-dismissed)))
[contact-request])])
(when
(= chat-type constants/one-to-one-chat-type)
(or (= contact-request-state constants/contact-request-state-none)
(= contact-request-state constants/contact-request-state-received)
(= contact-request-state constants/contact-request-state-dismissed)))
[contact-request]])
(defn chat-intro-one-to-one
[{:keys [chat-id] :as opts}]
(let [contact @(re-frame/subscribe [:contacts/contact-by-identity chat-id])
mutual-contact-requests-enabled? @(re-frame/subscribe [:mutual-contact-requests/enabled?])
contact-names @(re-frame/subscribe [:contacts/contact-two-names-by-identity
chat-id])]
(let [contact @(rf/subscribe [:contacts/contact-by-identity chat-id])
contact-names @(rf/subscribe [:contacts/contact-two-names-by-identity
chat-id])]
[chat-intro
(assoc opts
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?
:contact-name (first contact-names)
:contact-request-state (or (:contact-request-state contact)
constants/contact-request-state-none))]))
:contact-name (first contact-names)
:contact-request-state (or (:contact-request-state contact)
constants/contact-request-state-none))]))
(defn chat-intro-header-container
[{:keys [group-chat invitation-admin
@@ -217,8 +214,8 @@
(defn invitation-bar
[chat-id]
(let [{:keys [state chat-id] :as invitation}
(first @(re-frame/subscribe [:group-chat/invitations-by-chat-id chat-id]))
{:keys [retry? message]} @(re-frame/subscribe [:chats/current-chat-membership])
(first @(rf/subscribe [:group-chat/invitations-by-chat-id chat-id]))
{:keys [retry? message]} @(rf/subscribe [:chats/current-chat-membership])
message-length (count message)]
[react/view {:margin-horizontal 16 :margin-top 10}
(cond
@@ -238,13 +235,13 @@
[quo/button
{:type :secondary
:accessibility-label :retry-button
:on-press #(re-frame/dispatch [:group-chats.ui/membership-retry])}
:on-press #(rf/dispatch [:group-chats.ui/membership-retry])}
(i18n/label :t/mailserver-retry)]
:left
[quo/button
{:type :secondary
:accessibility-label :remove-group-button
:on-press #(re-frame/dispatch [:group-chats.ui/remove-chat-confirmed chat-id])}
:on-press #(rf/dispatch [:group-chats.ui/remove-chat-confirmed chat-id])}
(i18n/label :t/remove-group)]}]
:else
[toolbar/toolbar
@@ -255,7 +252,7 @@
:accessibility-label :introduce-yourself-button
:disabled (or (string/blank? message)
(> message-length chat.group/message-max-length))
:on-press #(re-frame/dispatch [:send-group-chat-membership-request])}
:on-press #(rf/dispatch [:send-group-chat-membership-request])}
(i18n/label :t/request-membership)]}])]))
(defn get-space-keeper-ios
@@ -289,9 +286,9 @@
(defn list-footer
[{:keys [chat-id] :as chat}]
(let [loading-messages? @(re-frame/subscribe [:chats/loading-messages? chat-id])
no-messages? @(re-frame/subscribe [:chats/chat-no-messages? chat-id])
all-loaded? @(re-frame/subscribe [:chats/all-loaded? chat-id])]
(let [loading-messages? @(rf/subscribe [:chats/loading-messages? chat-id])
no-messages? @(rf/subscribe [:chats/chat-no-messages? chat-id])
all-loaded? @(rf/subscribe [:chats/all-loaded? chat-id])]
[react/view {:style (when platform/android? {:scaleY -1})}
(if (or loading-messages? (not chat-id) (not all-loaded?))
[react/view {:height 324 :align-items :center :justify-content :center}
@@ -340,15 +337,15 @@
(defn list-on-end-reached
[]
(if @state/scrolling
(re-frame/dispatch [:chat.ui/load-more-messages-for-current-chat])
(utils/set-timeout #(re-frame/dispatch [:chat.ui/load-more-messages-for-current-chat])
(rf/dispatch [:chat.ui/load-more-messages-for-current-chat])
(utils/set-timeout #(rf/dispatch [:chat.ui/load-more-messages-for-current-chat])
(if platform/low-device? 700 200))))
(defn get-render-data
[{:keys [group-chat chat-id public? community-id admins space-keeper show-input? edit-enabled
in-pinned-view?]}]
(let [current-public-key @(re-frame/subscribe [:multiaccount/public-key])
community @(re-frame/subscribe [:communities/community community-id])
(let [current-public-key @(rf/subscribe [:multiaccount/public-key])
community @(rf/subscribe [:communities/community community-id])
group-admin? (get admins current-public-key)
community-admin? (when community (community :admin))
message-pin-enabled (and (not public?)
@@ -371,17 +368,15 @@
[{:keys [chat
bottom-space
pan-responder
mutual-contact-requests-enabled?
space-keeper
show-input?]}]
(let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat
messages @(re-frame/subscribe [:chats/raw-chat-messages-stream chat-id])
messages @(rf/subscribe [:chats/raw-chat-messages-stream chat-id])
one-to-one? (= chat-type constants/one-to-one-chat-type)
contact-added? (when one-to-one? @(re-frame/subscribe [:contacts/contact-added? chat-id]))
contact-added? (when one-to-one? @(rf/subscribe [:contacts/contact-added? chat-id]))
should-send-contact-request?
(and
mutual-contact-requests-enabled?
one-to-one?
(not contact-added?))]
@@ -423,13 +418,13 @@
[]
(when (and (not @navigation.state/curr-modal) (= (get @re-frame.db/app-db :view-id) :chat))
(react/hw-back-remove-listener navigate-back-handler)
(re-frame/dispatch [:close-chat])
(re-frame/dispatch [:navigate-back])))
(rf/dispatch [:close-chat])
(rf/dispatch [:navigate-back])))
(defn topbar-content
[]
(let [window-width @(re-frame/subscribe [:dimensions/window-width])
{:keys [group-chat chat-id] :as chat-info} @(re-frame/subscribe [:chats/current-chat])]
(let [window-width @(rf/subscribe [:dimensions/window-width])
{:keys [group-chat chat-id] :as chat-info} @(rf/subscribe [:chats/current-chat])]
[react/touchable-highlight
{:on-press #(when-not group-chat
(debounce/dispatch-and-chill [:chat.ui/show-profile chat-id] 1000))
@@ -452,9 +447,9 @@
[react/view {:flex 1 :left 52 :right 52 :top 0 :bottom 0 :position :absolute}
[topbar-content]]
[react/touchable-highlight
{:on-press-in #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/current-chat-actions])
:height 256}])
{:on-press-in #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/current-chat-actions])
:height 256}])
:accessibility-label :chat-menu-button
:style {:right 0
:top 0
@@ -481,26 +476,28 @@
set-active-panel (get-set-active-panel active-panel)
on-close #(set-active-panel nil)]
(fn []
(let [{:keys [chat-id show-input? group-chat admins invitation-admin] :as chat}
;;we want to react only on these fields, do not use full chat map here
@(re-frame/subscribe [:chats/current-chat-chat-view])
mutual-contact-requests-enabled? @(re-frame/subscribe [:mutual-contact-requests/enabled?])
max-bottom-space (max @bottom-space @panel-space)]
(let [{:keys [chat-id
show-input?
group-chat
admins
invitation-admin]
:as chat}
@(rf/subscribe [:chats/current-chat-chat-view])
max-bottom-space (max @bottom-space
@panel-space)]
[:<>
[topbar]
[connectivity/loading-indicator]
(when chat-id
(if group-chat
[invitation-requests chat-id admins]
(when-not mutual-contact-requests-enabled? [add-contact-bar chat-id])))
(when group-chat
[invitation-requests chat-id admins]))
;;MESSAGES LIST
[messages-view
{:chat chat
:bottom-space max-bottom-space
:pan-responder pan-responder
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?
:space-keeper space-keeper
:show-input? show-input?}]
{:chat chat
:bottom-space max-bottom-space
:pan-responder pan-responder
:space-keeper space-keeper
:show-input? show-input?}]
(when (and group-chat invitation-admin)
[accessory/view
{:y position-y
@@ -1,5 +1,5 @@
(ns status-im.ui.screens.communities.reorder-categories
(:require [clojure.set :as clojure.set]
(:require [clojure.set :as set]
[clojure.string :as string]
[clojure.walk :as walk]
[quo.core :as quo]
@@ -48,7 +48,7 @@
[{:keys [id community-id] :as home-item} is-active? drag]
(let [chat-id (string/replace id community-id "")
background-color (if is-active? colors/gray-lighter colors/white)
home-item (clojure.set/rename-keys home-item {:id :chat-id})]
home-item (set/rename-keys home-item {:id :chat-id})]
[rn/view
{:accessibility-label :chat-item
:style (merge styles/category-item
@@ -48,7 +48,7 @@
:on-press (fn []
(rf/dispatch [:communities/load-category-states id])
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community {:community-id id}]))
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[community/community-actions community])}])}
@@ -111,7 +111,7 @@
(i18n/label :t/open-membership))]]
:on-press #(do
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community {:community-id id}]))}]))
(rf/dispatch [:navigate-to-nav2 :community {:community-id id}]))}]))
(defn communities-actions
[]
+53 -38
View File
@@ -1,19 +1,21 @@
(ns status-im.ui.screens.home.sheet.views
(:require [quo.core :as quo]
(:require [i18n.i18n :as i18n]
[quo.core :as quo]
[quo2.core :as quo2]
[quo2.foundations.colors :as colors]
[re-frame.core :as rf]
[i18n.i18n :as i18n]
[re-frame.core :as re-frame]
[react-native.background-timer :as timer]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.ui.components.invite.views :as invite]
[status-im.ui.components.react :as rn]
[status-im.ui.screens.home.sheet.styles :as style]
[status-im.ui2.screens.chat.components.new-chat.view :as new-chat-aio]
[status-im.utils.config :as config]
[quo2.core :as quo2]
[status-im.ui.screens.home.sheet.styles :as style]))
[utils.re-frame :as rf]))
(defn hide-sheet-and-dispatch
(defn- hide-sheet-and-dispatch
[event]
(rf/dispatch [:bottom-sheet/hide])
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(rf/dispatch event))
(defn add-new-view
@@ -28,7 +30,7 @@
{:type :icon
:theme :icon
:accessibility-label :universal-qr-scanner
:on-press #(hide-sheet-and-dispatch
:on-press #(rf/dispatch
[::qr-scanner/scan-code
{:handler ::qr-scanner/on-scan-success}])}
:main-icons/qr]]
@@ -51,46 +53,59 @@
:accessibility-label :join-public-chat-button
:icon :main-icons/public-chat
:on-press #(hide-sheet-and-dispatch [:open-modal :new-public-chat])}]
(when @(rf/subscribe [:communities/enabled?])
(when (rf/sub [:communities/enabled?])
[quo/list-item
{:theme :accent
:title (i18n/label :t/communities-alpha)
:accessibility-label :communities-button
:icon :main-icons/communities
:on-press #(hide-sheet-and-dispatch [:navigate-to :communities])}])
:on-press #(rf/dispatch [:navigate-to :communities])}])
[invite/list-item
{:accessibility-label :chats-menu-invite-friends-button}]])
(defn new-chat-bottom-sheet
[]
[rn/view
[quo2/menu-item
{:theme :main
:title (i18n/label :t/new-chat)
:icon-bg-color :transparent
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :start-a-new-chat
:icon :i/new-message
:on-press #(hide-sheet-and-dispatch [:bottom-sheet/show-sheet
:start-a-new-chat])}]
[quo2/menu-item
{:theme :main
:title (i18n/label :t/add-a-contact)
:icon-bg-color :transparent
:icon-container-style {:padding-horizontal 0}
:container-padding-horizontal {:padding-horizontal 4}
:style-props {:margin-top 18
:margin-bottom 9}
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :add-a-contact
:subtitle (i18n/label :t/enter-a-chat-key)
:subtitle-color colors/neutral-50
:icon :i/add-user
:on-press #(hide-sheet-and-dispatch [:open-modal :new-contact])}]])
(let [{:keys [animation-delay]} (rf/sub [:bottom-sheet/config])]
[rn/view
[quo2/menu-item
{:theme :main
:title (i18n/label :t/new-chat)
:icon-bg-color :transparent
:type :transparent
:container-padding-vertical 12
:style-props {:border-bottom-width 1
:border-color (colors/theme-colors colors/neutral-10
colors/neutral-90)}
:title-column-style {:margin-left 2}
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :start-a-new-chat
:icon :i/new-message
:on-press (fn []
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(timer/set-timeout
#(rf/dispatch [:bottom-sheet/show-sheet :start-a-new-chat])
(or animation-delay 450)))}]
[quo2/menu-item
{:theme :main
:title (i18n/label :t/connect-with-users)
:icon-bg-color :transparent
:type :transparent
:icon-container-style {:padding-horizontal 0}
:container-padding-horizontal {:padding-horizontal 4}
:style-props {:margin-top 18
:margin-bottom 9}
:container-padding-vertical 12
:title-column-style {:margin-left 2}
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :connect-with-users
:subtitle (i18n/label :t/enter-a-chat-key)
:subtitle-color colors/neutral-50
:icon :i/add-user
:on-press (fn []
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(timer/set-timeout
#(rf/dispatch [:open-modal :new-contact])
(or animation-delay 450)))}]]))
(def new-chat-bottom-sheet-comp
+2 -7
View File
@@ -27,7 +27,6 @@
[status-im.ui.screens.home.styles :as styles]
[status-im.ui.screens.home.views.inner-item :as inner-item]
[status-im.utils.utils :as utils]
[status-im2.setup.config :as config]
[utils.debounce :as debounce])
(:require-macros [status-im.utils.views :as views]))
@@ -152,9 +151,7 @@
home-item
{:on-press (fn []
(re-frame/dispatch [:dismiss-keyboard])
(if config/new-ui-enabled?
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]))
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(re-frame/dispatch [:search/home-filter-changed nil]))
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
@@ -169,9 +166,7 @@
home-item
{:on-press (fn []
(re-frame/dispatch [:dismiss-keyboard])
(if config/new-ui-enabled?
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]))
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(re-frame/dispatch [:search/home-filter-changed nil]))
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
@@ -1,14 +1,19 @@
(ns status-im.ui.screens.multiaccounts.sheets
(:require [quo.core :as quo]
[re-frame.core :as re-frame]
[i18n.i18n :as i18n]))
[i18n.i18n :as i18n]
status-im2.common.bottom-sheet.view))
(defn- hide-sheet-and-dispatch
[event]
(re-frame/dispatch [:dismiss-bottom-sheet])
(re-frame/dispatch event))
(defn actions-sheet
[]
[quo/list-item
{:theme :accent
:on-press #(do (re-frame/dispatch [:bottom-sheet/hide])
(re-frame/dispatch [:generate-and-derive-addresses]))
:on-press #(hide-sheet-and-dispatch [:generate-and-derive-addresses])
:icon :main-icons/add
:accessibility-label :generate-a-new-key
:title (i18n/label :t/generate-a-new-key)}])
@@ -10,7 +10,6 @@
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.multiaccounts.sheets :as sheets]
[status-im.ui.screens.multiaccounts.styles :as styles]
[utils.security.core :as security]))
@@ -41,8 +40,7 @@
(defn topbar-button
[]
(re-frame/dispatch [:bottom-sheet/show-sheet
{:content sheets/actions-sheet}]))
(re-frame/dispatch [:bottom-sheet/show-sheet :generate-a-new-key {}]))
(defview multiaccounts
[]
@@ -1,4 +1,5 @@
(ns status-im.ui2.screens.chat.components.new-chat.styles)
(def contact-selection-heading
{:style {:flex-direction :row
:justify-content :space-between
@@ -13,4 +14,9 @@
:margin-left 20
:margin-bottom 36
:justify-content :center
:align-items :center})
:align-items :center})
(defn chat-button
[{:keys [bottom]}]
{:position :absolute
:bottom (- bottom 50)})
@@ -8,12 +8,19 @@
[i18n.i18n :as i18n]
[status-im.ui.components.react :as react]
[utils.re-frame :as rf]
[status-im.ui.screens.chat.sheets :refer [hide-sheet-and-dispatch]]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui2.screens.common.contact-list.view :as contact-list]
[quo2.components.markdown.text :as text]
[status-im.ui.components.invite.events :as invite.events]
[status-im.ui2.screens.chat.components.new-chat.styles :as style]))
[status-im.ui2.screens.chat.components.new-chat.styles :as style]
status-im2.common.bottom-sheet.view
[quo.react :as quo.react]
[quo.components.safe-area :as safe-area]))
(defn- hide-sheet-and-dispatch
[event]
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(rf/dispatch event))
(defn- on-toggle
[allow-new-users? checked? public-key]
@@ -39,81 +46,87 @@
:size :paragraph-1
:style {:margin-bottom 2
:margin-top 20}}
"You have no contacts"]
(i18n/label :t/you-have-no-contacts)]
[text/text
{:weight :regular
:size :label
:style {:margin-bottom 20}}
"Invite your friends and family to Status"]
(i18n/label :t/invite-friends-and-family)]
[quo2/button
{:type :primary
:style {:margin-bottom 12}
:on-press #(rf/dispatch [::invite.events/share-link nil])}
"Invite friends"]
(i18n/label :t/invite-friends)]
[quo2/button
{:type :grey
:on-press #(hide-sheet-and-dispatch [:open-modal :new-contact])}
"Add a contact"]])
(i18n/label :t/add-a-contact)]])
(defn contact-selection-list
[]
(let [contacts (rf/sub
[:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
window-height (rf/sub [:dimensions/window-height])
one-contact-selected? (= selected-contacts-count 1)
contacts-selected? (pos? selected-contacts-count)
{:keys [names public-key]} (-> contacts first :data first)
added? (reagent/atom '())
{:keys [nickname ens-name three-words-name]} names
first-username (or ens-name nickname three-words-name)
no-contacts? (empty? contacts)]
[react/view {:style {:height (* window-height 0.95)}}
[quo2/button
{:type :grey
:icon true
:on-press #(rf/dispatch [:bottom-sheet/hide])
:style style/contact-selection-close
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
quo2.colors/neutral-90)}
:i/close]
[react/view style/contact-selection-heading
[quo2/text
{:weight :semi-bold
:size :heading-1
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}}
(i18n/label :t/new-chat)]
(when-not no-contacts?
[quo2/text
{:size :paragraph-2
:weight :regular
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)}}
(i18n/label :t/selected-count-from-max
{:selected (inc selected-contacts-count)
:max constants/max-group-chat-participants})])]
[react/view
{:style {:height 430
:margin-bottom -20}}
(if no-contacts?
[no-contacts-view]
[contact-list/contact-list
{:icon :check
:group nil
:added? added?
:search? false
:start-a-new-chat? true
:on-toggle on-toggle}])]
(when contacts-selected?
[toolbar/toolbar
{:show-border? false
:center [button/button
{:type :primary
:accessibility-label :next-button
:on-press #(do
(if one-contact-selected?
(hide-sheet-and-dispatch [:chat.ui/start-chat
public-key])
(hide-sheet-and-dispatch [:navigate-to :new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user first-username})
(i18n/label :t/setup-group-chat))]}])]))
[:f>
(fn []
(quo.react/effect! #(rf/dispatch [:clear-contacts]) [])
(let [contacts (rf/sub
[:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
window-height (rf/sub [:dimensions/window-height])
one-contact-selected? (= selected-contacts-count 1)
contacts-selected? (pos? selected-contacts-count)
{:keys [names public-key]} (-> contacts first :data first)
added? (reagent/atom '())
{:keys [nickname ens-name three-words-name]} names
first-username (or ens-name nickname three-words-name)
no-contacts? (empty? contacts)
safe-area (safe-area/use-safe-area)]
[react/view {:style {:height (* window-height 0.9)}}
[quo2/button
{:type :grey
:icon true
:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])
:style style/contact-selection-close
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
quo2.colors/neutral-90)}
:i/close]
[react/view style/contact-selection-heading
[quo2/text
{:weight :semi-bold
:size :heading-1
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-100 quo2.colors/white)}}
(i18n/label :t/new-chat)]
(when-not no-contacts?
[quo2/text
{:size :paragraph-2
:weight :regular
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)}}
(i18n/label :t/selected-count-from-max
{:selected (inc selected-contacts-count)
:max constants/max-group-chat-participants})])]
[react/view
{:style {:height 430
:margin-bottom -20}}
(if no-contacts?
[no-contacts-view]
[contact-list/contact-list
{:icon :check
:group nil
:added? added?
:search? false
:start-a-new-chat? true
:on-toggle on-toggle}])]
(when contacts-selected?
[toolbar/toolbar
{:show-border? false
:center [button/button
{:type :primary
:accessibility-label :next-button
:style (style/chat-button safe-area)
:on-press #(do
(if one-contact-selected?
(hide-sheet-and-dispatch [:chat.ui/start-chat
public-key])
(hide-sheet-and-dispatch [:navigate-to
:new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user first-username})
(i18n/label :t/setup-group-chat))]}])]))])
@@ -64,14 +64,9 @@
(i18n/label :t/message-deleted)]])
(defn reply-message
[{:keys [chat-id id]}
[{:keys [from identicon content-type contentType parsed-text content deleted? deleted-for-me?]}
in-chat-input? pin?]
(let [reply-content-sub (-> [:chats/chat-messages chat-id]
rf/sub
(get id))
{:keys [from identicon content-type contentType parsed-text content deleted? deleted-for-me?]}
reply-content-sub
contact-name (rf/sub [:contacts/contact-name-by-identity from])
(let [contact-name (rf/sub [:contacts/contact-name-by-identity from])
current-public-key (rf/sub [:multiaccount/public-key])
content-type (or content-type contentType)]
[rn/view
@@ -164,7 +164,7 @@
:dy 0 ;used for gesture
:pdy 0 ;used for gesture
:state :min ;:min, :custom-chat-available,
;:custom-chat-unavailable, :max
;:custom-chat-unavailable, :max
:clear false
:minimized-from-handlebar? false})
keyboard-was-shown? (atom false)
@@ -188,19 +188,19 @@
360)
(:top insets)
(:status-bar-height @navigation-const)) ; 360
; -
; default
; height
; -
; default
; height
max-height (Math/abs (- max-y 56 (:bottom insets))) ; 56
; -
; top-bar
; height
; -
; top-bar
; height
added-value (if (and (not (seq suggestions))
(or edit reply))
38
0) ; increased height
; of input box
; needed when reply
; of input box
; needed when reply
min-y (+ min-y (when (or edit reply) 38))
bg-opacity (reanimated/use-shared-value 0)
bg-bottom (reanimated/use-shared-value (-
@@ -450,7 +450,7 @@
[quo/text
{:style {:margin-top 6}
:weight :bold
:size :large}
:size :heading-2}
(i18n/label :t/contact-request)]
[rn/view {:style {:padding-horizontal 16}}
[quo/text
@@ -3,9 +3,8 @@
(defn pin-popover
[width]
{:position :absolute
:width (- width 16)
:left 8
{:width (- width 16)
:margin-left 8
:background-color (colors/theme-colors colors/neutral-80-opa-90 colors/white-opa-90)
:flex-direction :row
:border-radius 16
@@ -5,7 +5,7 @@
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im.ui2.screens.chat.pin-limit-popover.style :as style] ;; TODO move to status-im2
[status-im.ui2.screens.chat.pin-limit-popover.style :as style]
[utils.re-frame :as rf]))
;; TODO (flexsurfer) this should be an in-app notification component in quo2
@@ -24,38 +24,41 @@
(reanimated/with-timing (if show-pin-limit-modal? 1 0)))
(reanimated/set-shared-value z-index-animation
(reanimated/with-timing (if show-pin-limit-modal? 10 -1)))))
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity opacity-animation
:z-index z-index-animation}
(style/pin-popover width))
:accessibility-label :pin-limit-popover}
[rn/view {:style (style/pin-alert-container)}
[rn/view {:style style/pin-alert-circle}
[rn/text {:style {:color colors/danger-50}} "!"]]]
[rn/view {:style {:margin-left 8}}
[quo/text {:weight :semi-bold :color (colors/theme-colors colors/white colors/neutral-100)}
(i18n/label :t/cannot-pin-title)]
[quo/text {:size :paragraph-2 :color (colors/theme-colors colors/white colors/neutral-100)}
(i18n/label :t/cannot-pin-desc)]
[rn/touchable-opacity
{:accessibility-label :view-pinned-messages
:active-opacity 1
:on-press (fn []
(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id]))
:style style/view-pinned-messages}
[quo/text {:size :paragraph-2 :weight :medium :color colors/white}
(i18n/label :t/view-pinned-messages)]]]
[rn/touchable-opacity
{:accessibility-label :close-pin-limit-popover
:active-opacity 1
:on-press #(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
:style {:position :absolute
:top 16
:right 16}}
[quo/icon :i/close
{:color (colors/theme-colors colors/white colors/neutral-100)
:size 8}]]]))])
(when show-pin-limit-modal?
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:opacity opacity-animation
:z-index z-index-animation}
(style/pin-popover width))
:accessibility-label :pin-limit-popover}
[rn/view {:style (style/pin-alert-container)}
[rn/view {:style style/pin-alert-circle}
[rn/text {:style {:color colors/danger-50}} "!"]]]
[rn/view {:style {:margin-left 8}}
[quo/text {:weight :semi-bold :color (colors/theme-colors colors/white colors/neutral-100)}
(i18n/label :t/cannot-pin-title)]
[quo/text {:size :paragraph-2 :color (colors/theme-colors colors/white colors/neutral-100)}
(i18n/label :t/cannot-pin-desc)]
[rn/touchable-opacity
{:accessibility-label :view-pinned-messages
:active-opacity 1
:on-press (fn []
(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list
chat-id])
(rf/dispatch [:dismiss-keyboard]))
:style style/view-pinned-messages}
[quo/text {:size :paragraph-2 :weight :medium :color colors/white}
(i18n/label :t/view-pinned-messages)]]]
[rn/touchable-opacity
{:accessibility-label :close-pin-limit-popover
:active-opacity 1
:on-press #(rf/dispatch [:pin-message/hide-pin-limit-modal chat-id])
:style {:position :absolute
:top 16
:right 16}}
[quo/icon :i/close
{:color (colors/theme-colors colors/white colors/neutral-100)
:size 12}]]])))])
@@ -1,36 +0,0 @@
(ns status-im.ui2.screens.chat.pinned-banner.view
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
;; TODO (flexsurfer) this should be a banner component in quo2
;; https://github.com/status-im/status-mobile/issues/14528
(defn pinned-banner
[{:keys [latest-pin-text pins-count on-press]}]
[rn/touchable-opacity
{:accessibility-label :pinned-banner
:style {:height 50
:background-color colors/primary-50-opa-20
:flex-direction :row
:align-items :center
:padding-horizontal 20
:padding-vertical 10}
:active-opacity 1
:on-press on-press}
[quo/icon :i/pin {:size 20}]
[quo/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 {:position :absolute
:right 22
:height 20
:width 20
:border-radius 8
:justify-content :center
:align-items :center
:background-color colors/neutral-80-opa-5}}
[quo/text {:size :label :weight :medium} pins-count]]])
@@ -9,10 +9,12 @@
[quo/divider-label {:label title}])
(defn contact-list
[data]
(let [contacts (if (:group data)
(rf/sub [:contacts/add-members-sections])
(rf/sub [:contacts/filtered-active-sections]))]
[{:keys [start-a-new-chat?] :as data}]
(let [contacts (if start-a-new-chat?
(rf/sub [:contacts/sorted-and-grouped-by-first-letter])
(if (:group data)
(rf/sub [:contacts/grouped-by-first-letter])
(rf/sub [:contacts/filtered-active-sections])))]
[rn/section-list
{:key-fn :title
:sticky-section-headers-enabled false
+19 -3
View File
@@ -14,7 +14,8 @@
[utils.re-frame :as rf]
[status-im.wallet.choose-recipient.core :as choose-recipient]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[status-im.native-module.core :as status]))
;; TODO(yenda) investigate why `handle-universal-link` event is
;; dispatched 7 times for the same link
@@ -76,12 +77,26 @@
(rf/defn handle-community
[cofx {:keys [community-id]}]
(log/info "universal-links: handling community" community-id)
(navigation/navigate-to-cofx cofx :community {:community-id community-id}))
(navigation/navigate-to-cofx cofx :community {:community-id community-id})
)
(rf/defn handle-navigation-to-desktop-community-from-mobile
{:events [:handle-navigation-to-desktop-community-from-mobile]}
[{:keys [db]} cofx deserialized-key]
(navigation/navigate-to-cofx cofx :community {:community-id deserialized-key})
)
(rf/defn handle-desktop-community
[cofx {:keys [community-id]}]
(status/deserialize-and-compress-key
community-id
(fn [deserialized-key]
(rf/dispatch [:handle-navigation-to-desktop-community-from-mobile cofx (str deserialized-key)]))))
(rf/defn handle-community-chat
[cofx {:keys [chat-id]}]
(log/info "universal-links: handling community chat" chat-id)
{:dispatch [:chat.ui/navigate-to-chat chat-id]})
{:dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]})
(rf/defn handle-public-chat
[cofx {:keys [topic]}]
@@ -145,6 +160,7 @@
:private-chat (handle-private-chat cofx data)
:community-requests (handle-community-requests cofx data)
:community (handle-community cofx data)
:desktop-community (handle-desktop-community cofx data)
:community-chat (handle-community-chat cofx data)
:contact (handle-view-profile cofx data)
:browser (handle-browse cofx data)
+4 -4
View File
@@ -1,5 +1,5 @@
(ns status-im.utils.views
(:require [clojure.walk :as w]))
(:require [clojure.walk :as walk]))
(defn atom?
[sub]
@@ -9,9 +9,9 @@
(defn walk-sub
[sub form->sym]
(if (coll? sub)
(w/postwalk (fn [f]
(or (form->sym f) f))
sub)
(walk/postwalk (fn [f]
(or (form->sym f) f))
sub)
(or (form->sym sub) sub)))
(defn prepare-subs
+2 -2
View File
@@ -1,6 +1,6 @@
(ns status-im.wallet.core
(:require
[clojure.set :as clojure.set]
[clojure.set :as set]
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.async-storage.core :as async-storage]
@@ -360,7 +360,7 @@
(rf/merge cofx
(multiaccounts.update/multiaccount-update
:wallet/visible-tokens
(update visible-tokens chain clojure.set/union chain-visible-tokens)
(update visible-tokens chain set/union chain-visible-tokens)
{})
(update-tokens-balances balances)
(prices/update-prices))))
+29 -8
View File
@@ -22,14 +22,35 @@
:top 0
:background-color colors/neutral-100})
(def container
{:position :absolute
:left 0
:right 0
:top 0
:bottom 0
:overflow :hidden})
(defn content-style
[insets]
{:position :absolute
:left 0
:right 0
:top 0
:padding-top border-radius
:padding-bottom (:bottom insets)})
(defn selected-background
[]
{:border-radius 12
:padding-left 12
:margin-horizontal 8
:margin-bottom 10
:height 48
:background-color (colors/theme-colors colors/white colors/neutral-90)})
(defn background
[]
{:position :absolute
:left 0
:right 0
:top 0
:bottom 0
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1
:border-top-left-radius border-radius
:border-top-right-radius border-radius
:overflow :hidden
:background-color (colors/theme-colors colors/white colors/neutral-95)})
:border-top-right-radius border-radius})
+58 -77
View File
@@ -10,13 +10,11 @@
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]))
[utils.re-frame :as rf]))
(def bottom-sheet-js (js/require "../src/js/bottom_sheet.js"))
(def animation-delay 450)
(defn with-animation
(defn- with-animation
[value & [options callback]]
(reanimated/with-spring
value
@@ -26,20 +24,6 @@
options)
callback))
(def content-height (reagent/atom nil))
(def show-bottom-sheet? (reagent/atom nil))
(def keyboard-was-shown? (reagent/atom false))
(def expanded? (reagent/atom false))
(def gesture-running? (reagent/atom false))
(defn reset-atoms
[]
(reset! show-bottom-sheet? nil)
(reset! content-height nil)
(reset! expanded? false)
(reset! keyboard-was-shown? false)
(reset! gesture-running? false))
(defn get-bottom-sheet-gesture
[pan-y translate-y bg-height bg-height-expanded
window-height keyboard-shown disable-drag? expandable?
@@ -47,16 +31,16 @@
(-> (gesture/gesture-pan)
(gesture/on-start
(fn [_]
(reset! gesture-running? true)
(rf/dispatch [:bottom-sheet/gesture-running? true])
(when (and keyboard-shown (not disable-drag?) show-bottom-sheet?)
(re-frame/dispatch [:dismiss-keyboard]))))
(gesture/on-update
(fn [evt]
(when (and (not disable-drag?) show-bottom-sheet?)
(let [max-pan-up (if (or @expanded? (not expandable?))
(let [max-pan-up (if (or expanded? (not expandable?))
0
(- (- bg-height-expanded bg-height)))
max-pan-down (if @expanded?
max-pan-down (if expanded?
bg-height-expanded
bg-height)]
(reanimated/set-shared-value pan-y
@@ -67,21 +51,21 @@
max-pan-up))))))
(gesture/on-end
(fn [_]
(reset! gesture-running? false)
(rf/dispatch [:bottom-sheet/gesture-running? false])
(when (and (not disable-drag?) show-bottom-sheet?)
(let [end-pan-y (- window-height (.-value translate-y))
expand-threshold (min (* bg-height * 1.1) (+ bg-height 50))
collapse-threshold (max (* bg-height-expanded * 0.9) (- bg-height-expanded 50))
expand-threshold (min (* bg-height 1.1) (+ bg-height 50))
collapse-threshold (max (* bg-height-expanded 0.9) (- bg-height-expanded 50))
should-close-bottom-sheet? (< end-pan-y (max (* bg-height 0.7) 50))]
(cond
should-close-bottom-sheet?
(close-bottom-sheet)
(and (not @expanded?) (> end-pan-y expand-threshold))
(reset! expanded? true)
(and (not expanded?) (> end-pan-y expand-threshold))
(rf/dispatch [:bottom-sheet/did-expand true])
(and @expanded? (< end-pan-y collapse-threshold))
(reset! expanded? false))))))))
(and expanded? (< end-pan-y collapse-threshold))
(rf/dispatch [:bottom-sheet/did-expand false]))))))))
(defn bottom-sheet
[props children]
@@ -91,28 +75,26 @@
visible? :visible?
backdrop-dismiss? :backdrop-dismiss?
expandable? :expandable?
selected-item :selected-item
:or {show-handle? true
backdrop-dismiss? true
expandable? false}}
props
close-bottom-sheet (fn []
(reset! show-bottom-sheet? false)
(when (fn? on-cancel) (on-cancel))
(timer/set-timeout
#(do
(re-frame/dispatch [:bottom-sheet/hide-navigation-overlay])
(reset-atoms))
animation-delay))]
close-bottom-sheet #(re-frame/dispatch-sync [:dismiss-bottom-sheet on-cancel])]
[safe-area/consumer
(fn [insets]
[:f>
(fn []
(let [{window-height :height
window-width :width}
(let [{height :height
window-width :width}
(rn/use-window-dimensions)
window-height (if selected-item (- height 72) height)
{:keys [keyboard-shown]} (hooks/use-keyboard)
bg-height-expanded (- window-height (:top insets))
bg-height (max (min @content-height bg-height-expanded) 200)
{:keys [content-height show-bottom-sheet? keyboard-was-shown? expanded? gesture-running?
animation-delay]}
(rf/sub [:bottom-sheet/config])
bg-height (max (min content-height bg-height-expanded) 150)
bottom-sheet-dy (reanimated/use-shared-value 0)
pan-y (reanimated/use-shared-value 0)
translate-y (.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y)
@@ -120,7 +102,7 @@
(.useBackgroundOpacity ^js bottom-sheet-js translate-y bg-height window-height)
on-content-layout (fn [evt]
(let [height (oget evt "nativeEvent" "layout" "height")]
(reset! content-height height)))
(rf/dispatch [:bottom-sheet/update-height height])))
on-expanded (fn []
(reanimated/set-shared-value bottom-sheet-dy bg-height-expanded)
(reanimated/set-shared-value pan-y 0))
@@ -143,30 +125,30 @@
(react/effect! #(do
(cond
(and
(nil? @show-bottom-sheet?)
(nil? show-bottom-sheet?)
visible?
(some? @content-height)
(> @content-height 0))
(reset! show-bottom-sheet? true)
(some? content-height)
(> content-height 0))
(rf/dispatch [:bottom-sheet/show-quo2-bottom-sheet true])
(and @show-bottom-sheet? (not visible?))
(and show-bottom-sheet? (not visible?))
(close-bottom-sheet)))
[@show-bottom-sheet? @content-height visible?])
[show-bottom-sheet? content-height visible?])
(react/effect! #(do
(when @show-bottom-sheet?
(when show-bottom-sheet?
(cond
keyboard-shown
(do
(reset! keyboard-was-shown? true)
(reset! expanded? true))
(and @keyboard-was-shown? (not keyboard-shown))
(reset! expanded? false))))
[@show-bottom-sheet? @keyboard-was-shown?])
(rf/dispatch [:bottom-sheet/show-quo2-bottom-sheet true])
(rf/dispatch [:bottom-sheet/did-expand true]))
(and keyboard-was-shown? (not keyboard-shown))
(rf/dispatch [:bottom-sheet/did-expand false]))))
[show-bottom-sheet? keyboard-was-shown?])
(react/effect! #(do
(when-not @gesture-running?
(when-not gesture-running?
(cond
@show-bottom-sheet?
(if @expanded?
show-bottom-sheet?
(if expanded?
(do
(reanimated/set-shared-value
bottom-sheet-dy
@@ -176,7 +158,7 @@
;; withTiming/withSpring callback not working
;; on-expanded should be called as a callback of
;; with-animation instead, once this issue has been resolved
(timer/set-timeout on-expanded animation-delay))
(timer/set-timeout on-expanded (or animation-delay 450)))
(do
(reanimated/set-shared-value
bottom-sheet-dy
@@ -186,11 +168,11 @@
;; withTiming/withSpring callback not working
;; on-collapsed should be called as a callback of
;; with-animation instead, once this issue has been resolved
(timer/set-timeout on-collapsed animation-delay)))
(timer/set-timeout on-collapsed (or animation-delay 450))))
(= @show-bottom-sheet? false)
(= show-bottom-sheet? false)
(reanimated/set-shared-value bottom-sheet-dy (with-animation 0)))))
[@show-bottom-sheet? @expanded? @gesture-running?])
[show-bottom-sheet? expanded? gesture-running?])
[:<>
[rn/touchable-without-feedback {:on-press (when backdrop-dismiss? close-bottom-sheet)}
@@ -205,22 +187,21 @@
{:transform [{:translateY translate-y}]}
{:width window-width
:height window-height})}
[rn/view {:style (styles/background)}
[rn/keyboard-avoiding-view
{:behaviour (if platform/ios? :padding :height)
:style {:flex 1}}
[rn/view
{:style {:position :absolute
:left 0
:right 0
:top 0
:padding-top styles/border-radius
:padding-bottom (:bottom insets)}
:on-layout (when-not (and
(some? @content-height)
(> @content-height 0))
on-content-layout)}
children]]
[rn/view {:style styles/container}
(when selected-item
[rn/view {:style (styles/selected-background)}
[selected-item]])
[rn/view {:style (styles/background)}
[rn/keyboard-avoiding-view
{:behaviour (if platform/ios? :padding :height)
:style {:flex 1}}
[rn/view
{:style (styles/content-style insets)
:on-layout (when-not (and
(some? content-height)
(> content-height 0))
on-content-layout)}
children]]
(when show-handle?
[rn/view {:style (styles/handle)}])]]]]))])]))
(when show-handle?
[rn/view {:style (styles/handle)}])]]]]]))])]))
@@ -4,7 +4,9 @@
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.confirmation-drawer.style :as style]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[re-frame.core :as re-frame]
status-im2.common.bottom-sheet.view))
(defn avatar
[group-chat color display-name photo-path]
@@ -26,7 +28,7 @@
[quo/text {:style {:margin-left 10}} extra-text]]))
(defn confirmation-drawer
[{:keys [title description context button-text on-press extra-action extra-text]}]
[{:keys [title description context button-text on-press extra-action extra-text accessibility-label]}]
(let [extra-action-selected? (reagent/atom false)]
(fn []
(let [{:keys [group-chat chat-id public-key color name]} context
@@ -38,7 +40,9 @@
id]))
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path id]))]
[rn/view {:style {:margin-horizontal 20}}
[rn/view
{:style {:margin-horizontal 20}
:accessibility-label accessibility-label}
[quo/text
{:weight :semi-bold
:size :heading-1} title]
@@ -54,7 +58,7 @@
[quo/button
{:type :grey
:style {:flex 0.48} ;;WUT? 0.48 , whats that ?
:on-press #(rf/dispatch [:bottom-sheet/hide])}
:on-press #(re-frame/dispatch-sync [:dismiss-bottom-sheet])}
(i18n/label :t/close)]
[quo/button
{:type :danger
+20
View File
@@ -13,6 +13,9 @@
(def ^:const content-type-community 9)
(def ^:const content-type-gap 10)
(def ^:const content-type-contact-request 11) ;; TODO: temp, will be removed
(def ^:const content-type-gif 12)
(def ^:const content-type-link 13)
(def ^:const content-type-album 14)
(def ^:const contact-request-state-none 0)
(def ^:const contact-request-state-mutual 1)
@@ -198,3 +201,20 @@
(def ^:const delete-message-undo-time-limit-ms 4000)
(def ^:const delete-message-for-me-undo-time-limit-ms 4000)
(def ^:const album-image-sizes
{4 {0 146
1 146
2 146
3 146}
5 {0 146
1 146
2 97
3 97
4 97}
:default {0 146
1 146
2 72.5
3 72.5
4 72.5
5 72.5}})
@@ -2,21 +2,19 @@
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.platform :as platform]
[status-im2.common.home.actions.view :as actions]
[status-im2.contexts.chat.home.chat-list-item.style :as style]
[utils.address :as utils.address]
[utils.re-frame :as rf]
[reagent.core :as reagent]))
[reagent.core :as reagent]
[quo.react :as react]))
(defn open-chat
[chat-id]
(let [view-id (rf/sub [:view-id])]
(when (= view-id :shell-stack)
(rf/dispatch [:dismiss-keyboard])
(if platform/android?
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(rf/dispatch [:chat.ui/navigate-to-chat chat-id]))
(rf/dispatch [:chat.ui/show-profile chat-id])
(rf/dispatch [:search/home-filter-changed nil]))))
(defn action-icon
@@ -28,31 +26,39 @@
admin? (get admins current-pk)
checked? (reagent/atom (if start-a-new-chat?
user-selected?
member?))]
[rn/touchable-opacity
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item extra-data])}])
:style {:position :absolute
:right 20}}
(if (= icon :options)
[quo/icon :i/options {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]
[quo/checkbox
{:default-checked? @checked?
:accessibility-label :contact-toggle-check
:disabled? (and member? (not admin?))
:on-change (fn [selected]
(if start-a-new-chat?
(on-toggle true @checked? public-key)
(if-not member?
(if selected
(rf/dispatch [:select-participant public-key true])
(rf/dispatch [:deselect-participant public-key true]))
(if selected
(rf/dispatch [:undo-deselect-member public-key true])
(rf/dispatch [:deselect-member public-key true])))))}])]))
member?))
on-check (fn [selected]
(if start-a-new-chat?
(on-toggle true @checked? public-key)
(if-not member?
(if selected
(rf/dispatch [:select-participant public-key true])
(rf/dispatch [:deselect-participant public-key true]))
(if selected
(rf/dispatch [:undo-deselect-member public-key true])
(rf/dispatch [:deselect-member public-key true])))))]
[:f>
(fn []
[rn/touchable-opacity
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item extra-data])}])
:style {:position :absolute
:right 20}}
(if (= icon :options)
[quo/icon :i/options
{:size 20
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]
(react/use-memo
(fn []
[quo/checkbox
{:default-checked? @checked?
:accessibility-label :contact-toggle-check
:disabled? (and member? (not admin?))
:on-change on-check}])
[checked?]))])]))
(defn contact-list-item
[item _ _ {:keys [group start-a-new-chat? on-toggle] :as extra-data}]
[item _ _ {:keys [start-a-new-chat? on-toggle] :as extra-data}]
(let [{:keys [public-key ens-verified added? images]} item
display-name (first (rf/sub
[:contacts/contact-two-names-by-identity
@@ -71,9 +77,8 @@
:on-press #(if start-a-new-chat?
(on-toggle true user-selected? public-key)
(open-chat public-key))
:on-long-press #(when (some? group)
(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item extra-data])}]))})
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item extra-data])}])})
[quo/user-avatar
{:full-name display-name
:profile-picture photo-path
+235 -199
View File
@@ -1,31 +1,38 @@
(ns status-im2.common.home.actions.view
(:require [i18n.i18n :as i18n]
[quo2.components.drawers.action-drawers :as drawer]
[status-im.chat.models :as chat.models]
[status-im2.common.confirmation-drawer.view :as confirmation-drawer] ;;TODO move to
;;status-im2
[status-im2.common.constants :as constants]
[utils.re-frame :as rf]))
(:require ;;TODO move to
;;status-im2
[i18n.i18n :as i18n]
[quo2.components.drawers.action-drawers :as drawer]
[status-im.chat.models :as chat.models]
[status-im2.common.confirmation-drawer.view :as confirmation-drawer] ;;TODO move to
[status-im2.common.constants :as constants]
[utils.re-frame :as rf]
[react-native.background-timer :as timer]
[re-frame.core :as re-frame]))
(defn- entry
[{:keys [icon label on-press danger? sub-label chevron? add-divider?]}]
[{:keys [icon label on-press danger? sub-label chevron? add-divider? accessibility-label]}]
{:pre [(keyword? icon)
(string? label)
(fn? on-press)
(boolean? danger?)
(boolean? chevron?)]}
{:icon icon
:label label
:on-press on-press
:danger? danger?
:sub-label sub-label
:right-icon (when chevron? :i/chevron-right)
:add-divider? add-divider?})
{:icon icon
:label label
:on-press on-press
:danger? danger?
:sub-label sub-label
:right-icon (when chevron? :i/chevron-right)
:add-divider? add-divider?
:accessibility-label accessibility-label})
(defn hide-sheet-and-dispatch
[event]
(rf/dispatch [:bottom-sheet/hide])
(rf/dispatch event))
(let [{:keys [animation-delay]} (rf/sub [:bottom-sheet/config])]
(re-frame/dispatch-sync [:dismiss-bottom-sheet])
(timer/set-timeout (fn []
(rf/dispatch event))
(or animation-delay 450))))
(defn show-profile-action
[chat-id]
@@ -42,11 +49,11 @@
(defn mute-chat-action
[chat-id]
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id true]))
(rf/dispatch [::chat.models/mute-chat-toggled chat-id true]))
(defn unmute-chat-action
[chat-id]
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id false]))
(rf/dispatch [::chat.models/mute-chat-toggled chat-id false]))
(defn clear-history-action
[{:keys [chat-id] :as item}]
@@ -54,11 +61,12 @@
[:bottom-sheet/show-sheet
{:content (fn []
(confirmation-drawer/confirmation-drawer
{:title (i18n/label :t/clear-history?)
:description (i18n/label :t/clear-history-confirmation-content)
:context item
:button-text (i18n/label :t/clear-history)
:on-press #(hide-sheet-and-dispatch [:chat.ui/clear-history chat-id])}))}]))
{:title (i18n/label :t/clear-history?)
:description (i18n/label :t/clear-history-confirmation-content)
:context item
:accessibility-label :clear-history-confirm
:button-text (i18n/label :t/clear-history)
:on-press #(hide-sheet-and-dispatch [:chat.ui/clear-history chat-id])}))}]))
(defn delete-chat-action
[{:keys [chat-id] :as item}]
@@ -66,11 +74,12 @@
[:bottom-sheet/show-sheet
{:content (fn []
(confirmation-drawer/confirmation-drawer
{:title (i18n/label :t/delete-chat?)
:description (i18n/label :t/delete-chat-confirmation)
:context item
:button-text (i18n/label :t/delete-chat)
:on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat chat-id])}))}]))
{:title (i18n/label :t/delete-chat?)
:description (i18n/label :t/delete-chat-confirmation)
:context item
:accessibility-label :delete-chat-confirm
:button-text (i18n/label :t/delete-chat)
:on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat chat-id])}))}]))
(defn leave-group-action
[item chat-id]
@@ -78,14 +87,15 @@
[:bottom-sheet/show-sheet
{:content (fn []
(confirmation-drawer/confirmation-drawer
{:title (i18n/label :t/leave-group?)
:description (i18n/label :t/leave-chat-confirmation)
:context item
:button-text (i18n/label :t/leave-group)
:on-press #(do
(rf/dispatch [:navigate-back])
(hide-sheet-and-dispatch [:group-chats.ui/leave-chat-confirmed
chat-id]))}))}]))
{:title (i18n/label :t/leave-group?)
:description (i18n/label :t/leave-chat-confirmation)
:context item
:accessibility-label :leave-group
:button-text (i18n/label :t/leave-group)
:on-press #(do
(rf/dispatch [:navigate-back])
(hide-sheet-and-dispatch [:group-chats.ui/leave-chat-confirmed
chat-id]))}))}]))
(defn block-user-action
[{:keys [public-key] :as item}]
@@ -93,255 +103,281 @@
[:bottom-sheet/show-sheet
{:content (fn []
(confirmation-drawer/confirmation-drawer
{:title (i18n/label :t/block-user?)
:description (i18n/label :t/block-contact-details)
:context item
:button-text (i18n/label :t/block-user)
:on-press #(hide-sheet-and-dispatch [:contact.ui/block-contact-confirmed
public-key])}))}]))
{:title (i18n/label :t/block-user?)
:description (i18n/label :t/block-contact-details)
:context item
:accessibility-label :block-user
:button-text (i18n/label :t/block-user)
:on-press #(hide-sheet-and-dispatch [:contact.ui/block-contact-confirmed
public-key])}))}]))
(defn mute-chat-entry
[chat-id]
(let [muted? (rf/sub [:chats/muted chat-id])]
(entry {:icon (if muted? :i/muted :i/activity-center)
:label (i18n/label
(if muted?
:unmute-chat
:mute-chat))
:on-press (if muted?
#(unmute-chat-action chat-id)
#(mute-chat-action chat-id))
:danger? false
:sub-label nil
:chevron? true})))
(entry {:icon (if muted? :i/muted :i/activity-center)
:label (i18n/label
(if muted?
:unmute-chat
:mute-chat))
:on-press (if muted?
#(unmute-chat-action chat-id)
#(mute-chat-action chat-id))
:danger? false
:accessibility-label :mute-chat
:sub-label nil
:chevron? true})))
(defn mark-as-read-entry
[chat-id]
(entry {:icon :i/correct
:label (i18n/label :t/mark-as-read)
:on-press #(mark-all-read-action chat-id)
:danger? false
:sub-label nil
:chevron? false
:add-divider? true}))
(entry {:icon :i/correct
:label (i18n/label :t/mark-as-read)
:on-press #(mark-all-read-action chat-id)
:danger? false
:accessibility-label :mark-as-read
:sub-label nil
:chevron? false
:add-divider? true}))
(defn clear-history-entry
[chat-id]
(entry {:icon :i/delete
:label (i18n/label :t/clear-history)
:on-press #(clear-history-action chat-id)
:danger? true
:sub-label nil
:chevron? false
:add-divider? true}))
(entry {:icon :i/delete
:label (i18n/label :t/clear-history)
:on-press #(clear-history-action chat-id)
:danger? true
:sub-label nil
:accessibility-label :clear-history
:chevron? false
:add-divider? true}))
(defn delete-chat-entry
[item]
(entry {:icon :i/delete
:label (i18n/label :t/delete-chat)
:on-press #(delete-chat-action item)
:danger? true
:sub-label nil
:chevron? false}))
(entry {:icon :i/delete
:label (i18n/label :t/delete-chat)
:on-press #(delete-chat-action item)
:danger? true
:accessibility-label :delete-chat
:sub-label nil
:chevron? false}))
(defn leave-group-entry
[item extra-data]
(entry {:icon :i/log-out
:label (i18n/label :t/leave-group)
:on-press #(leave-group-action item (if extra-data (:chat-id extra-data) (:chat-id item)))
:danger? true
:sub-label nil
:chevron? false
:add-divider? extra-data}))
(entry
{:icon :i/log-out
:label (i18n/label :t/leave-group)
:on-press #(leave-group-action item (if extra-data (:chat-id extra-data) (:chat-id item)))
:danger? true
:accessibility-label :leave-group
:sub-label nil
:chevron? false
:add-divider? extra-data}))
(defn view-profile-entry
[chat-id]
(entry {:icon :i/friend
:label (i18n/label :t/view-profile)
:on-press #(show-profile-action chat-id)
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/friend
:label (i18n/label :t/view-profile)
:on-press #(show-profile-action chat-id)
:danger? false
:accessibility-label :view-profile
:sub-label nil
:chevron? false}))
(defn edit-nickname-entry
[chat-id]
(entry {:icon :i/edit
:label (i18n/label :t/edit-nickname)
:on-press #(edit-nickname-action chat-id)
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/edit
:label (i18n/label :t/edit-nickname)
:on-press #(edit-nickname-action chat-id)
:danger? false
:accessibility-label :edit-nickname
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): Requires design input.
(defn edit-name-image-entry
[]
(entry {:icon :i/edit
:label (i18n/label :t/edit-name-and-image)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/edit
:label (i18n/label :t/edit-name-and-image)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:accessibility-label :edit-name-and-image
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): Requires design input.
(defn notifications-entry
[add-divider?]
(entry {:icon :i/notifications
:label (i18n/label :t/notifications)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label "All messages" ; TODO: placeholder
:chevron? true
:add-divider? add-divider?}))
(entry {:icon :i/notifications
:label (i18n/label :t/notifications)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label "All messages" ; TODO: placeholder
:accessibility-label :manage-notifications
:chevron? true
:add-divider? add-divider?}))
;; TODO(OmarBasem): Requires design input.
(defn fetch-messages-entry
[]
(entry {:icon :i/save
:label (i18n/label :t/fetch-messages)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? true}))
(entry {:icon :i/save
:label (i18n/label :t/fetch-messages)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:accessibility-label :fetch-messages
:sub-label nil
:chevron? true}))
;; TODO(OmarBasem): Requires design input.
(defn pinned-messages-entry
[]
(entry {:icon :i/pin
:label (i18n/label :t/pinned-messages)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? true}))
(entry {:icon :i/pin
:label (i18n/label :t/pinned-messages)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:accessibility-label :pinned-messages
:sub-label nil
:chevron? true}))
(defn remove-from-contacts-entry
[contact]
(entry {:icon :i/remove-user
:label (i18n/label :t/remove-from-contacts)
:on-press #(hide-sheet-and-dispatch [:contact.ui/remove-contact-pressed contact])
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/remove-user
:label (i18n/label :t/remove-from-contacts)
:on-press #(hide-sheet-and-dispatch [:contact.ui/remove-contact-pressed contact])
:danger? false
:accessibility-label :remove-from-contacts
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): Requires design input.
(defn rename-entry
[]
(entry {:icon :i/edit
:label (i18n/label :t/rename)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/edit
:label (i18n/label :t/rename)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:accessibility-label :rename-contact
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): Requires design input.
(defn show-qr-entry
[]
(entry {:icon :i/qr-code
:label (i18n/label :t/show-qr)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/qr-code
:label (i18n/label :t/show-qr)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:accessibility-label :show-qr-code
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): to be implemented.
(defn share-profile-entry
[]
(entry {:icon :i/share
:label (i18n/label :t/share-profile)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/share
:label (i18n/label :t/share-profile)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:accessibility-label :share-profile
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): to be implemented.
(defn share-group-entry
[]
(entry {:icon :i/share
:label (i18n/label :t/share)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/share
:label (i18n/label :t/share)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:accessibility-label :share-group
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): Requires status-go impl.
(defn mark-untrustworthy-entry
[]
(entry {:icon :i/alert
:label (i18n/label :t/mark-untrustworthy)
:on-press #(js/alert "TODO: to be implemented, requires status-go impl.")
:danger? true
:sub-label nil
:chevron? false
:add-divider? true}))
(entry {:icon :i/alert
:label (i18n/label :t/mark-untrustworthy)
:on-press #(js/alert "TODO: to be implemented, requires status-go impl.")
:danger? true
:accessibility-label :mark-untrustworthy
:sub-label nil
:chevron? false
:add-divider? true}))
(defn block-user-entry
[item]
(entry {:icon :i/block
:label (i18n/label :t/block-user)
:on-press #(block-user-action item)
:danger? true
:sub-label nil
:chevron? false}))
(entry {:icon :i/block
:label (i18n/label :t/block-user)
:on-press #(block-user-action item)
:danger? true
:accessibility-label :block-user
:sub-label nil
:chevron? false}))
(defn remove-from-group-entry
[{:keys [public-key]} chat-id]
(let [username (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))]
(entry {:icon :i/placeholder
:label (i18n/label :t/remove-user-from-group {:username username})
:on-press #(hide-sheet-and-dispatch [:group-chats.ui/remove-member-pressed chat-id
public-key true])
:danger? true
:sub-label nil
:chevron? false
:add-divider? true})))
(entry {:icon :i/placeholder
:label (i18n/label :t/remove-user-from-group {:username username})
:on-press #(hide-sheet-and-dispatch [:group-chats.ui/remove-member-pressed chat-id
public-key true])
:danger? true
:accessibility-label :remove-from-group
:sub-label nil
:chevron? false
:add-divider? true})))
(defn group-details-entry
[chat-id]
(entry {:icon :i/members
:label (i18n/label :t/group-details)
:on-press #(hide-sheet-and-dispatch [:show-group-chat-profile chat-id])
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/members
:label (i18n/label :t/group-details)
:on-press #(hide-sheet-and-dispatch [:show-group-chat-profile chat-id])
:danger? false
:accessibility-label :group-details
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): to be implemented.
(defn add-members-entry
[]
(entry {:icon :i/add-user
:label (i18n/label :t/add-members)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/add-user
:label (i18n/label :t/add-members)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:accessibility-label :add-members
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): to be implemented.
(defn manage-members-entry
[]
(entry {:icon :i/add-user
:label (i18n/label :t/manage-members)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/add-user
:label (i18n/label :t/manage-members)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:accessibility-label :manage-members
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): to be implemented.
(defn edit-group-entry
[]
(entry {:icon :i/edit
:label (i18n/label :t/edit-name-and-image)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/edit
:label (i18n/label :t/edit-name-and-image)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:accessibility-label :edit-group
:sub-label nil
:chevron? false}))
;; TODO(OmarBasem): to be implemented.
(defn group-privacy-entry
[]
(entry {:icon :i/privacy
:label (i18n/label :t/change-group-privacy)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(entry {:icon :i/privacy
:label (i18n/label :t/change-group-privacy)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:accessibility-label :group-privacy
:sub-label nil
:chevron? false}))
(defn destructive-actions
[{:keys [group-chat] :as item}]
+3 -2
View File
@@ -3,5 +3,6 @@
(defn not-implemented
[content]
[rn/view {:border-color :red :border-width 1}
content])
(when content
[rn/view {:border-color :red :border-width 1}
content]))
+18 -18
View File
@@ -3,25 +3,25 @@
(rf/defn upsert
{:events [:toasts/upsert]}
[{:keys [db]} id opts]
(let [{:keys [ordered toasts]} (:toasts db)
update? (some #(= % id) ordered)
ordered (if (not update?) (conj ordered id) ordered)
toasts (assoc toasts id opts)
db (-> db
(update :toasts assoc :ordered ordered :toasts toasts)
(update :toasts dissoc :hide-toasts-timer-set))]
(if (and (not update?) (= (count ordered) 1))
{:show-toasts []
:db db}
{:db db})))
(rf/defn create
{:events [:toasts/create]}
[{:keys [db]} opts]
(let [next-toast-id (or (get-in [:toasts :next-toast-id] db) 1)]
{:db (assoc-in db [:toasts :next-toast-id] (inc next-toast-id))
:dispatch [:toasts/upsert (str "toast-" next-toast-id) opts]}))
(let [{:keys [ordered toasts]} (:toasts db)
next-toast-number (get-in db [:toasts :next-toast-number] 1)
id (or (:id opts)
(str "toast-" next-toast-number))
update? (some #(= % id) ordered)
ordered (if (not update?)
(conj ordered id)
ordered)
toasts (assoc toasts id (dissoc opts :id))]
(cond-> {:db (-> db
(update :toasts assoc :ordered ordered :toasts toasts)
(update :toasts dissoc :hide-toasts-timer-set))}
(and (not update?) (= (count ordered) 1))
(assoc :show-toasts [])
(not (:id opts))
(update-in [:db :toasts :next-toast-number] inc))))
(rf/defn hide-toasts-with-check
{:events [:toasts/hide-with-check]}
+35 -31
View File
@@ -8,23 +8,28 @@
[status-im2.common.toasts.style :as style]
[utils.re-frame :as rf]))
(def ^:private slide-out-up-animation
(-> ^js reanimated/slide-out-up-animation
.springify
(.damping 20)
(.stiffness 300)))
;; (def ^:private slide-out-up-animation
;; (-> ^js reanimated/slide-out-up-animation
;; .springify
;; (.damping 20)
;; (.stiffness 300)))
(def ^:private slide-in-up-animation
(-> ^js reanimated/slide-in-up-animation
.springify
(.damping 20)
(.stiffness 300)))
;; (def ^:private slide-in-up-animation
;; (-> ^js reanimated/slide-in-up-animation
;; .springify
;; (.damping 20)
;; (.stiffness 300)))
(def ^:private linear-transition
(-> ^js reanimated/linear-transition
.springify
(.damping 20)
(.stiffness 300)))
;; (def ^:private linear-transition
;; (-> ^js reanimated/linear-transition
;; .springify
;; (.damping 20)
;; (.stiffness 300)))
(defn toast
[id]
(let [toast-opts (rf/sub [:toasts/toast id])]
[quo/toast toast-opts]))
(defn container
[id]
@@ -35,13 +40,11 @@
(fn []
[:f>
(fn []
(let [toast-opts (rf/sub [:toasts/toast id])
duration (get toast-opts :duration 3000)
on-dismissed #((get toast-opts :on-dismissed identity) id)
translate-y (reanimated/use-shared-value 0)
(let [duration (or (rf/sub [:toasts/toast-cursor id :duration]) 3000)
on-dismissed #((or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity) id)
create-timer (fn []
(reset! timer (utils.utils/set-timeout #(do (close!) (on-dismissed))
duration)))
(reset! timer (utils.utils/set-timeout close! duration)))
translate-y (reanimated/use-shared-value 0)
pan
(->
(gesture/gesture-pan)
@@ -78,13 +81,16 @@
(rn/use-unmount on-dismissed)
[gesture/gesture-detector {:gesture pan}
[reanimated/view
{:entering slide-in-up-animation
:exiting slide-out-up-animation
:layout reanimated/linear-transition
:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
style/each-toast-container)}
[quo/toast toast-opts]]]))])))
{;; TODO: this will eanble layout animation at runtime and causing flicker on android
;; we need to resolve this and re-enable layout animation
;; issue at https://github.com/status-im/status-mobile/issues/14752
;; :entering slide-in-up-animation
;; :exiting slide-out-up-animation
;; :layout reanimated/linear-transition
:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
style/each-toast-container)}
[toast id]]]))])))
(defn toasts
[]
@@ -92,6 +98,4 @@
[into
[rn/view
{:style style/outmost-transparent-container}]
(->> toasts-ordered
reverse
(map (fn [id] ^{:key id} [container id])))]))
(map (fn [id] ^{:key id} [container id]) toasts-ordered)]))
@@ -2,7 +2,7 @@
(:require [cljs.test :refer [deftest is testing]]
[status-im.constants :as constants]
status-im.events
[status-im.test-helpers :as h]
[test-helpers.unit :as h]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.contexts.activity-center.notification-types :as types]
[utils.re-frame :as rf]))
@@ -17,7 +17,7 @@
;; `:chat.ui/navigate-to-chat`, otherwise the chat screen
;; looks completely broken if it has never been opened
;; before for the accepted contact.
[rn/touchable-without-feedback
[rn/touchable-opacity
{:on-press (fn []
(rf/dispatch [:hide-popover])
(rf/dispatch [:contact.ui/send-message-pressed

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