Compare commits

...
Author SHA1 Message Date
Ulises M cd3a1172b3 Add tests 2023-03-03 20:02:17 -06:00
Ulises M 8c9d351f14 Refactor user-avatar 2023-03-03 17:00:11 -06:00
Ulises M 3e93aba011 Fix requires 2023-03-03 16:05:34 -06:00
Jamie Caprani 8d43a6d5be Tests 2023-03-03 16:05:34 -06:00
Ulises Manuel Cárdenas ff3ba6c0f0 Add new text input component 2023-03-03 15:03:38 -06:00
Mohamed Javid 3483bb1107 [Fix] Community Context for Mention or Replies Notification in Activity Center (#15234)
* [Fix] Community Context for Mention or Replies Notification in Activity Center

https://github.com/status-im/status-go/compare/ebc1fc33...71f778ec

* [Update] Status Go Version
2023-03-03 22:57:32 +05:30
Icaro Motta 1f1ab30a4e Use new RPC endpoints to fetch and count unread notifications (#15245)
There are endpoint changes in the status-go PR #3237
https://github.com/status-im/status-go/pull/3237) that will cause breakage in
the Mobile & Desktop clients. The Desktop team has already implemented the
changes and is waiting for Mobile to do the same.

The new endpoints are generally better, more ergonomic to use. There's also a
new endpoint to allow fetching multiple unread counters for all types of
notifications so we can finally remove the dreadful workaround in mobile calling
`status-go` 10+ times in a row.

- Fixes https://github.com/status-im/status-mobile/issues/15119
- Fixes https://github.com/status-im/status-mobile/issues/15229
2023-03-03 12:43:41 -03:00
Icaro Motta 064204256e Fix Activity Center popover not opening (#15239)
Fixes #15230 - The popover state in the app db must be discarded before trying to
open the Activity Center. This workaround is used in other parts of the app too.
It's ugly, but the only quick fix I found.

It's plenty obvious the popover component and all its surrounding logic should
be revisited in the future.
2023-03-03 10:34:55 -03:00
Omar Basem 8923408972 Landscape Mode (#15175)
* feat: landscape mode
2023-03-03 16:33:28 +04:00
Icaro Motta 52b87bab3e Redesign and simplify Activity Center app db (#15216)
Fixes #15215. Redesign the app db state for the Activity Center. Please, see the issue being fixed for more details about the problems being solved.

TL;DR: There's a lot less state to keep track and reconcile and way less nesting in the app db because we're only managing the state of the *current tab*, not all tabs.

Additionally:

- [x] While updating unit tests, found a bug on the sorting notifications' logic.
- [x] While updating unit tests, found a bug where notifications that are not of the type *contact request* were being removed from the app db.
- [x] Fixed regression where pressing on a notification would not open the chat.
- [x] Hardened unit tests.

#### Platforms

- Android
- iOS

##### Non-functional

- Less memory consumption.
- Faster reconciliation of notification coming from signals and from synchronous responses from RPC calls.
2023-03-03 09:17:35 -03:00
John Ngei 25d44b11f1 Fix: chat header height 2023-03-02 21:57:19 +03:00
Brian Sztamfater 9333692830 feat: remove wallet connect 1.0 (#15010) 2023-03-02 17:55:03 +01:00
jakub 4fe8b81bf6 ios: fix xcode using system Node.js version
As discovered in:
https://github.com/status-im/status-mobile/pull/15225

The attempt to fix this in:
https://github.com/status-im/status-mobile/pull/15180

But it doesn't appear to work, so instead I'm allowing an override of
`NODE_BINARY` variable and spetting it when defining the Nix shell.

The key things here are:

* Xcode injects its own paths into `PATH` which breaks Nix env.
* Combining Nix shells with `inputsFrom` does not inherit all vars.

It's important to set these variables in `shellHook` and not elsewhere.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-02 17:32:52 +01:00
Omar Basem 4dfd3af7f5 Album Reactions (#15208)
* feat: album actions
2023-03-02 20:11:17 +04:00
Icaro Motta 11b6702939 Fix (#15232) 2023-03-02 11:02:01 -03:00
Jamie Caprani 39c39915a7 chore: separate resources for old and new ui (#15108) 2023-03-02 14:25:01 +01:00
Ibrahem Khalil 01c058fecc [15127] Make reply and pinned banner react on edit (#15189) 2023-03-02 15:03:30 +02:00
Roman Volosovskyi 8f75874868 [#15042] Fix inconsistent contact request state on syncing 2023-03-02 12:45:37 +01:00
Icaro Motta 041622d98b Make popover delay configurable (#15225)
Make the popover delay in milliseconds configurable.

To open the Activity Center, 30ms delay seems to be more than enough. It's a quick fix because the current 250ms to open the AC gives the wrong impression to users (and confuses even us developers) who think the AC has a performance issue to open.

See issue https://github.com/status-im/status-mobile/pull/15222 for the full discussion.
2023-03-02 08:41:18 -03:00
yqrashawn 4190dfd26b feat: support community that all members allowed to pin (#15197) 2023-03-02 18:43:21 +08:00
flexsurferandChurikova Tetiana f731f75fca move profile tab (#15224)
* move profile tab

* e2e: new profile tab

* e2e: fix leftovers

* e2e: last

---------

Co-authored-by: Churikova Tetiana <tatiana@status.im>
2023-03-02 10:55:45 +01:00
Parvesh Monu 78682b823b fix root id of :init-root-fx (#15228) 2023-03-02 12:10:41 +05:30
Ulises Manuel Cárdenas 7d9709ee67 Improve chat Avatar (#15036) 2023-03-01 14:54:40 -06:00
Ajay Sivan aec1b5fafa quo2 strength divider component (#15177) 2023-03-01 15:47:02 +00:00
Jamie Caprani 5c67216b31 feat: add bottom sheet to see community rules (#15130) 2023-03-01 06:09:46 -08:00
Siddarth Kumar 0c9a195ca9 Improve QR code Handler mobile side PR (#15168)
* point to the relevant branch on status-go

https://github.com/status-im/status-go/compare/a9bfed21...6839f458

* update commit-sha1

* bump version to latest status-go
2023-03-01 18:15:49 +05:30
Churikova Tetiana 06192e7a24 e2e: outgoing CR + new UI 2023-03-01 12:36:49 +01:00
Omar Basem 4a6e42c6f9 fix: activity center closing animation (#15222)
fix: activity center closing animation
2023-03-01 15:12:16 +04:00
yqrashawn 2ce4a820d7 fix: deleted-by user name style (#15218) 2023-03-01 15:03:27 +08:00
jakub b72f0d4702 nix: fix Gradle nodeps JAR symlink filename
Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-28 17:57:39 +01:00
frank b75e1304d8 added param deviceType (#15136) 2023-02-28 21:43:10 +08:00
Yevheniia Berdnyk c2782a26f7 paste from clipboard fix 2023-02-28 15:07:06 +02:00
flexsurfer fa03e91080 Sanitize quo2 namespace (#15207) 2023-02-28 13:59:09 +01:00
Omar Basem f9dda56310 fix: image dimensions on Android (#15211) 2023-02-28 16:20:00 +04:00
jakub 51276237f2 nix: include nodeps JARs in Gradle deps (#15212)
* nix: update gradle dependencies

Signed-off-by: Jakub Sokołowski <jakub@status.im>

* nix: include nodeps JARs in Gradle deps

Signed-off-by: Jakub Sokołowski <jakub@status.im>

* nix: include nodeps JAR for semver4j 0.16.4

Can cause failures like in some cases:
```
A problem occurred configuring project ':react-native-hole-view'.
> Could not resolve all files for configuration ':react-native-hole-view:classpath'.
   > Could not find semver4j-0.16.4-nodeps.jar (com.github.gundy:semver4j:0.16.4).
     Searched in the following locations:
         file:/nix/store/3n2pxsqa2izlx8c23s6jgqai0bqaklm1-status-mobile-maven-deps/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4-nodeps.jar
```

Signed-off-by: Jakub Sokołowski <jakub@status.im>

---------

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-28 17:13:44 +05:30
flexsurfer c667d05929 bump status-go v0.133.2 (#15200) 2023-02-27 17:44:36 +01:00
Churikova Tetiana e1bcc8fec4 e2e: fix pinned messages 2023-02-27 16:39:39 +01:00
Jamie Caprani f84c2ec9f5 chore: add old edit option to communities options (#15131) 2023-02-27 05:49:37 -08:00
flexsurfer 80f063d0dd [#15056] Can't see display/ens/name when mentioning in community (#15085) 2023-02-27 12:51:53 +01:00
Parvesh Monu 69c3a72357 Navigation code cleanup (#15196) 2023-02-27 15:40:11 +05:30
yqrashawn c28b34ac08 fix: toast style on android (#15194) 2023-02-27 17:25:21 +08:00
yqrashawn b192e9efd4 fix: no delete-by ui for delete for me message (#15171)
issue 1 in https://github.com/status-im/status-mobile/issues/15115
2023-02-27 11:14:42 +08:00
jakub 6c7054b5b4 ios: fix lowercased variable name in Xcode config
In some cases might result in failures due to empty shebang:
```
Command PhaseScriptExecution failed with a nonzero exit code
```
Because the script file looks like this:
```
\#!
set -o errexit
export NODE_BINARY="node"
export NODE_ARGS=" --openssl-legacy-provider --max-old-space-size=16384 "

bash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1
```

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-25 11:59:20 +01:00
Icaro Motta 1806cb792a Allow users to swipe to delete or swipe to toggle unread notification status (#15106)
Adds support for swiping left/right on some types of notifications. Swiping left
(from left to right) shows a blue button allowing the user to mark the
notification as read/unread. Swiping right (from right to left) shows a red
button, allowing the user to delete the notification for good.

Related PR in status-go https://github.com/status-im/status-go/pull/3201.

Fixes https://github.com/status-im/status-mobile/issues/14901
Fixes https://github.com/status-im/status-mobile/issues/14900

Technical notes
===============

How's the performance? It feels near native performance in a production release
in a mid-range smartphone. So I'd say it's pretty good, but let me know if you
find any issue.

- I refrained from trying to eliminate all code duplication in this PR. Some
  notifications will behave differently, especially the ones with call to
  action, so I ask you to please take that in consideration when reviewing. See
  https://github.com/status-im/status-mobile/issues/15118
- React Native Gesture Handler has a component named
  [Swipeable](https://docs.swmansion.com/react-native-gesture-handler/docs/api/components/swipeable/).
  I used it instead of writing a monstrosity 👹 of code in
  Reanimated to achieve the same results.
- RN Gesture Handler touchables are the only ones that work with the Swipeable
  component, so I used them and added vars to `react-native.gesture`.
- I had to manually interpolate the translation X of the buttons behind
  notifications because notifications are transparent. To make interpolation
  work with `Swipeable` it's mandatory to use RN `Animated.View` and not
  `Reanimated.View` (see next point).
- `Swipeable` expects us to pass functions that will receive RN
  `AnimatedInterpolation` instances and the rendering lifecycle does not work as
  usual. Hooks didn't trigger as expected, functional Reagent components didn't
  behave as expected, etc. This means `Reanimated.View` and its interpolation
  function is out of question. I did try for almost two days, nothing works.

Testing notes
=============

These are some of the manual tests I ran. There are more scenarios to cover
obviously. Assuming no unread notifications before each flow:

Contact request notification
============================

From the perspective of an user A:

1. Receive a contact request from a non-mutual contact B.
2. Verify the unread count is displayed over the bell icon.
3. Verify the unread count is displayed on the `Messages > Contacts` tab, as
   well as on the AC `Contact requests` tab.
4. Open the AC and before accepting/declining the contact request, check that
   you CAN'T swipe left or right.
5. Accept or decline the contact request.
6. Check the unread indicator disappears in all necessary places.
7. Press on the notification and see if you're redirected to the chat.
8. Go back to the AC and swipe left to mark as `Unread`. Notice that opening the
   chat marks the notification as `Read`. Also very important, notice that the
   `Messages > Contacts` tab will NOT show the *pending contact requests*
   section at the top. This is on purpose, given the notification is unread, but
   the user has already accepted/declined the contact request, hence it's not
   pending.
9. Swipe left againg to mark as `Read`. Check all unread indicators are updated.
10. Swipe right to delete the notification (it won't be displayed ever again).

Admin notification
==================

1. Generate an admin notification, e.g. a community owner receiving a request
   notification to join.
2. Verify the unread count is displayed over the bell icon, as well as the AC
   Admin tab.
3. Verify the community unread indicator is correctly displayed.
4. As an admin, open the AC and before accepting/declining the request, check
   that you CAN'T swipe left or right.
5. Accept or decline the membership request.
6. Check the unread indicator disappears accordingly.
7. Swipe left to mark as `Read`.
8. Swipe left to mark as `Unread`.
9. Swipe right to delete the notification (it won't be displayed ever again).

Mentions & replies
==================

Similar steps outlined for `Admin` notifications, but there's one important
difference. Mention and reply notifications don't require a call to action from
the user, so the user can swipe left/right **without** first having to do
anything on the notification (such as pressing on it). See issue
https://github.com/status-im/status-mobile/issues/15118

What about other types of notifications?
========================================

Swipe gestures for other notification types will be implemented in a separate
PR.
2023-02-24 21:22:31 -03:00
Churikova Tetiana 432f7bcd8c e2e: 1-1 chat, communities 2023-02-24 20:05:30 +01:00
jakub 26d618e305 ios: use sh in shellPath instead of absolute path
Otherwise Xcode uses system Node.js version which is different from Nix
version and can result in weird failures like:
```
admin@macm1-01.he-eu-fsn1.ci.devel:~/status-mobile % node --version
v16.19.0

admin@macm1-01.he-eu-fsn1.ci.devel:~/status-mobile % node --openssl-legacy-provider
node: bad option: --openssl-legacy-provider

admin@macm1-01.he-eu-fsn1.ci.devel:~/status-mobile % make shell
Configuring Nix shell for target 'default'...

[nix-shell:~/status-mobile]$ node --version
v16.17.1

[nix-shell:~/status-mobile]$ node --openssl-legacy-provider
Welcome to Node.js v16.17.1.
Type ".help" for more information.
>
```

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-24 13:30:28 +01:00
John Ngei fac2f952d0 Fix: scroll-page component sticky header height 2023-02-23 18:31:21 +03:00
yqrashawn e830f633d8 fix: toast style (#15170) 2023-02-23 20:18:44 +08:00
Michele Balistreri 6a58f9552d update keycard native module
Signed-off-by: Michele Balistreri <michele@bitgamma.com>
2023-02-23 11:11:20 +01:00
Omar Basem 00db44ab0d Zoomable Image (#15078)
* feat: zoomable image
2023-02-23 07:46:42 +04:00
Ajay Sivan 6ffed4ad47 quo2 profile-select component
Signed-off-by: Parvesh Monu <parvesh.dhullmonu@gmail.com>
2023-02-23 01:41:56 +05:30
jakub e2169cbbd4 ios: use --openssl-legacy-provider with iOS builds
Fixes issue with following failure:
```
Failed to construct transformer:  Error: error:0308010C:digital envelope routines::unsupported
    at new Hash (node:internal/crypto/hash:71:19)
    at Object.createHash (node:crypto:130:10)
    at stableHash (/Users/jenkins/workspace/status-mobile/platforms/ios/node_modules/metro-cache/src/stableHash.js:19:8)
    at JsTransformer.getCacheKey (/Users/jenkins/workspace/status-mobile/platforms/ios/node_modules/metro/src/JSTransformer/worker.js:471:7)
    at getTransformCacheKey (/Users/jenkins/workspace/status-mobile/platforms/ios/node_modules/metro/src/DeltaBundler/Transformer/getTransformCacheKey.js:39:29)
    at new Transformer (/Users/jenkins/workspace/status-mobile/platforms/ios/node_modules/metro/src/DeltaBundler/Transformer.js:147:28)
    at /Users/jenkins/workspace/status-mobile/platforms/ios/node_modules/metro/src/Bundler.js:54:29
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
  library: 'digital envelope routines',
  reason: 'unsupported',
  code: 'ERR_OSSL_EVP_UNSUPPORTED'
```
https://roytuts.com/how-to-fix-err_ossl_evp_unsupported-in-react-js-application/

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-22 18:48:03 +01:00
Ajay Sivan c8fd7121d3 quo2 password-tips component (#15157) 2023-02-22 14:50:56 +01:00
frank 0c96661583 use random tcp port for listen address for node (#15143) 2023-02-22 21:38:27 +08:00
Ajay Sivan d6c09d289c quo2 color-picker component (#15105) 2023-02-22 12:05:40 +01:00
jakub d5cc24fecf ci: add Xcode cleanup Jenkinsfile
Too often Xcode derived data and archives are clogging up hosts.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-22 09:21:59 +01:00
Ajay Sivan 20e16e2f42 fix: Community display image & cover image rendering fixes (#15047) 2023-02-22 07:11:15 +01:00
yqrashawn 3fc4c36ac6 fix: toast style (#15144) 2023-02-22 09:55:21 +08:00
Alexander 1b33aa4988 Outgoing contact requests (#14853)
* First thoughts/ideas

* Showing "Cancel contact request" button

* Fixes

* Restructuring, `retractContactRequest`

* Pending label

* Proper buttons for activity notifications

* New updates

* Returning back `activity-log` `items`

* Last changes in code

* Lint fix

* Lint fix (2)

* Style fixes

* Style fixes

* Code fixes

* Style fixes

* Fixes

https://github.com/status-im/status-go/compare/1d9d7343...0082f7e9

* Footer update

* Toasts done

* Formatting fix

* Go version update

* Fixes for deletion

* status-go-version.json

* Lint fix

* Fixes

* Lint fix

* status-go version

* status-go version
2023-02-21 22:45:54 +01:00
Alexander 888bf12856 Paste button (#15002)
* Paste button

* Lint fix

* str -> string

* Removing of redundant stuff

* Style fixes

* Style fixes

* Style fixes (android)

* Style fixes (android)

* The last style fix

* Styles

* Lint fix
2023-02-21 13:42:22 +01:00
Andrea Maria Piana c4aef97a6d [Fixes: #15093] Add support for mention @everyone
This commit adds support for displaying @everyone mention.
2023-02-21 12:19:02 +00:00
294 changed files with 6276 additions and 5543 deletions
+47
View File
@@ -0,0 +1,47 @@
library 'status-jenkins-lib@v1.6.6'
pipeline {
agent {
label 'linux'
}
triggers {
cron('H 5 * * *')
}
options {
timestamps()
/* Prevent Jenkins jobs from running forever */
timeout(time: 15, unit: 'MINUTES')
/* Disable concurrent jobs */
disableConcurrentBuilds()
/* Don't keep more than 50 builds */
buildDiscarder(logRotator(numToKeepStr: '10'))
}
stages {
stage('Get Nodes') {
steps { script {
stagePerNode = nodesByLabel('macos').collectEntries {
["${it}" : generateNodeCleanupStage(it)]
}
} }
}
stage('Clean Xcode') {
steps { script {
parallel stagePerNode
} }
}
}
}
def generateNodeCleanupStage(nodeLabel) {
return { stage(nodeLabel) {
node(nodeLabel) {
dir('/Users/jenkins/Library/Developer/Xcode') {
sh 'rm -fr Archives DerivedData'
}
}
} }
}
+12 -12
View File
@@ -525,8 +525,8 @@
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -o errexit\nexport NODE_BINARY=\"node\"\nexport NODE_ARGS=\" --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
shellPath = "/usr/bin/env sh";
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
};
0F876BD5356F61BF142A01A0 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -546,7 +546,7 @@
"$(DERIVED_FILE_DIR)/Pods-Status-StatusIm-StatusImTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
@@ -568,7 +568,7 @@
"$(DERIVED_FILE_DIR)/Pods-Status-StatusIm-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
@@ -583,8 +583,8 @@
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -o errexit\nexport NODE_BINARY=\"node\"\nexport NODE_ARGS=\" --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
shellPath = "/usr/bin/env sh";
shellScript = "set -o errexit\nexport NODE_BINARY=\"${NODE_BINARY:-node}\"\nexport NODE_ARGS=\" --openssl-legacy-provider --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
};
3AAD2AD724A3A60E0075D594 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
@@ -597,7 +597,7 @@
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
};
3C1038075AE5E6FB86AC2319 /* [CP] Copy Pods Resources */ = {
@@ -618,7 +618,7 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-resources.sh\"\n";
showEnvVarsInLog = 0;
};
@@ -640,7 +640,7 @@
"$(DERIVED_FILE_DIR)/Pods-Status-StatusImPR-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
@@ -662,7 +662,7 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
@@ -677,7 +677,7 @@
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
};
E732E3E1B024946173BF6D3D /* [CP] Copy Pods Resources */ = {
@@ -698,7 +698,7 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR-resources.sh\"\n";
showEnvVarsInLog = 0;
};
+14
View File
@@ -16,6 +16,7 @@ let
mkdir -p $out
cd $out
'' +
# TODO: Generalize this section to not repeat the same code.
(concatMapStrings (dep:
let
url = "${dep.host}/${dep.path}";
@@ -33,6 +34,13 @@ let
jar-download = optionalString (jar.sha256 != "") (
fetchurl { url = "${url}.${dep.type}"; inherit (jar) sha256; }
);
nodeps = {
sha1 = attrByPath [ "nodeps" "sha1" ] "" dep;
sha256 = attrByPath [ "nodeps" "sha256" ] "" dep;
};
nodeps-download = optionalString (nodeps.sha256 != "") (
fetchurl { url = "${url}-nodeps.jar"; inherit (nodeps) sha256; }
);
fileName = last (splitString "/" dep.path);
directory = removeSuffix fileName dep.path;
in
@@ -51,6 +59,12 @@ let
${optionalString (jar.sha1 != "") ''
echo "${jar.sha1}" > "${dep.path}.${dep.type}.sha1"
''}
${optionalString (nodeps-download != "") ''
ln -s "${nodeps-download}" "${dep.path}-nodeps.jar"
''}
${optionalString (nodeps.sha1 != "") ''
echo "${nodeps.sha1}" > "${dep.path}.${dep.type}.sha1"
''}
'')
deps));
+59 -45
View File
@@ -4018,30 +4018,30 @@
},
{
"path": "com/github/status-im/status-keycard-java/android/3.0.4/android-3.0.4",
"path": "com/github/status-im/status-keycard-java/android/3.1.1/android-3.1.1",
"host": "https://jitpack.io",
"type": "jar",
"pom": {
"sha1": "e6e1933d85ac05b51953effc21ab893679f5864b",
"sha256": "1y9kqp3qgx3kqaf6vm6iwphdj8caqd9x6kncjsnp6f0nirp5ijzq"
"sha1": "ac7e6699628e329dfc028345f32bc41c5d6c2f33",
"sha256": "12qh5qwncj2gbv6g1whz32rliap34mv2kxlyqv2ivg5jc6yfvyhj"
},
"jar": {
"sha1": "dca6e47e087a649643bbad1c1feb4b0b5e1aaf45",
"sha256": "0krxjj5h5zmap4645llscwkmyszm8qyngwg8vi8ds1mf2kp0jaz1"
"sha1": "26118061c0996fff357ae30cc360e5928c8dd455",
"sha256": "15m0h4ri0ny7jz4vvl25blw5s65iivlv5gchw0j5n0jblr1wr270"
}
},
{
"path": "com/github/status-im/status-keycard-java/lib/3.0.4/lib-3.0.4",
"path": "com/github/status-im/status-keycard-java/lib/3.1.1/lib-3.1.1",
"host": "https://jitpack.io",
"type": "jar",
"pom": {
"sha1": "718d3d286d53186552a84cee1a1283e0975da789",
"sha256": "0s2mbx1638qig4m802rf0ill9bghgga8w3ld0vpcz6x7h2kmvv6g"
"sha1": "63c7bbd55ddbf88d1b89941f78158aa07fb46873",
"sha256": "1x0n0xq6zgg5qj6s6j9sjpy3zbggfznr64pb6sjh2882y4d1j6qi"
},
"jar": {
"sha1": "b2afa2711a9898d9aeb188195edde53c00984543",
"sha256": "16c7r0667pbgljx1p8zmvahv1igcnway1qjqprbn0n4ny1vy2imm"
"sha1": "07f0374f17160c8731350316226ffe0de50f6f31",
"sha256": "1bfvb0ynxa0ws46cqmyx6d960pyg7hjxv3xwx7mg0xw03xk2bam1"
}
},
@@ -5778,6 +5778,10 @@
"jar": {
"sha1": "de8c77583e97bbbd3cdbe5f406b583e9b081ff56",
"sha256": "0435ff3qzmcxprsm93x3aw9clgfpa871zl41izhijwm3bwib9yfy"
},
"nodeps": {
"sha1": "273cc1869ddf7ebbac8176402e29f41b1c83d7df",
"sha256": "1w4a2ak60r46wiy8yl00yy8v397qa2zja5jmsd7wsk1p2sjyqn9z"
}
},
@@ -6930,12 +6934,12 @@
},
{
"path": "com/sun/xml/bind/jaxb-bom-ext/4.0.1/jaxb-bom-ext-4.0.1",
"path": "com/sun/xml/bind/jaxb-bom-ext/4.0.2/jaxb-bom-ext-4.0.2",
"host": "https://repo.maven.apache.org/maven2",
"type": "pom",
"pom": {
"sha1": "6916f1573d78b0d41b629257277da86215ea7a6f",
"sha256": "069gm0wclljzdjn5j29hizhc4rakszk8kgzmsx66h5fkvlcvgd5b"
"sha1": "600924984be6a63e1c38d5f6ef0637a070002937",
"sha256": "1jsdpynkd7d7bqp81ajcy7fa2riz9wnl8rb81icd8shv7awnkbfx"
}
},
@@ -6950,12 +6954,12 @@
},
{
"path": "com/sun/xml/bind/mvn/jaxb-parent/4.0.1/jaxb-parent-4.0.1",
"path": "com/sun/xml/bind/mvn/jaxb-parent/4.0.2/jaxb-parent-4.0.2",
"host": "https://repo.maven.apache.org/maven2",
"type": "pom",
"pom": {
"sha1": "315ec09b889041008f815ddd41cca9633ee50cc4",
"sha256": "1bpqac2a25qq81h99zvj20n9ac2hd8iry7mnwisvd4f8avpm272i"
"sha1": "160938bb66dc61a4839edaad77a5b7b7f9f5171d",
"sha256": "184avj0jpjz1rsxrrw88yn31yxkvw1l3blyq6fs4sbmgac12dvqc"
}
},
@@ -6980,12 +6984,12 @@
},
{
"path": "com/sun/xml/bind/mvn/jaxb-txw-parent/4.0.1/jaxb-txw-parent-4.0.1",
"path": "com/sun/xml/bind/mvn/jaxb-txw-parent/4.0.2/jaxb-txw-parent-4.0.2",
"host": "https://repo.maven.apache.org/maven2",
"type": "pom",
"pom": {
"sha1": "0f5e6242fe24ccd5e4c663dc66f7b935b4cffb55",
"sha256": "1niyxycc1k9qb0hpkb30zcccai28pq4yhy9a8p45d24zgrvdgs1a"
"sha1": "c9c99b4e33782535b5988616bc3b452543cb48e5",
"sha256": "0xxyqayffjwdmagqa6jqca8ykl3iz2vhw59l6478nv8ir268x2rn"
}
},
@@ -7650,12 +7654,12 @@
},
{
"path": "org/antlr/antlr4-master/4.11.1/antlr4-master-4.11.1",
"path": "org/antlr/antlr4-master/4.12.0/antlr4-master-4.12.0",
"host": "https://repo.maven.apache.org/maven2",
"type": "pom",
"pom": {
"sha1": "298ecf68d872658e1d92457168018bd5b8fff245",
"sha256": "1b80dq56qs5rqzbvq5pyf2pcsgfmmfmsmznhbxw1armvvbl5vskj"
"sha1": "5cd9d694d06e046886a7a8e54d70b22bc03af4a3",
"sha256": "0x3rhw76nrzh35d8liq9wffm74rshxwg944xc55c3qlcwlxg3xj2"
}
},
@@ -7674,16 +7678,16 @@
},
{
"path": "org/antlr/antlr4-runtime/4.11.1/antlr4-runtime-4.11.1",
"path": "org/antlr/antlr4-runtime/4.12.0/antlr4-runtime-4.12.0",
"host": "https://repo.maven.apache.org/maven2",
"type": "jar",
"pom": {
"sha1": "b76aa0c70639f8b3112e4d5e14abf951cb38761c",
"sha256": "0d0vd3nh9f2aqy4njx4d0qh7jwha83crmxkyplgmk307b4lyqmn4"
"sha1": "3113149fe4ea467b27f14f2b99096cac9d4ca53a",
"sha256": "1r3isigbls4i2ldc4kyq3kzv2klcgz7przyq3knz02aasrzm95n6"
},
"jar": {
"sha1": "069214c1de1960040729702eb58deac8827135e7",
"sha256": "0nfsdach3x0vyv1isnvvjp7hif0kdzyb1i1f0lv4vhfcq59nav70"
"sha1": "dd105cf6ac9f7417b3782c178f6dbd06bf75df57",
"sha256": "0d6sd7jrxfxd7qp5gbsd8vdq6wp1r2iww189g76i0vkxj8s3ndfv"
}
},
@@ -8540,16 +8544,16 @@
},
{
"path": "org/checkerframework/checker-qual/3.29.0/checker-qual-3.29.0",
"path": "org/checkerframework/checker-qual/3.31.0/checker-qual-3.31.0",
"host": "https://repo.maven.apache.org/maven2",
"type": "jar",
"pom": {
"sha1": "76bd5ffeef4d9b039e6445e2674264dbc5bfb94c",
"sha256": "0azs4ndih02r5a3fvn08sndwc58ymzma2krqclfz6pivmfrxcyp2"
"sha1": "a600a4210e8c3db6ea45ea0989920b0255dbb6f6",
"sha256": "0cajb4ivvw446lc3bcwl49difmpgg1rrcbzklxc87rs7pqz9qms3"
},
"jar": {
"sha1": "a805a761b7a734d69f9c1766ead1ff78698a1497",
"sha256": "1hb8ajlszzvh3cimvzkwgkx2689rh131jh7259a7s94cvzjq1p77"
"sha1": "eeefd4af42e2f4221d145c1791582f91868f99ab",
"sha256": "1fai6kk72j76ivgipgl7ckbcn8g8yl289pbx712zpii2dm3mzvqw"
}
},
@@ -8775,6 +8779,16 @@
}
},
{
"path": "org/eclipse/ee4j/project/1.0.8/project-1.0.8",
"host": "https://repo.maven.apache.org/maven2",
"type": "pom",
"pom": {
"sha1": "41a621037931f9f4aa8768694be9f5cb59df83df",
"sha256": "0jv7vwx72mx30ydlhk5ql3q8zb67m2qpw43f4inaypm3aip7n30d"
}
},
{
"path": "org/eclipse/jdt/core/compiler/ecj/4.4.2/ecj-4.4.2",
"host": "https://repo.maven.apache.org/maven2",
@@ -8828,12 +8842,12 @@
},
{
"path": "org/glassfish/jaxb/jaxb-bom/4.0.1/jaxb-bom-4.0.1",
"path": "org/glassfish/jaxb/jaxb-bom/4.0.2/jaxb-bom-4.0.2",
"host": "https://repo.maven.apache.org/maven2",
"type": "pom",
"pom": {
"sha1": "99d85661aef6ac9f6bfb6af0f0ea507d054b91e1",
"sha256": "151zbrywjzbnmwqg246iyz0bqnx2hh730hxmig62vh67s2nbw8lm"
"sha1": "12668536ac24e77398bd675a1e458c1824d156c7",
"sha256": "08bgmpyhps9h25z6950g7751zg6g5vkvn02v1znamarlaw2niyl6"
}
},
@@ -8852,16 +8866,16 @@
},
{
"path": "org/glassfish/jaxb/jaxb-core/4.0.1/jaxb-core-4.0.1",
"path": "org/glassfish/jaxb/jaxb-core/4.0.2/jaxb-core-4.0.2",
"host": "https://repo.maven.apache.org/maven2",
"type": "jar",
"pom": {
"sha1": "e366262bbe2037088461f748896f6aa4afcfd3c6",
"sha256": "14d3d3p0c42qd8jq8mxmpymd17x5zxixhyccwfmxkr24ad9pvj46"
"sha1": "9aecfe4442b96fc3f9cabc25e7c6e310972d674e",
"sha256": "00yij4s17cvixysjdjrzc51jd07fpcc11jy4lgg1z8zfvx6zdhma"
},
"jar": {
"sha1": "b4707bb31dfcf54ae424b930741f0cd62d672af9",
"sha256": "19v525w4qb65czx1v31k5lz0yan9vc030h736iqgz59l2048hf3l"
"sha1": "08c29249f6c10f4ee08967783831580b0f5c5360",
"sha256": "1k8c8wf420nmqyhyr6p0ns12mx127bzwq71rp6x0nj3qmma2kzyp"
}
},
@@ -8894,16 +8908,16 @@
},
{
"path": "org/glassfish/jaxb/txw2/4.0.1/txw2-4.0.1",
"path": "org/glassfish/jaxb/txw2/4.0.2/txw2-4.0.2",
"host": "https://repo.maven.apache.org/maven2",
"type": "jar",
"pom": {
"sha1": "160273691bf3ffa0745bf86453dd56c62ec23ac2",
"sha256": "03zv45jgmppikcqk7gq01pyryzvam3qnllc5q7jjywvnq5mjdvvp"
"sha1": "f8eef3319522b021e51123ea88d6ab4d484d2c59",
"sha256": "1ry99inn7v0fpgfrnhj3h4qnhaccmksn8vsrgfn1ysj6cqrfgc8p"
},
"jar": {
"sha1": "797720dfe2e15504f6014fb82eb873051a653c75",
"sha256": "1aba3rk9jm66k65vx95a92sdapbsvfbsvii26s8y9rach44p9m7l"
"sha1": "24e167be69c29ebb7ee0a3b1f9b546f1dfd111fc",
"sha256": "036gl0lp8y83zxy01pyzvq169i0r03lhm169fw7m6hha9wp92wga"
}
},
+2 -2
View File
@@ -357,8 +357,8 @@ com.github.bumptech.glide:glide:4.12.0
com.github.bumptech.glide:okhttp3-integration:4.12.0
com.github.clans:fab:1.6.4
com.github.gundy:semver4j:0.16.4
com.github.status-im.status-keycard-java:android:3.0.4
com.github.status-im.status-keycard-java:lib:3.0.4
com.github.status-im.status-keycard-java:android:3.1.1
com.github.status-im.status-keycard-java:lib:3.1.1
com.github.status-im:function:0.0.1
com.github.wix-playground:ahbottomnavigation:3.3.0
com.github.wix-playground:reflow-animator:1.0.6
+12 -11
View File
@@ -285,8 +285,8 @@ https://dl.google.com/dl/android/maven2/com/google/android/material/material/1.0
https://dl.google.com/dl/android/maven2/com/google/android/material/material/1.2.0-alpha03/material-1.2.0-alpha03.pom
https://jitpack.io/com/github/Dimezis/BlurView/version-2.0.2/BlurView-version-2.0.2.pom
https://jitpack.io/com/github/status-im/function/0.0.1/function-0.0.1.pom
https://jitpack.io/com/github/status-im/status-keycard-java/android/3.0.4/android-3.0.4.pom
https://jitpack.io/com/github/status-im/status-keycard-java/lib/3.0.4/lib-3.0.4.pom
https://jitpack.io/com/github/status-im/status-keycard-java/android/3.1.1/android-3.1.1.pom
https://jitpack.io/com/github/status-im/status-keycard-java/lib/3.1.1/lib-3.1.1.pom
https://jitpack.io/com/github/wix-playground/ahbottomnavigation/3.3.0/ahbottomnavigation-3.3.0.pom
https://jitpack.io/com/github/wix-playground/reflow-animator/1.0.6/reflow-animator-1.0.6.pom
https://jitpack.io/com/github/yalantis/ucrop/2.2.6-native/ucrop-2.2.6-native.pom
@@ -503,12 +503,12 @@ https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/4.1.1
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/2.21/istack-commons-2.21.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/4.1.1/istack-commons-4.1.1.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/2.2.11/jaxb-bom-ext-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/4.0.1/jaxb-bom-ext-4.0.1.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/4.0.2/jaxb-bom-ext-4.0.2.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-parent/2.2.11/jaxb-parent-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-parent/4.0.1/jaxb-parent-4.0.1.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-parent/4.0.2/jaxb-parent-4.0.2.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-runtime-parent/2.2.11/jaxb-runtime-parent-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-txw-parent/2.2.11/jaxb-txw-parent-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-txw-parent/4.0.1/jaxb-txw-parent-4.0.1.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-txw-parent/4.0.2/jaxb-txw-parent-4.0.2.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/FastInfoset/1.2.13/FastInfoset-1.2.13.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/FastInfoset/2.1.0/FastInfoset-2.1.0.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/fastinfoset-project/1.2.13/fastinfoset-project-1.2.13.pom
@@ -561,9 +561,9 @@ https://repo.maven.apache.org/maven2/org/antlr/ST4/4.0.8/ST4-4.0.8.pom
https://repo.maven.apache.org/maven2/org/antlr/ST4/4.3.4/ST4-4.3.4.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.5.2-1/antlr4-master-4.5.2-1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.5.3/antlr4-master-4.5.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.11.1/antlr4-master-4.11.1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.12.0/antlr4-master-4.12.0.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-runtime/4.11.1/antlr4-runtime-4.11.1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-runtime/4.12.0/antlr4-runtime-4.12.0.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4/4.5.3/antlr4-4.5.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-master/3.3/antlr-master-3.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-master/3.5.2/antlr-master-3.5.2.pom
@@ -636,7 +636,7 @@ https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.56/bcprov
https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.60/bcprov-jdk15on-1.60.pom
https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.29.0/checker-qual-3.29.0.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.31.0/checker-qual-3.31.0.pom
https://repo.maven.apache.org/maven2/org/codehaus/codehaus-parent/4/codehaus-parent-4.pom
https://repo.maven.apache.org/maven2/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
https://repo.maven.apache.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.pom
@@ -656,16 +656,17 @@ https://repo.maven.apache.org/maven2/org/easymock/easymock/5.1.0/easymock-5.1.0.
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation-project/2.0.0/angus-activation-project-2.0.0.pom
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation/2.0.0/angus-activation-2.0.0.pom
https://repo.maven.apache.org/maven2/org/eclipse/ee4j/project/1.0.7/project-1.0.7.pom
https://repo.maven.apache.org/maven2/org/eclipse/ee4j/project/1.0.8/project-1.0.8.pom
https://repo.maven.apache.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.4.2/ecj-4.4.2.pom
https://repo.maven.apache.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.4/ecj-4.4.pom
https://repo.maven.apache.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.6.1/ecj-4.6.1.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-bom/2.2.11/jaxb-bom-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-bom/4.0.1/jaxb-bom-4.0.1.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-bom/4.0.2/jaxb-bom-4.0.2.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-core/2.2.11/jaxb-core-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-core/4.0.1/jaxb-core-4.0.1.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-core/4.0.2/jaxb-core-4.0.2.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-runtime/2.2.11/jaxb-runtime-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/txw2/2.2.11/txw2-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/txw2/4.0.1/txw2-4.0.1.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/txw2/4.0.2/txw2-4.0.2.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/2.2/hamcrest-core-2.2.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
+22
View File
@@ -36,6 +36,11 @@ function match_repo_url() {
exit 1
}
function pom_has_nodeps_jar() {
grep '<shadedClassifierName>nodeps</shadedClassifierName>' $1 \
2>&1 >/dev/null
}
if [[ -z "${1}" ]]; then
echo "Required argument not given!" >&2
exit 1
@@ -96,6 +101,16 @@ if [[ "${OBJ_TYPE}" != "pom" ]]; then
fi
fi
# Some deps include nodeps JARs which include.
if pom_has_nodeps_jar "${POM_PATH}"; then
NODEPS_NIX_FETCH_OUT=$(nix_fetch "${OBJ_REL_URL}-nodeps.jar")
if [[ ${?} -eq 0 ]]; then
NODEPS_PATH=$(get_nix_path "${NODEPS_NIX_FETCH_OUT}")
NODEPS_SHA256=$(get_nix_sha "${NODEPS_NIX_FETCH_OUT}")
NODEPS_SHA1=$(get_sha1 "${NODEPS_PATH}")
fi
fi
# Format into a Nix attrset entry
echo -ne "
{
@@ -114,6 +129,13 @@ if [[ -n "${OBJ_SHA256}" ]]; then
\"jar\": {
\"sha1\": \"${OBJ_SHA1}\",
\"sha256\": \"${OBJ_SHA256}\"
}";[[ -n "${NODEPS_SHA256}" ]] && echo -n ","
fi
if [[ -n "${NODEPS_SHA256}" ]]; then
echo -n "
\"nodeps\": {
\"sha1\": \"${NODEPS_SHA1}\",
\"sha256\": \"${NODEPS_SHA256}\"
}"
fi
echo -e "\n },"
+1
View File
@@ -20,6 +20,7 @@ in {
];
# WARNING: Executes shellHook in reverse order.
# WARNING: Only some variables are merged.
inputsFrom = [
fastlane.shell
cocoapods-sh
+8 -2
View File
@@ -1,8 +1,14 @@
{ mkShell, deps }:
{ mkShell, nodejs, deps }:
mkShell {
# check if node modules changed and if so install them
# Check if node modules changed and if so install them.
shellHook = ''
# Fix for ERR_OSSL_EVP_UNSUPPORTED error.
export NODE_OPTIONS="--openssl-legacy-provider";
# Fix Xcode using system Node.js version.
export NODE_BINARY="${nodejs}/bin/node";
export STATUS_MOBILE_HOME=$(git rev-parse --show-toplevel)
"$STATUS_MOBILE_HOME/nix/scripts/node_modules.sh" ${deps.nodejs-patched}
'';
+2 -2
View File
@@ -28,7 +28,6 @@
"@react-native-community/push-notification-ios": "^1.4.1",
"@react-native-community/slider": "^3.0.0",
"@walletconnect/client": "^2.0.0-beta.23",
"@walletconnect/client-legacy": "npm:@walletconnect/client@^1.7.1",
"bignumber.js": "git+https://github.com/status-im/bignumber.js.git#refs/tags/v4.0.2-status",
"chance": "^1.1.0",
"create-react-class": "^15.6.2",
@@ -62,6 +61,7 @@
"react-native-lottie-splash-screen": "^1.0.1",
"react-native-mail": "^6.1.1",
"react-native-navigation": "^7.27.1",
"react-native-orientation-locker": "^1.5.0",
"react-native-permissions": "^2.1.5",
"react-native-randombytes": "^3.6.1",
"react-native-reanimated": "2.3.3",
@@ -69,7 +69,7 @@
"react-native-safe-area-context": "^2.0.0",
"react-native-shake": "^3.3.1",
"react-native-share": "^7.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.38",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39",
"react-native-svg": "^9.8.4",
"react-native-touch-id": "^4.4.1",
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Before

Width:  |  Height:  |  Size: 539 KiB

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Before

Width:  |  Height:  |  Size: 601 B

After

Width:  |  Height:  |  Size: 601 B

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 896 B

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 593 B

Before

Width:  |  Height:  |  Size: 837 B

After

Width:  |  Height:  |  Size: 837 B

Before

Width:  |  Height:  |  Size: 998 B

After

Width:  |  Height:  |  Size: 998 B

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 377 KiB

After

Width:  |  Height:  |  Size: 377 KiB

Before

Width:  |  Height:  |  Size: 738 KiB

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

+2 -4
View File
@@ -1,11 +1,9 @@
#!/usr/bin/env sh
CHANGES=$(git diff --no-ext-diff --diff-filter=d --cached --unified=0 --no-prefix --minimal --exit-code src/quo src/quo2 | grep '^+' || echo '')
INVALID_CHANGES=$(echo "$CHANGES" | grep -E '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im)')
INVALID_CHANGES=$(grep -E -r '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im\.|status-im2\.)' './src/quo2')
if test -n "$INVALID_CHANGES"; then
echo "re-frame dispatch/subscribe and status-im are not allowed in quo/quo2 components"
echo "WARNING: re-frame, status-im are not allowed in quo2 components"
echo ''
echo "$INVALID_CHANGES"
exit 1
+19 -11
View File
@@ -139,6 +139,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def react-native-svg
#js
{:ClipPath #js {:render identity}
:Circle #js {:render identity}
:Defs #js {:render identity}
:Path #js {:render identity}
:Rect #js {:render identity}
@@ -265,7 +266,15 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def react-native-gesture-handler
#js
{:default #js {}
{:FlatList #js {}
:Gesture #js {:Pan nil}
:GestureDetector #js {}
:LongPressGestureHandler #js {}
:NativeViewGestureHandler #js {}
:PanGestureHandler #js {}
:PureNativeButton #js {}
:RectButton #js {}
:ScrollView #js {}
:State #js
{:BEGAN nil
:ACTIVE nil
@@ -273,19 +282,13 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
:END nil
:FAILED nil
:UNDETERMINED nil}
:PureNativeButton #js {}
:Swipeable #js {}
:TapGestureHandler #js {}
:PanGestureHandler #js {}
:TouchableHighlight #js {}
:LongPressGestureHandler #js {}
:TouchableWithoutFeedback #js {}
:NativeViewGestureHandler #js {}
:FlatList #js {}
:ScrollView #js {}
:TouchableOpacity #js {}
:GestureDetector #js {}
:Gesture #js {:Pan nil}
:createNativeWrapper identity})
:TouchableWithoutFeedback #js {}
:createNativeWrapper identity
:default #js {}})
(def react-native-redash #js {:clamp nil})
@@ -331,6 +334,10 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def react-native-camera-roll
(clj->js {:default #js {}}))
(def react-native-orientation-locker
(clj->js {:default #js {}
:useDeviceOrientationChange #js {}}))
(def wallet-connect-client
#js
{:default #js {}
@@ -396,6 +403,7 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
"react-native-share" react-native-share
"@react-native-async-storage/async-storage" async-storage
"react-native-svg" react-native-svg
"react-native-orientation-locker" react-native-orientation-locker
"../src/js/worklet_factory.js" worklet-factory
"../src/js/shell_worklets.js" shell-worklets
"../src/js/bottom_sheet.js" bottom-sheet
@@ -5,12 +5,11 @@
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[react-native.fast-image :as fast-image]
[reagent.core :as reagent]
[quo2.foundations.colors :as colors]
[status-im.ui.components.fast-image :as fast-image]
[quo2.components.animated-header-flatlist.style :as style]
[oops.core :as oops]
[utils.re-frame :as rf]))
[oops.core :as oops]))
(def header-height 234)
(def cover-height 192)
@@ -51,10 +50,8 @@
[reanimated/view {:style (style/entity-picture size-animation)}
[display-picture-comp image-animation]]]))
(defn animated-header-list
[{:keys [header-comp main-comp] :as parameters}]
[{:keys [header-comp main-comp back-button-on-press] :as parameters}]
[safe-area/consumer
(fn [insets]
(let [window-height (:height (rn/get-window))
@@ -76,7 +73,7 @@
[rn/view {:style (style/container-view view-height)}
[rn/touchable-opacity
{:active-opacity 1
:on-press #(rf/dispatch [:navigate-back])
:on-press back-button-on-press
:style (style/button-container {:left 20})}
[quo/icon :i/arrow-left {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
[rn/touchable-opacity
@@ -1,154 +0,0 @@
(ns quo2.components.avatars.user-avatar
(:require [clojure.string :refer [blank? split upper-case]]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :refer [dark?]]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]))
(def sizes
{:big {:outer 80
:inner 72
:status-indicator 20
:status-indicator-border 4
:font-size :heading-1}
:medium {:outer 48
:inner 44
:status-indicator 12
:status-indicator-border 2
:font-size :paragraph-1}
:small {:outer 32
:inner 28
:status-indicator 12
:status-indicator-border 2
:font-size :paragraph-2}
:xs {:outer 24
:inner 24
:status-indicator 0
:status-indicator-border 0
:font-size :paragraph-2}
:xxs {:outer 20
:inner 20
:status-indicator 0
:status-indicator-border 0
:font-size :label}
:xxxs {:outer 16
:inner 16
:status-indicator 0
:status-indicator-border 0
:font-size :label}})
(defn dot-indicator
[size status-indicator? online? ring? dark?]
(when status-indicator?
(let [dimensions (get-in sizes [size :status-indicator])
border-width (get-in sizes [size :status-indicator-border])
right (case size
:big 2
:medium 0
:small -2
0)
bottom (case size
:big (if ring?
-1
2)
:medium (if ring?
0
-2)
:small (if ring?
-2
-2)
0)]
[rn/view
{:style {:background-color (if online?
colors/success-50
colors/neutral-40)
:width dimensions
:height dimensions
:border-width border-width
:border-radius dimensions
:border-color (if dark?
colors/neutral-100
colors/white)
:position :absolute
:bottom bottom
:right right}}])))
(defn container-styling
[inner-dimensions outer-dimensions]
{:width inner-dimensions
:position :absolute
:top (/ (- outer-dimensions inner-dimensions) 2)
:left (/ (- outer-dimensions inner-dimensions) 2)
:height inner-dimensions
:border-radius inner-dimensions})
(defn container
[inner-dimensions outer-dimensions & children]
[rn/view
{:style (merge {:background-color (colors/custom-color-by-theme :turquoise 50 60)
:justify-content :center
:align-items :center}
(container-styling inner-dimensions outer-dimensions))}
children])
(def small-sizes #{:xs :xxs :xxxs})
(def identicon-sizes #{:big :medium :small})
(defn user-avatar
[{:keys [ring?
online?
size
status-indicator?
profile-picture
full-name]
:or {full-name "empty name"
status-indicator? true
online? true
size :big
ring? true}}]
(let [initials (if full-name
(reduce str (map first (split full-name " ")))
"")
first-initial-letter (if full-name
(or (first full-name) "")
"")
identicon? (contains? identicon-sizes size)
small? (contains? small-sizes size)
outer-dimensions (get-in sizes [size :outer])
inner-dimensions (get-in sizes
[size
(if ring?
:inner
:outer)])
font-size (get-in sizes [size :font-size])
icon-text (if-not (or (blank? first-initial-letter)
(blank? initials))
(if small?
first-initial-letter
initials)
"")]
[rn/view
{:accessibility-label :user-avatar
:style {:width outer-dimensions
:height outer-dimensions
:border-radius outer-dimensions}}
(when (and false (and ring? identicon?)) ;;TODO not implemented yet
[icons/icon :i/identicon-ring
{:size outer-dimensions
:no-color true}])
(if profile-picture
;; display image
[fast-image/fast-image
{:source profile-picture
:style (container-styling inner-dimensions outer-dimensions)}]
;; else display initials
[container inner-dimensions outer-dimensions
^{:key :icon-text}
[text/text
{:weight :semi-bold
:size font-size
:style {:color colors/white-opa-70}}
(upper-case icon-text)]])
[dot-indicator size status-indicator? online? ring? (dark?)]]))
@@ -0,0 +1,127 @@
(ns quo2.components.avatars.user-avatar.component-spec
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[status-im2.common.resources :as resources]
[test-helpers.component :as h]))
(defn- test-truthy [element]
(.toBeTruthy (js/expect element)))
(defn- test-null [element]
(.toBeNull (js/expect element)))
(h/describe "user avatar"
(h/test "Default render"
(h/render [user-avatar/user-avatar])
(test-truthy (h/get-by-label-text :user-avatar))
(test-truthy (h/get-by-text "EN")))
(h/describe "Profile picture"
(h/test "Renders"
(h/render
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)}])
(test-truthy (h/get-by-label-text :profile-picture)))
(h/test "Renders even if `:full-name` is passed"
(h/render
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)
:full-name "New User1"}])
(test-truthy (h/get-by-label-text :profile-picture))
(test-null (h/query-by-label-text :initials-avatar)))
(h/describe "Status indicator"
(h/test "Render"
(h/render
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)
:status-indicator? true}])
(test-truthy (h/get-by-label-text :profile-picture))
(test-truthy (h/get-by-label-text :status-indicator)))
(h/test "Do not render"
(h/render
[user-avatar/user-avatar {:profile-picture (resources/get-mock-image :user-picture-male4)
:status-indicator? false}])
(test-truthy (h/get-by-label-text :profile-picture))
(test-null (h/query-by-label-text :status-indicator)))))
(h/describe "Initials Avatar"
(h/describe "Render initials"
(letfn [(user-avatar-component [size]
[user-avatar/user-avatar {:full-name "New User"
:size size}])]
(h/describe "Two letters"
(h/test "Size :big"
(h/render (user-avatar-component :big))
(test-truthy (h/get-by-text "NU")))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(test-truthy (h/get-by-text "NU")))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(test-truthy (h/get-by-text "NU"))))
(h/describe "One letter"
(h/test "Size :xs"
(h/render (user-avatar-component :xs))
(test-truthy (h/get-by-text "N")))
(h/test "Size :xxs"
(h/render (user-avatar-component :xxs))
(test-truthy (h/get-by-text "N")))
(h/test "Size :xxxs"
(h/render (user-avatar-component :xxxs))
(test-truthy (h/get-by-text "N"))))))
(h/describe "Render ring"
(letfn [(user-avatar-component [size]
[user-avatar/user-avatar {:full-name "New User"
:ring-background (resources/get-mock-image :ring)
:size size}])]
(h/describe "Passed and drawn"
(h/test "Size :big"
(h/render (user-avatar-component :big))
(test-truthy (h/get-by-label-text :initials-avatar))
(test-truthy (h/get-by-label-text :ring-background)))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(test-truthy (h/get-by-label-text :initials-avatar))
(test-truthy (h/get-by-label-text :ring-background)))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(test-truthy (h/get-by-label-text :initials-avatar))
(test-truthy (h/get-by-label-text :ring-background))))
(h/describe "Passed and not drawn (because of invalid size for ring)"
(h/test "Size :xs"
(h/render (user-avatar-component :xs))
(test-truthy (h/get-by-label-text :initials-avatar))
(test-null (h/query-by-label-text :ring-background)))
(h/test "Size :xxs"
(h/render (user-avatar-component :xxs))
(test-truthy (h/get-by-label-text :initials-avatar))
(test-null (h/query-by-label-text :ring-background)))
(h/test "Size :xxxs"
(h/render (user-avatar-component :xxxs))
(test-truthy (h/get-by-label-text :initials-avatar))
(test-null (h/query-by-label-text :ring-background))))))
(h/describe "Status indicator"
(h/test "Render"
(h/render
[user-avatar/user-avatar {:full-name "Test User"
:status-indicator? true}])
(test-truthy (h/get-by-label-text :initials-avatar))
(test-truthy (h/get-by-label-text :status-indicator)))
(h/test "Do not render"
(h/render
[user-avatar/user-avatar {:full-name "Test User"
:status-indicator? false}])
(test-truthy (h/get-by-label-text :initials-avatar))
(test-null (h/query-by-label-text :status-indicator))))))
@@ -0,0 +1,83 @@
(ns quo2.components.avatars.user-avatar.style
(:require [quo2.foundations.colors :as colors]))
(def sizes
{:big {:outer 80
:inner 72
:status-indicator 20
:status-indicator-border 4
:font-size :heading-1}
:medium {:outer 48
:inner 44
:status-indicator 12
:status-indicator-border 2
:font-size :paragraph-1}
:small {:outer 32
:inner 28
:status-indicator 12
:status-indicator-border 2
:font-size :paragraph-2}
:xs {:outer 24
:inner 24
:status-indicator 0
:status-indicator-border 0
:font-size :paragraph-2}
:xxs {:outer 20
:inner 20
:status-indicator 0
:status-indicator-border 0
:font-size :label}
:xxxs {:outer 16
:inner 16
:status-indicator 0
:status-indicator-border 0
:font-size :label}})
(defn outer
[size]
(let [dimensions (get-in sizes [size :outer])]
{:width dimensions
:height dimensions
:border-radius dimensions}))
(defn initials-avatar
[size draw-ring?]
(let [outer-dimensions (get-in sizes [size :outer])
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
{:position :absolute
:top (/ (- outer-dimensions inner-dimensions) 2)
:left (/ (- outer-dimensions inner-dimensions) 2)
:width inner-dimensions
:height inner-dimensions
:border-radius inner-dimensions
:justify-content :center
:align-items :center
:background-color (colors/custom-color-by-theme :turquoise 50 60)}))
(def initials-avatar-text
{:color colors/white-opa-70})
(defn dot
[size online? ring?]
(let [background (if online? colors/success-50 colors/neutral-40)
dimensions (get-in sizes [size :status-indicator])
border-width (get-in sizes [size :status-indicator-border])
right (case size
:big 2
:medium 0
:small -2
0)
bottom (case size
:big (if ring? -1 2)
:medium (if ring? 0 -2)
:small -2
0)]
{:position :absolute
:bottom bottom
:right right
:width dimensions
:height dimensions
:border-width border-width
:border-radius dimensions
:border-color (colors/theme-colors colors/white colors/neutral-100)
:background-color background}))
@@ -0,0 +1,56 @@
(ns quo2.components.avatars.user-avatar.view
(:require [clojure.string :as string]
[quo2.components.avatars.user-avatar.style :as style]
[quo2.components.markdown.text :as text]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]))
(defn- extract-initials
[full-name amount-initials]
(let [upper-case-first-letter (comp string/upper-case first)
names-list (string/split full-name " ")]
(->> names-list
(map upper-case-first-letter)
(take amount-initials)
(string/join))))
(defn initials-avatar
[{:keys [full-name size draw-ring?]}]
(let [font-size (get-in style/sizes [size :font-size])
amount-initials (if (#{:xs :xxs :xxxs} size) 1 2)]
[rn/view {:accessibility-label :initials-avatar
:style (style/initials-avatar size draw-ring?)}
[text/text
{:style style/initials-avatar-text
:size font-size
:weight :semi-bold}
(extract-initials full-name amount-initials)]]))
(def valid-ring-sizes #{:big :medium :small})
(defn user-avatar
"If no `profile-picture` is given, draws the initials based on the `full-name` and
uses `ring-background` to display the ring behind the initials when given. Otherwise,
shows the `profile-picture` which already comes with the ring drawn."
[{:keys [full-name status-indicator? online? size profile-picture ring-background]
:or {status-indicator? true
online? true
size :big}}]
(let [full-name (or full-name "empty name")
draw-ring? (and ring-background (valid-ring-sizes size))
outer-styles (style/outer size)]
[rn/view {:style outer-styles :accessibility-label :user-avatar}
;; The `profile-picture` already has the ring in it
(when-let [image (or profile-picture ring-background)]
[fast-image/fast-image
{:accessibility-label (if draw-ring? :ring-background :profile-picture)
:style outer-styles
:source image}])
(when-not profile-picture
[initials-avatar
{:full-name full-name
:size size
:draw-ring? draw-ring?}])
(when status-indicator?
[rn/view {:accessibility-label :status-indicator
:style (style/dot size online? draw-ring?)}])]))
@@ -0,0 +1,23 @@
(ns quo2.components.colors.color-picker.component-spec
(:require [quo2.components.colors.color-picker.view :as color-picker]
[reagent.core :as reagent]
[test-helpers.component :as h]))
(h/describe "color-picker"
(h/test "color picker rendered"
(h/render [color-picker/view])
(-> (h/expect (h/get-all-by-label-text :color-picker-item))
(.toHaveLength 12)))
(h/test "clicks on a color item"
(let [event (h/mock-fn)]
(h/render [color-picker/view {:on-change #(event)}])
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
(-> (h/expect event)
(.toHaveBeenCalled))))
(h/test "color picker color changed"
(let [selected (reagent/atom nil)]
(h/render [color-picker/view {:on-change #(reset! selected %)}])
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
(-> (h/expect @selected)
(.toStrictEqual :blue)))))
@@ -0,0 +1,48 @@
(ns quo2.components.colors.color-picker.style
(:require [quo2.foundations.colors :as colors]))
(def color-picker-container
{:max-width 338
:flex-direction :row
:flex-wrap :wrap
:justify-content :space-between})
(def flex-break
{:flex-basis "100%"
:height 10})
(defn color-button
[color selected?]
(merge {:width 48
:height 48
:border-width 4
:border-radius 24
:transform [{:rotate "45deg"}]
:border-color :transparent}
(when selected?
{:border-top-color (colors/alpha color 0.4)
:border-end-color (colors/alpha color 0.4)
:border-bottom-color (colors/alpha color 0.2)
:border-start-color (colors/alpha color 0.2)})))
(defn color-circle
[color border?]
{:width 40
:height 40
:transform [{:rotate "-45deg"}]
:background-color color
:justify-content :center
:align-items :center
:border-color color
:border-width (if border? 2 0)
:overflow :hidden
:border-radius 20})
(defn secondary-overlay
[secondary-color border?]
{:width (if border? 18 20)
:height 40
:position :absolute
:right 0
:background-color secondary-color})
@@ -0,0 +1,71 @@
(ns quo2.components.colors.color-picker.view
(:require [react-native.core :as rn]
[quo2.foundations.colors :as colors]
[quo2.components.icon :as icon]
[reagent.core :as reagent]
[quo2.components.colors.color-picker.style :as style]))
(def color-list [:blue :yellow :turquoise :copper :sky :camel :orange :army :pink :purple :magenta])
(defn picker-colors
[blur?]
(concat (map (fn [color]
{:name color
:color (colors/custom-color-by-theme color (if blur? 60 50) 60)})
color-list)
[{:name :yinyang
:color (colors/theme-colors (colors/custom-color :yin 50)
(colors/custom-color :yang 50))
:secondary-color (colors/theme-colors (colors/custom-color :yang 50)
(colors/custom-color :yin 50))}]))
(defn- on-change-handler
[selected color-name on-change]
(reset! selected color-name)
(when on-change (on-change color-name)))
(defn- color-item
[{:keys [name
color
secondary-color
selected?
on-press
blur?]}]
(let [border? (and (not blur?) (and secondary-color (not selected?)))]
[rn/touchable-opacity
{:style (style/color-button color selected?)
:accessibility-label :color-picker-item
:on-press #(on-press name)}
[rn/view
{:style (style/color-circle color border?)}
(when (and secondary-color (not selected?))
[rn/view
{:style (style/secondary-overlay secondary-color border?)}])
(when selected?
[icon/icon :i/check
{:size 20
:color (or secondary-color
colors/white)}])]]))
(defn view
"Options
- `default-selected?` Default selected color name.
- `selected` Selected color name.
- `on-change` Callback called when a color is selected `(fn [color-name])`.
- `blur?` Boolean to enable blur background support.}"
[{:keys [default-selected?]}]
(let [internal-selected (reagent/atom default-selected?)]
(fn [{:keys [blur? on-change selected]}]
(when (and (not (nil? selected)) (not= @internal-selected selected))
(reset! internal-selected selected))
[rn/view {:style style/color-picker-container}
(doall (map-indexed (fn [index color]
[:<> {:key (color :name)}
[color-item
(merge color
{:selected? (= (color :name) @internal-selected)
:on-press #(on-change-handler internal-selected % on-change)
:blur? blur?})]
(when (= index 5) [rn/view {:style style/flex-break}])])
(picker-colors blur?)))])))
@@ -0,0 +1,38 @@
(ns quo2.components.dividers.strength-divider.component-spec
(:require [quo2.components.dividers.strength-divider.view :as strength-divider]
[test-helpers.component :as h]))
(h/describe "select-profile component"
(h/test "render component"
(h/render [strength-divider/view {:type :okay}])
(-> (h/expect (h/get-by-label-text :strength-divider))
(.toBeTruthy)))
(h/test "render component with :type :very-weak"
(h/render [strength-divider/view {:type :very-weak}])
(-> (h/expect (h/get-by-translation-text :strength-divider-very-weak-label))
(.toBeTruthy)))
(h/test "render component with :type :weak"
(h/render [strength-divider/view {:type :weak}])
(-> (h/expect (h/get-by-translation-text :strength-divider-weak-label))
(.toBeTruthy)))
(h/test "render component with :type :okay"
(h/render [strength-divider/view {:type :okay}])
(-> (h/expect (h/get-by-translation-text :strength-divider-okay-label))
(.toBeTruthy)))
(h/test "render component with :type :strong"
(h/render [strength-divider/view {:type :strong}])
(-> (h/expect (h/get-by-translation-text :strength-divider-strong-label))
(.toBeTruthy)))
(h/test "render component with :type :very-strong"
(h/render [strength-divider/view {:type :very-strong}])
(-> (h/expect (h/get-by-translation-text :strength-divider-very-strong-label))
(.toBeTruthy)))
(h/test "render component with :type :alert"
(h/render [strength-divider/view {:type :alert} "Text message"])
(-> (h/expect (h/get-by-text "Text message"))
(.toBeTruthy)))
(h/test "render component with :type :info"
(h/render [strength-divider/view {:type :info} "Text Info"])
(-> (h/expect (h/get-by-text "Text Info"))
(.toBeTruthy))))
@@ -0,0 +1,13 @@
(ns quo2.components.dividers.strength-divider.style)
(def container
{:height 40
:flex-direction :row
:padding-horizontal 20
:align-items :center})
(defn text
[color]
{:color color
:margin-left 4})
@@ -0,0 +1,85 @@
(ns quo2.components.dividers.strength-divider.view
(:require [quo2.components.dividers.strength-divider.style :as style]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[react-native.svg :as svg]
[utils.i18n :as i18n]))
(def strength-divider-types
{:very-weak {:default-text (i18n/label :t/strength-divider-very-weak-label)
:color colors/danger-60
:percentage 20}
:weak {:default-text (i18n/label :t/strength-divider-weak-label)
:color (colors/custom-color :orange 60)
:percentage 40}
:okay {:default-text (i18n/label :t/strength-divider-okay-label)
:color (colors/custom-color :yellow 60)
:percentage 60}
:strong {:default-text (i18n/label :t/strength-divider-strong-label)
:color colors/success-60
:percentage 80}
:very-strong {:default-text (i18n/label :t/strength-divider-very-strong-label)
:color colors/success-60
:percentage 100}
:info {:color colors/white-opa-40}
:alert {:color colors/danger-60}})
(defn circular-progress
[{:keys [color percentage]}]
(let [strength-indicator-radius 6.5
strength-indicator-circumference (* 2 Math/PI strength-indicator-radius)]
[svg/svg
{:view-box "0 0 16 16"
:width 14.2
:transform [{:rotate "270deg"}]
:height 14.2}
[svg/circle
{:cx 8
:cy 8
:r strength-indicator-radius
:fill :transparent
:stroke-width 1.2
:stroke (colors/alpha color 0.2)}]
[svg/circle
{:cx 8
:cy 8
:r strength-indicator-radius
:fill :transparent
:stroke-width 1.2
:stroke-dasharray strength-indicator-circumference
:stroke-dashoffset (* (- 100 percentage) 0.01 strength-indicator-circumference)
:stroke color}]
[svg/circle]]))
(defn strength-indicator
[type]
(let [{:keys [color percentage]} (strength-divider-types type)]
(case type
:info nil
:alert [icon/icon :i/alert
{:color color
:size 16}]
[circular-progress {:color color :percentage percentage}])))
(defn view
"Options
- `:type` `:very-weak`/`:weak`/`:okay`/`:strong`/`:very-strong`/`:info`/`:alert`)
`text` message string(only works when type is `info`/`alert`)"
[{:keys [type] :or {type :very-weak}} text]
(let [{:keys [color default-text]} (strength-divider-types type)]
[linear-gradient/linear-gradient
{:colors [(colors/alpha color 0.05) (colors/alpha color 0)]}
[rn/view
{:style style/container
:accessibility-label :strength-divider}
[strength-indicator type]
[text/text
{:size :paragraph-2
:weight :medium
:style (style/text color)}
(or default-text text)]]]))
+170
View File
@@ -0,0 +1,170 @@
(ns quo2.components.input.style
(:require [quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]))
(def variants-colors
"Colors that keep the same across input's status change"
{:light {:label colors/neutral-50
:icon colors/neutral-50
:cursor (colors/custom-color :blue 50)
:button-border colors/neutral-30
:clear-icon colors/neutral-40
:password-icon colors/neutral-50}
:light-blur {:label colors/neutral-80-opa-40
:icon colors/neutral-80-opa-70
:cursor (colors/custom-color :blue 50)
:button-border colors/neutral-80-opa-30
:password-icon colors/neutral-100
:clear-icon colors/neutral-80-opa-30}
:dark {:label colors/neutral-40
:icon colors/neutral-40
:cursor (colors/custom-color :blue 60)
:button-border colors/neutral-70
:password-icon colors/white
:clear-icon colors/neutral-60}
:dark-blur {:label colors/white-opa-40
:icon colors/white-opa-70
:cursor colors/white
:button-border colors/white-opa-10
:password-icon colors/white
:clear-icon colors/white-opa-10}})
(def status-colors
{:light {:default {:border-color colors/neutral-20
:placeholder colors/neutral-40
:text colors/neutral-100}
:focus {:border-color colors/neutral-40
:placeholder colors/neutral-30
:text colors/neutral-100}
:error {:border-color colors/danger-opa-40
:placeholder colors/neutral-40
:text colors/neutral-100}
:disabled {:border-color colors/neutral-20
:placeholder colors/neutral-40
:text colors/neutral-40}}
:light-blur {:default {:border-color colors/neutral-80-opa-10
:placeholder colors/neutral-80-opa-40
:text colors/neutral-100}
:focus {:border-color colors/neutral-80-opa-20
:placeholder colors/neutral-80-opa-20
:text colors/neutral-100}
:error {:border-color colors/danger-opa-40
:placeholder colors/neutral-80-opa-40
:text colors/neutral-100}
:disabled {:border-color colors/neutral-80-opa-10
:placeholder colors/neutral-80-opa-30
:text colors/neutral-80-opa-30}}
:dark {:default {:border-color colors/neutral-80
:placeholder colors/neutral-50
:text colors/white}
:focus {:border-color colors/neutral-60
:placeholder colors/neutral-60
:text colors/white}
:error {:border-color colors/danger-opa-40
:placeholder colors/white-opa-40
:text colors/white}
:disabled {:border-color colors/neutral-80
:placeholder colors/neutral-40
:text colors/neutral-40}}
:dark-blur {:default {:border-color colors/white-opa-10
:placeholder colors/white-opa-40
:text colors/white}
:focus {:border-color colors/white-opa-40
:placeholder colors/white-opa-20
:text colors/white}
:error {:border-color colors/danger-opa-40
:placeholder colors/white-opa-40
:text colors/white}
:disabled {:border-color colors/white-opa-10
:placeholder colors/white-opa-20
:text colors/white-opa-20}}})
(defn input-container
[colors-by-status small? disabled?]
{:flex-direction :row
:padding-horizontal 8
:border-width 1
:border-color (:border-color colors-by-status)
:border-radius (if small? 10 14)
:opacity (if disabled? 0.3 1)})
(defn left-icon-container
[small?]
{:margin-left (if small? 0 4)
:margin-right (if small? 4 8)
:margin-top (if small? 5 9)
:height 20
:width 20})
(defn icon
[colors-by-variant]
{:color (:icon colors-by-variant)
:size 20})
(defn input
[colors-by-status small? multiple-lines?]
(merge (text/text-style {:size :paragraph-1 :weight :regular})
{:flex 1
:text-align-vertical :top
:padding-horizontal 0
:padding-vertical (if small? 4 8)
:color (:text colors-by-status)}
(when-not multiple-lines?
{:height (if small? 30 38)})))
(defn right-icon-touchable-area
[small?]
{:margin-left (if small? 4 8)
:padding-right (if small? 0 4)
:padding-top (if small? 5 9)})
(defn password-icon
[variant-colors]
{:size 20
:color (:password-icon variant-colors)})
(defn clear-icon
[variant-colors]
{:size 20
:color (:clear-icon variant-colors)})
(def texts-container
{:flex 1
:flex-direction :row
:height 18
:margin-bottom 8})
(def label-container {:flex 1})
(defn label-color
[variant-colors]
{:color (:label variant-colors)})
(def counter-container
{:flex 1
:align-items :flex-end})
(defn counter-color
[current-chars char-limit variant-colors]
{:color (if (> current-chars char-limit)
colors/danger-60
(:label variant-colors))})
(defn button
[colors-by-variant small?]
{:justify-content :center
:align-items :center
:height 24
:border-width 1
:border-color (:button-border colors-by-variant)
:border-radius 8
:margin-vertical (if small? 3 7)
:margin-left 4
:margin-right (if small? -4 0)
:padding-horizontal 7
:padding-top 1.5
:padding-bottom 2.5})
(defn button-text
[colors-by-status]
{:color (:text colors-by-status)})
+173
View File
@@ -0,0 +1,173 @@
(ns quo2.components.input.view
(:require [oops.core :as oops]
[quo2.components.icon :as icon]
[quo2.components.input.style :as style]
[quo2.components.markdown.text :as text]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- label-&-counter
[{:keys [label current-chars char-limit variant-colors]}]
(let [count-text (when char-limit (str current-chars "/" char-limit))]
[rn/view {:style style/texts-container}
[rn/view {:style style/label-container}
[text/text
{:style (style/label-color variant-colors)
:weight :medium
:size :paragraph-2}
label]]
[rn/view {:style style/counter-container}
[text/text
{:style (style/counter-color current-chars char-limit variant-colors)
:weight :regular
:size :paragraph-2}
count-text]]]))
(defn- left-accessory
[{:keys [variant-colors small icon-name]}]
[rn/view {:style (style/left-icon-container small)}
[icon/icon icon-name (style/icon variant-colors)]])
(defn- right-accessory
[{:keys [variant-colors small disabled on-press icon-style-fn icon-name]}]
[rn/touchable-opacity
{:style (style/right-icon-touchable-area small)
:disabled disabled
:on-press on-press}
[icon/icon icon-name (icon-style-fn variant-colors)]])
(defn- right-button
[{:keys [variant-colors colors-by-status small disabled on-press text]}]
[rn/touchable-opacity
{:style (style/button variant-colors small)
:disabled disabled
:on-press on-press}
[rn/text {:style (style/button-text colors-by-status)}
text]])
(def ^:private custom-props
"Custom properties that must be removed from properties map passed to InputText."
[:type :variant :error :right-icon :left-icon :disabled :small :button :label
:char-limit :on-char-limit-reach :icon-name])
(defn- base-input
[{:keys [on-change-text on-char-limit-reach]}]
(let [status (reagent/atom :default)
on-focus #(reset! status :focus)
on-blur #(reset! status :default)
multiple-lines? (reagent/atom false)
set-multiple-lines! #(let [height (oops/oget % "nativeEvent.contentSize.height")]
(if (> height 57)
(reset! multiple-lines? true)
(reset! multiple-lines? false)))
char-count (reagent/atom 0)
update-char-limit! (fn [new-text char-limit]
(when on-change-text (on-change-text new-text))
(let [amount-chars (count new-text)]
(reset! char-count amount-chars)
(when (>= amount-chars char-limit)
(on-char-limit-reach amount-chars))))]
(fn [{:keys [variant error right-icon left-icon disabled small button label char-limit
multiline clearable]
:or {variant :light}
:as props}]
(let [status-path (cond
disabled :disabled
error :error
:else @status)
colors-by-status (get-in style/status-colors [variant status-path])
variant-colors (style/variants-colors variant)
clean-props (apply dissoc props custom-props)]
[rn/view
(when (or label char-limit)
[label-&-counter
{:variant-colors variant-colors
:label label
:current-chars @char-count
:char-limit char-limit}])
[rn/view {:style (style/input-container colors-by-status small disabled)}
(when-let [{:keys [icon-name]} left-icon]
[left-accessory
{:variant-colors variant-colors
:small small
:icon-name icon-name}])
[rn/text-input
(cond-> {:style (style/input colors-by-status small @multiple-lines?)
:placeholder-text-color (:placeholder colors-by-status)
:cursor-color (:cursor variant-colors)
:editable (not disabled)
:on-focus on-focus
:on-blur on-blur}
:always (merge clean-props)
multiline (assoc :on-content-size-change set-multiple-lines!)
char-limit (assoc :on-change-text #(update-char-limit! char-limit %)))]
(when-let [{:keys [on-press icon-name style-fn]} right-icon]
[right-accessory
{:variant-colors variant-colors
:small small
:disabled disabled
:icon-style-fn style-fn
:icon-name icon-name
:on-press (fn []
(when clearable (reset! char-count 0))
(on-press))}])
(when-let [{:keys [on-press text]} button]
[right-button
{:colors-by-status colors-by-status
:variant-colors variant-colors
:small small
:disabled disabled
:on-press on-press
:text text}])]]))))
(defn- password-input
[_]
(let [password-shown? (reagent/atom false)]
(fn [props]
[base-input
(assoc props
:auto-capitalize :none
:auto-complete :new-password
:secure-text-entry (not @password-shown?)
:right-icon {:style-fn style/password-icon
:icon-name (if @password-shown? :i/hide :i/reveal)
:on-press #(swap! password-shown? not)})])))
(defn input
"This input supports the following properties:
- :type - Can be `:text`(default) or `:password`.
- :variant - :light(default), :light-blur, :dark or :dark-blur.
- :small - Boolean to specify if this input is rendered in its small version.
- :multiline - Boolean to specify if this input support multiple lines.
- :icon-name - The name of an icon to display at the left of the input.
- :error - Boolean to specify it this input marks an error.
- :disabled - Boolean to specify if this input is disabled or not.
- :clearable - Booolean to specify if this input has a clear button at the end.
- :on-clear - Function executed when the clear button is pressed.
- :button - Map containing `:on-press` & `:text` keys, if provided renders a button
- :label - A label for this input.
- :char-limit - A number to set a maximum char limit for this input.
- :on-char-limit-reach - Function executed each time char limit is reached or exceeded.
and supports the usual React Native's TextInput properties to control its behaviour:
- :value
- :default-value
- :on-change
- :on-change-text
...
"
[{:keys [type clearable on-clear on-change-text icon-name]
:or {type :text}
:as props}]
(let [base-props (cond-> props
icon-name (assoc-in [:left-icon :icon-name] icon-name)
clearable (assoc :right-icon
{:style-fn style/clear-icon
:icon-name :i/clear
:on-press #(when on-clear (on-clear))})
on-change-text (assoc :on-change-text
(fn [new-text]
(on-change-text new-text)
(reagent/flush))))]
(if (= type :password)
[password-input base-props]
[base-input base-props])))
@@ -1,5 +1,5 @@
(ns quo2.components.list-items.preview-list
(:require [quo2.components.avatars.user-avatar :as user-avatar]
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as quo2.icons]
[quo2.components.markdown.text :as quo2.text]
[quo2.foundations.colors :as colors]
@@ -0,0 +1,66 @@
(ns quo2.components.list-items.user-list
(:require [react-native.core :as rn]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.markdown.text :as text]
[quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[quo2.components.messages.author.view :as author]
[quo2.components.selectors.selectors :as selectors]))
(def container-style
{:margin-horizontal 8
:padding-vertical 8
:padding-horizontal 12
:border-radius 12
:flex 1
:flex-direction :row
:align-items :center})
(defn action-icon
[{:keys [type on-press on-check disabled? checked?]}]
[rn/touchable-opacity
{:on-press (when on-press on-press)
:style {:position :absolute :right 20}}
(case type
:options
[icons/icon :i/options
{:size 20
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]
:checkbox
[selectors/checkbox
{:checked? checked?
:accessibility-label :user-list-toggle-check
:disabled? disabled?
:on-change (when on-check on-check)}]
:close
[text/text "not implemented"]
[rn/view])])
(defn user-list
[{:keys [short-chat-key primary-name secondary-name photo-path online? contact? verified?
untrustworthy? on-press on-long-press accessory]}]
[rn/touchable-opacity
{:style container-style
:accessibility-label :user-list
:on-press (when on-press on-press)
:on-long-press (when on-long-press on-long-press)}
[user-avatar/user-avatar
{:full-name primary-name
:profile-picture photo-path
:status-indicator? true
:online? online?
:size :small}]
[rn/view {:style {:margin-left 8}}
[author/author
{:primary-name primary-name
:secondary-name secondary-name
:contact? contact?
:verified? verified?
:untrustworthy? untrustworthy?}]
(when short-chat-key
[text/text
{:size :paragraph-1
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
short-chat-key])]
(when accessory
[action-icon accessory])])
@@ -7,14 +7,6 @@
:flex-direction :row
:align-items :center})
(defn ens-text
[]
{:color (colors/theme-colors colors/neutral-100 colors/white)})
(defn nickname-text
[]
{:color (colors/theme-colors colors/neutral-100 colors/white)})
(def middle-dot-nickname
{:color colors/neutral-50
:margin-horizontal 4})
@@ -27,12 +19,6 @@
{:color colors/neutral-50
:margin-left 4})
(defn profile-name-text
[nickname?]
{:color (if nickname?
(colors/theme-colors colors/neutral-60 colors/neutral-40)
(colors/theme-colors colors/neutral-100 colors/white))})
(def icon-container
{:margin-left 4})
+55 -81
View File
@@ -3,97 +3,71 @@
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.components.messages.author.style :as style]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
(def middle-dot "·")
(defn display-name
[{:keys [profile-name nickname ens-name text-style]}]
(let [ens? (-> ens-name string/blank? not)
nickname? (-> nickname string/blank? not)]
(if ens?
[text/text
(merge {:weight :semi-bold
:size :paragraph-2
:style (style/ens-text)}
text-style)
ens-name]
[:<>
(if nickname?
[text/text
(merge {:weight :semi-bold
:size :paragraph-2
:style (style/nickname-text)}
text-style)
nickname]
[text/text
(merge {:weight :semi-bold
:size :paragraph-2
:style (style/profile-name-text nickname?)}
text-style)
profile-name])])))
(defn author
[{:keys [profile-name nickname short-chat-key ens-name time-str contact? verified? untrustworthy?]}]
[{:keys [primary-name secondary-name short-chat-key time-str contact? verified? untrustworthy?]}]
[:f>
(fn []
(let [ens? (-> ens-name string/blank? not)
nickname? (-> nickname string/blank? not)]
[rn/view {:style style/container}
(if ens?
[rn/view {:style style/container}
[:<>
[text/text
{:weight :semi-bold
:size :paragraph-2
:number-of-lines 1
:style {:color (colors/theme-colors colors/neutral-100 colors/white)}}
primary-name]
(when (not (string/blank? secondary-name))
[:<>
[text/text
{:weight :semi-bold
:size :paragraph-2
:style (style/ens-text)}
ens-name]
[:<>
(when nickname?
[:<>
[text/text
{:weight :semi-bold
:size :paragraph-2
:style (style/nickname-text)}
nickname]
[text/text
{:size :paragraph-2
:style style/middle-dot-nickname}
middle-dot]])
[text/text
{:weight (if nickname? :medium :semi-bold)
:size :paragraph-2
:style (style/profile-name-text nickname?)}
profile-name]])
(when contact?
[icons/icon :main-icons2/contact
{:size 12
:no-color true
:container-style style/icon-container}])
(cond
verified?
[icons/icon :main-icons2/verified
{:size 12
:no-color true
:container-style style/icon-container}]
untrustworthy?
[icons/icon :main-icons2/untrustworthy
{:size 12
:no-color true
:container-style style/icon-container}])
(when-not ens?
{:size :paragraph-2
:number-of-lines 1
:style style/middle-dot-nickname}
middle-dot]
[text/text
{:monospace true
:size :paragraph-2
:style style/chat-key-text}
short-chat-key])
(when-not ens?
[text/text
{:monospace true
:size :paragraph-2
:style style/middle-dot-chat-key}
middle-dot])
{:weight :medium
:size :paragraph-2
:number-of-lines 1
:style {:color (colors/theme-colors colors/neutral-60 colors/neutral-40)}}
secondary-name]])]
(when contact?
[icons/icon :main-icons2/contact
{:size 12
:no-color true
:container-style style/icon-container}])
(cond
verified?
[icons/icon :main-icons2/verified
{:size 12
:no-color true
:container-style style/icon-container}]
untrustworthy?
[icons/icon :main-icons2/untrustworthy
{:size 12
:no-color true
:container-style style/icon-container}])
(when (and (not verified?) short-chat-key)
[text/text
{:monospace true
:size :paragraph-2
:number-of-lines 1
:style style/chat-key-text}
short-chat-key])
(when (and (not verified?) time-str)
[text/text
{:monospace true
:size :paragraph-2
:number-of-lines 1
:style style/middle-dot-chat-key}
middle-dot])
(when time-str
[text/text
{:monospace true
:size :paragraph-2
:accessibility-label :message-timestamp
:style (style/time-text ens?)}
time-str]]))])
:number-of-lines 1
:style (style/time-text verified?)}
time-str])])])
@@ -1,6 +1,6 @@
(ns quo2.components.messages.system-message
(:require [quo2.components.avatars.icon-avatar :as icon-avatar]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
+1 -1
View File
@@ -1,6 +1,6 @@
(ns quo2.components.navigation.page-nav
(:require [clojure.string :as string]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.buttons.button :as button]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
@@ -33,25 +33,16 @@
:padding-vertical 8
:background-color colors/white-opa-5})
(def buttons-container
(def footer-container
{:margin-top 12
:flex-direction :row
:align-items :flex-start})
(def status
{:margin-top 12
:align-items :flex-start
:flex 1})
:flex-direction :row})
(defn title
[replying?]
{:color colors/white
:flex-shrink 1
:max-width (when-not replying? "60%")})
[]
{:color colors/white})
(def timestamp
{:text-transform :none
:flex-grow 1
:margin-left 8
:color colors/neutral-40})
@@ -75,3 +66,8 @@
(def top-section-container
{:align-items :center
:flex-direction :row})
(def title-container
{:flex 1
:flex-direction :row
:align-items :center})
@@ -7,19 +7,12 @@
[quo2.components.notifications.activity-log.style :as style]
[quo2.components.tags.status-tags :as status-tags]
[quo2.foundations.colors :as colors]
[utils.i18n :as i18n]
[react-native.core :as rn]
[reagent.core :as reagent]
[utils.i18n :as i18n]))
(def ^:private max-reply-length
280)
(defn- valid-reply?
[reply]
(<= (count reply) max-reply-length))
[reagent.core :as reagent]))
(defn- activity-reply-text-input
[reply-input on-update-reply]
[{:keys [on-update-reply max-reply-length valid-reply?]} reply-input]
[rn/view
[rn/view
{:style {:margin-top 16
@@ -99,44 +92,12 @@
body]
body)])
(defn- activity-buttons
[button-1 button-2 replying? reply-input]
(let [size (if replying? 40 24)
common-style (when replying?
{:padding-vertical 9
:flex-grow 1
:flex-basis 0})]
[rn/view style/buttons-container
(when button-1
[button/button
(-> button-1
(assoc :size size)
(update :style merge common-style {:margin-right 8}))
(:label button-1)])
(when button-2
[button/button
(-> button-2
(assoc :size size)
(assoc :disabled (and replying? (not (valid-reply? @reply-input))))
(update :style merge common-style))
(:label button-2)])]))
(defn- activity-status
[status]
[rn/view
{:style style/status
:accessibility-label :activity-status}
[status-tags/status-tag
{:size :small
:label (:label status)
:status status}]])
(defn- activity-title
[title replying?]
[text/text
{:weight :semi-bold
:accessibility-label :activity-title
:style (style/title replying?)
:style (style/title)
:size (if replying? :heading-2 :paragraph-1)}
title])
@@ -155,18 +116,42 @@
:style style/unread-dot-container}
[rn/view {:style style/unread-dot}]])
(defmulti footer-item-view (fn [item _ _] (:type item)))
(defmethod footer-item-view :button
[{:keys [label subtype disable-when] :as button} replying? reply-input]
(let [size (if replying? 40 24)
common-style (when replying?
{:padding-vertical 9
:flex-grow 1
:flex-basis 0})]
[button/button
(-> button
(assoc :size size)
(assoc :type subtype)
(assoc :disabled (and replying? (disable-when @reply-input)))
(update :style merge common-style {:margin-right 8}))
label]))
(defmethod footer-item-view :status
[{:keys [label subtype]} _ _]
[status-tags/status-tag
{:size :small
:label label
:status {:type subtype}}])
(defn- footer
[_]
[_ _]
(let [reply-input (reagent/atom "")]
(fn [{:keys [replying? on-update-reply status button-1 button-2]}]
(fn [{:keys [replying? items] :as props}]
[:<>
(when replying?
[activity-reply-text-input reply-input on-update-reply])
(cond (some? status)
[activity-status status]
(or button-1 button-2)
[activity-buttons button-1 button-2 replying? reply-input])])))
[activity-reply-text-input props reply-input])
(when items
[rn/view style/footer-container
(for [{:keys [key] :as item} items]
^{:key key}
[footer-item-view item replying? reply-input])])])))
(defn view
[{:keys [icon
@@ -179,7 +164,8 @@
:as props}]
[rn/view
{:accessibility-label :activity
:style style/container}
:style style/container
:on-layout (:on-layout props)}
(when-not replying?
[activity-icon icon])
[rn/view
@@ -187,9 +173,10 @@
:flex 1}}
[rn/view
[rn/view {:style style/top-section-container}
[activity-title title replying?]
(when-not replying?
[activity-timestamp timestamp])
[rn/view {:style style/title-container}
[activity-title title replying?]
(when-not replying?
[activity-timestamp timestamp])]
(when (and unread? (not replying?))
[activity-unread-dot])]
(when context
@@ -45,8 +45,8 @@
:else 0))
(def ^:private themes
{:color {:light colors/neutral-80-opa-40
:dark colors/white-opa-40}})
{:color {:dark colors/neutral-80-opa-40
:light colors/white-opa-40}})
(defn circle-timer
[{:keys [color duration size stroke-width trail-color rotation initial-remaining-time]}]
+53 -23
View File
@@ -1,21 +1,25 @@
(ns quo2.components.notifications.toast
(:require [utils.i18n :as i18n]
[quo2.components.icon :as icon]
(:require [quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.notifications.count-down-circle :as count-down-circle]
[quo2.foundations.colors :as colors]
[quo2.foundations.shadows :as shadows]
[quo2.theme :as theme]
[utils.i18n :as i18n]
[react-native.blur :as blur]
[react-native.core :as rn]))
(def ^:private themes
{:container {:dark {:background-color colors/white-opa-70}
:light {:background-color colors/neutral-80-opa-90}}
:light {:background-color colors/neutral-80-opa-70}}
:title {:dark {:color colors/neutral-100}
:light {:color colors/white}}
: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}}})
:action-container {:dark {:background-color colors/neutral-80-opa-5}
:light {:background-color colors/white-opa-5}}})
(defn- merge-theme-style
[component-key styles override-theme]
@@ -51,31 +55,56 @@
[i18n/label :t/undo]]])
(defn- toast-container
[{:keys [left middle right container-style override-theme]}]
[rn/view {:style (merge {:padding-left 12 :padding-right 12} container-style)}
[{:keys [left title text right container-style override-theme]}]
[rn/view
{:style (merge {:margin-horizontal 12
:border-radius 12
:overflow :hidden}
container-style)}
[blur/view
{:style {:height "100%"
:width "100%"
:position :absolute
:padding-vertical 8
:padding-left 10
:padding-right 8
:background-color :transparent}
:blur-amount 13
:blur-radius 10
:blur-type :transparent
:overlay-color :transparent}]
[rn/view
{:style (merge-theme-style :container
{:flex-direction :row
:width "100%"
:margin :auto
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12}
(merge
(:shadow-1 shadows/normal-scale)
{:flex-direction :row
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12})
override-theme)}
[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 {} override-theme)
:accessibility-label :toast-content}
middle]]
(when title
[text/text
{:size :paragraph-1
:weight :semi-bold
:style (merge-theme-style :title {} override-theme)
:accessibility-label :toast-title}
title])
(when text
[text/text
{:size :paragraph-2
:weight :medium
:style (merge-theme-style :text {} override-theme)
:accessibility-label :toast-content}
text])]
(when right right)]])
(defn toast
[{:keys [icon icon-color text action undo-duration undo-on-press container-style override-theme]}]
[{:keys [icon icon-color title text action undo-duration undo-on-press container-style
override-theme]}]
[toast-container
{:left (when icon
[icon/icon icon
@@ -84,7 +113,8 @@
(get-in themes
[:icon (or override-theme (theme/get-theme))
:color]))}])
:middle text
:title title
:text text
:right (if undo-duration
[toast-undo-action undo-duration undo-on-press override-theme]
action)
@@ -1,6 +1,5 @@
(ns quo2.components.onboarding.small-option-card.component-spec
(:require [quo2.components.onboarding.small-option-card.view :as small-option-card]
[status-im.react-native.resources :as resources]
[test-helpers.component :as h]))
(defn- testing-small-option-card
@@ -43,8 +42,7 @@
(-> on-press-fn js/expect .toHaveBeenCalled))))
(h/describe "Image rendered"
(let [image (resources/get-mock-image :small-opt-card-main)
component-props {:image image}]
(let [component-props {:image nil}]
(h/test "`:main` variant"
(h/render (testing-small-option-card :main component-props))
(-> (h/get-by-label-text :small-option-card-main-image) h/expect .-not .toBeNull))
@@ -0,0 +1,20 @@
(ns quo2.components.password.tips.component-spec
(:require [quo2.components.password.tips.view :as quo]
[test-helpers.component :as h]))
(h/describe "password tips component"
(h/test "render component"
(h/render [quo/view])
(-> (h/expect (h/get-by-label-text :password-tips))
(.toBeTruthy)))
(h/test "render component with proper text"
(h/render [quo/view {:completed? false} "Upper case"])
(-> (h/expect (h/get-by-text "Upper case"))
(.toBeTruthy)))
(h/test "render component with completed proper text & completed state"
(h/render [quo/view {:completed? true} "Numbers"])
(-> (h/expect (h/get-by-text "Numbers"))
(.toBeTruthy))
(-> (h/expect (h/get-by-label-text :password-tips-completed))
(.toBeTruthy))))
@@ -0,0 +1,18 @@
(ns quo2.components.password.tips.style
(:require [quo2.foundations.colors :as colors]))
(def container
{:align-self :flex-start})
(defn tip-text
[completed?]
{:color (if completed? colors/white-opa-40 colors/white-opa-70)})
(def strike-through
{:position :absolute
:background-color colors/white
:top 10
:left 0
:right 0
:height 0.8})
@@ -0,0 +1,24 @@
(ns quo2.components.password.tips.view
(:require [react-native.core :as rn]
[quo2.components.password.tips.style :as style]
[quo2.components.markdown.text :as text]))
(defn view
"Options
- `completed?` Password tip state
`text` Password tip string
"
[{:keys [completed?]} text]
[rn/view
{:style style/container
:accessibility-label :password-tips}
[text/text
{:style (style/tip-text completed?)
:weight :regular
:size :paragraph-2} text]
(when completed?
[rn/view
{:style style/strike-through
:accessibility-label :password-tips-completed}])])
@@ -2,7 +2,7 @@
(:require
[quo2.components.profile.profile-card.style :as style]
[quo2.foundations.colors :as colors]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.components.buttons.button :as button]
@@ -25,8 +25,7 @@
:profile-picture profile-picture
:override-theme :dark
:size :medium
:status-indicator? false
:ring? true}]
:status-indicator? false}]
[button/button
{:size 32
:type :blur-bg
@@ -0,0 +1,16 @@
(ns quo2.components.profile.select-profile.component-spec
(:require [quo2.components.profile.select-profile.view :as select-profile]
[test-helpers.component :as h]))
(h/describe "select-profile component"
(h/test "render component"
(h/render [select-profile/view])
(-> (h/expect (h/get-by-label-text :select-profile))
(.toBeTruthy)))
(h/test "call on-change handler when clicked"
(let [on-change (h/mock-fn)]
(h/render [select-profile/view {:on-change on-change}])
(h/fire-event :on-press (h/get-by-label-text :select-profile))
(-> (h/expect on-change)
(.toHaveBeenCalledTimes 1)))))
@@ -0,0 +1,37 @@
(ns quo2.components.profile.select-profile.style
(:require [quo2.foundations.colors :as colors]))
(defn container
[customization-color selected?]
{:padding 12
:background-color (colors/custom-color customization-color 50 40)
:border-width 1
:border-radius 16
:flex 1
:border-color (if selected? colors/white-opa-40 :transparent)})
(def header
{:flex-direction :row
:justify-content :space-between})
(def profile-name
{:margin-top 8
:color colors/white})
(defn select-radio
[selected?]
{:background-color (if selected? :transparent colors/white-opa-5)
:border-width 1.2
:width 20
:height 20
:border-radius 10
:justify-content :center
:align-items :center
:border-color (if selected? colors/white colors/white-opa-40)})
(def select-radio-inner
{:background-color colors/white
:border-radius 7
:width 14
:height 14})
@@ -0,0 +1,54 @@
(ns quo2.components.profile.select-profile.view
(:require
[quo2.components.profile.select-profile.style :as style]
[react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[reagent.core :as reagent]))
(defn- on-change-handler
[selected? on-change]
(swap! selected? not)
(when on-change (on-change @selected?)))
(defn view
"Options
- `default-selected?` The default selected state. Use when the component is not controlled.
- `selected?` Selected state. Use when the component is controlled.
- `name` Full name
- `profile-picture` Profile picture
- `customization-color` Customization color
- `(on-change selected?)` On change event handler
"
[{:keys [default-selected?]}]
(let [internal-selected? (reagent/atom (or default-selected? false))]
(fn [{:keys [selected?
profile-picture
ring-background
name
customization-color
on-change]
:or {customization-color :turquoise}}]
(let [avatar-image-key (if profile-picture :profile-picture :ring-background)
picture (or profile-picture ring-background)]
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
(reset! internal-selected? selected?))
[rn/touchable-opacity
{:style (style/container customization-color @internal-selected?)
:on-press #(on-change-handler internal-selected? on-change)
:active-opacity 1
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
avatar-image-key picture}]
[rn/view {:style (style/select-radio @internal-selected?)}
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]]))))
@@ -1,6 +1,6 @@
(ns quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec
(:require [quo2.components.record-audio.record-audio.view :as record-audio]
[status-im.audio.core :as audio]
[react-native.audio-toolkit :as audio]
[test-helpers.component :as h]))
(h/describe "record audio component"
@@ -20,7 +20,9 @@
(h/test "record-audio on-start-recording works"
(let [event (js/jest.fn)]
(h/render [record-audio/record-audio {:on-start-recording event}])
(h/render [record-audio/record-audio
{:on-start-recording event
:record-audio-permission-granted true}])
(h/fire-event
:on-start-should-set-responder
(h/get-by-test-id "record-audio")
@@ -31,7 +33,9 @@
(h/test "record-audio on-reviewing-audio works"
(let [event (js/jest.fn)]
(h/render [record-audio/record-audio {:on-reviewing-audio event}])
(h/render [record-audio/record-audio
{:on-reviewing-audio event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))]
(h/fire-event
@@ -50,7 +54,9 @@
(h/test "record-audio on-send works after reviewing audio"
(let [event (js/jest.fn)]
(h/render [record-audio/record-audio {:on-send event}])
(h/render [record-audio/record-audio
{:on-send event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
audio/get-recorder-file-path (fn [] "audio-file-path")]
@@ -77,7 +83,9 @@
(h/test "record-audio on-send works after sliding to the send button"
(let [event (js/jest.fn)]
(h/render [record-audio/record-audio {:on-send event}])
(h/render [record-audio/record-audio
{:on-send event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
audio/stop-recording (fn [_ on-stop _]
@@ -108,7 +116,9 @@
(h/test "record-audio on-cancel works after reviewing audio"
(let [event (js/jest.fn)]
(h/render [record-audio/record-audio {:on-cancel event}])
(h/render [record-audio/record-audio
{:on-cancel event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))]
(h/fire-event
@@ -132,7 +142,9 @@
(h/test "cord-audio on-cancel works after sliding to the cancel button"
(let [event (js/jest.fn)]
(h/render [record-audio/record-audio {:on-cancel event}])
(h/render [record-audio/record-audio
{:on-cancel event
:record-audio-permission-granted true}])
(with-redefs [audio/start-recording (fn [_ on-start _]
(on-start))
audio/stop-recording (fn [_ on-stop _]
@@ -4,7 +4,7 @@
[quo2.foundations.colors :as colors]
[react-native.core :as rn :refer [use-effect]]
[react-native.reanimated :as reanimated]
[status-im.audio.core :as audio]
[react-native.audio-toolkit :as audio]
[taoensso.timbre :as log]
[cljs-bean.core :as bean]
[reagent.core :as reagent]
@@ -1,19 +1,14 @@
(ns quo2.components.record-audio.record-audio.view
(:require [cljs-bean.core :as bean]
[oops.core :as oops]
(:require [oops.core :as oops]
[quo2.components.icon :as icons]
[quo2.components.record-audio.record-audio.style :as style]
[quo2.foundations.colors :as colors]
[quo2.components.record-audio.soundtrack.view :as soundtrack]
[react-native.core :as rn :refer [use-effect]]
[reagent.core :as reagent]
[status-im.utils.utils :as utils]
[quo2.components.markdown.text :as text]
[goog.string :as gstring]
[status-im.audio.core :as audio]
[utils.re-frame :as rf]
[utils.i18n :as i18n]
[react-native.permissions :as permissions]
[react-native.audio-toolkit :as audio]
[taoensso.timbre :as log]
[quo2.components.record-audio.record-audio.buttons.record-button-big :as record-button-big]
[quo2.components.record-audio.record-audio.buttons.send-button :as send-button]
@@ -154,7 +149,8 @@
{:color (colors/theme-colors colors/neutral-100 colors/white)}]]))])
(defn view
[{:keys [on-start-recording on-send on-cancel on-reviewing-audio]}]
[{:keys [on-start-recording on-send on-cancel on-reviewing-audio record-audio-permission-granted
on-request-record-audio-permission on-check-audio-permissions]}]
[:f>
(fn []
(let [recording? (reagent/atom false)
@@ -176,29 +172,8 @@
playing-timer (atom nil)
recorder-ref (atom nil)
player-ref (atom nil)
record-audio-permission-granted (atom true)
output-file (atom nil)
reached-max-duration? (atom false)
check-audio-permission
(fn []
(permissions/permission-granted?
:record-audio
#(reset! record-audio-permission-granted %)
#(reset! record-audio-permission-granted false)))
request-record-audio-permission
(fn []
(rf/dispatch
[:request-permissions
{:permissions [:record-audio]
:on-allowed
#(reset! record-audio-permission-granted true)
:on-denied
#(js/setTimeout
(fn []
(utils/show-popup
(i18n/label :t/audio-recorder-error)
(i18n/label :t/audio-recorder-permissions-error)))
50)}]))
destroy-player
(fn []
(audio/destroy-player @player-ref)
@@ -247,7 +222,7 @@
:ignore-max-x? false}
record-button-area)]
(when-not @reviewing-audio?
(if @record-audio-permission-granted
(if record-audio-permission-granted
(do
(when (not @idle?)
(reset! recording? pressed-record-button?))
@@ -294,8 +269,8 @@
#(log/error "[record-audio] start recording - error: " %))
(when on-start-recording
(on-start-recording))))
(request-record-audio-permission)))
(when @record-audio-permission-granted
(some-> on-request-record-audio-permission)))
(when record-audio-permission-granted
(reset! touch-active? true))))
(not @idle?))
on-responder-move
@@ -469,7 +444,7 @@
(reset! reached-max-duration? false)))]
(fn []
(use-effect (fn []
(check-audio-permission)
(some-> on-check-audio-permissions)
(reload-recorder)))
[rn/view
{:style style/bar-container}
@@ -515,14 +490,4 @@
on-cancel]
[record-button/record-button recording? reviewing-audio?]]])))])
(def record-audio
(reagent/adapt-react-class
(rn/memo
(fn [props]
(let [{:keys [onStartRecording onReviewingAudio onSend onCancel]} (bean/bean props)]
(reagent/as-element
[view
{:on-start-recording onStartRecording
:on-reviewing-audio onReviewingAudio
:on-send onSend
:on-cancel onCancel}]))))))
(def record-audio view)
@@ -2,7 +2,7 @@
(:require [quo2.components.record-audio.soundtrack.view :as soundtrack]
[test-helpers.component :as h]
[reagent.core :as reagent]
[status-im.audio.core :as audio]))
[react-native.audio-toolkit :as audio]))
(h/describe "soundtrack component"
(h/before-each
@@ -1,7 +1,7 @@
(ns quo2.components.record-audio.soundtrack.view
(:require [quo2.components.record-audio.soundtrack.style :as style]
[quo2.foundations.colors :as colors]
[status-im.audio.core :as audio]
[react-native.audio-toolkit :as audio]
[taoensso.timbre :as log]
[react-native.platform :as platform]
[react-native.slider :as slider]))
+1 -1
View File
@@ -159,7 +159,7 @@
;; {:overflow :visible} doesn't work on components inheriting
;; from ScrollView (e.g. FlatList). There are open issues, here's
;; just one about this topic:
;; https://github.com/facebook/react-native/issues/3121
;; https://github.com/facebook/react-native/issues/31218
:content-container-style {:padding-top (dec unread-count-offset)}
:extra-data (str @active-tab-id)
:horizontal true
+6 -10
View File
@@ -12,7 +12,7 @@
(def small-container-style
(merge default-container-style
{:padding-horizontal 8
:padding-vertical 3}))
:padding-vertical 1}))
(def large-container-style
(merge default-container-style
@@ -56,8 +56,8 @@
[size theme label]
[base-tag
{:size size
:background-color colors/success-50-opa-10
:icon :verified
:background-color colors/success-50-opa-10
:border-color colors/success-50-opa-20
:label label
:text-color (if (= theme :light)
@@ -77,18 +77,14 @@
colors/danger-60)}])
(defn- pending
[size theme label]
[size _ label]
[base-tag
{:size size
:icon :pending
:label label
:background-color (if (= theme :light)
colors/neutral-10
colors/neutral-80)
:border-color (if (= theme :light)
colors/neutral-20
colors/neutral-70)
:text-color colors/neutral-50}])
:background-color colors/white-opa-5
:border-color colors/white-opa-5
:text-color colors/white-opa-70}])
(defn status-tag
[{:keys [status size override-theme label]}]
+22 -4
View File
@@ -5,11 +5,12 @@
quo2.components.avatars.channel-avatar
quo2.components.avatars.group-avatar
quo2.components.avatars.icon-avatar
quo2.components.avatars.user-avatar
quo2.components.avatars.user-avatar.view
quo2.components.avatars.wallet-user-avatar
quo2.components.banners.banner.view
quo2.components.buttons.button
quo2.components.buttons.dynamic-button
quo2.components.colors.color-picker.view
quo2.components.community.community-card-view
quo2.components.community.community-list-view
quo2.components.community.community-view
@@ -20,6 +21,7 @@
quo2.components.dividers.date
quo2.components.dividers.divider-label
quo2.components.dividers.new-messages
quo2.components.dividers.strength-divider.view
quo2.components.drawers.action-drawers.view
quo2.components.drawers.drawer-buttons.view
quo2.components.drawers.permission-context.view
@@ -28,6 +30,7 @@
quo2.components.icon
quo2.components.info.info-message
quo2.components.info.information-box
quo2.components.input.view
quo2.components.list-items.channel
quo2.components.list-items.menu-item
quo2.components.list-items.preview-list
@@ -43,7 +46,9 @@
quo2.components.notifications.info-count
quo2.components.notifications.notification-dot
quo2.components.notifications.toast
quo2.components.password.tips.view
quo2.components.profile.profile-card.view
quo2.components.profile.select-profile.view
quo2.components.reactions.reaction
quo2.components.selectors.disclaimer.view
quo2.components.selectors.filter.view
@@ -59,7 +64,8 @@
quo2.components.tags.permission-tag
quo2.components.tags.tag
quo2.components.tags.tags
quo2.components.tags.token-tag))
quo2.components.tags.token-tag
quo2.components.list-items.user-list))
(def toast quo2.components.notifications.toast/toast)
(def button quo2.components.buttons.button/button)
@@ -90,14 +96,13 @@
(def filter quo2.components.selectors.filter.view/view)
(def skeleton quo2.components.loaders.skeleton/skeleton)
(def author quo2.components.messages.author.view/author)
(def display-name quo2.components.messages.author.view/display-name)
;;;; AVATAR
(def account-avatar quo2.components.avatars.account-avatar/account-avatar)
(def channel-avatar quo2.components.avatars.channel-avatar/channel-avatar)
(def group-avatar quo2.components.avatars.group-avatar/group-avatar)
(def icon-avatar quo2.components.avatars.icon-avatar/icon-avatar)
(def user-avatar quo2.components.avatars.user-avatar/user-avatar)
(def user-avatar quo2.components.avatars.user-avatar.view/user-avatar)
(def wallet-user-avatar quo2.components.avatars.wallet-user-avatar/wallet-user-avatar)
;;;; BANNER
@@ -106,6 +111,10 @@
;;;; CARDS
(def small-option-card quo2.components.onboarding.small-option-card.view/small-option-card)
;;;; COLORS
(def color-picker quo2.components.colors.color-picker.view/view)
(def picker-colors quo2.components.colors.color-picker.view/picker-colors)
;;;; COMMUNITY
(def community-card-view-item quo2.components.community.community-card-view/community-card-view-item)
(def communities-list-view-item quo2.components.community.community-list-view/communities-list-view-item)
@@ -124,16 +133,21 @@
(def divider-label quo2.components.dividers.divider-label/divider-label)
(def new-messages quo2.components.dividers.new-messages/new-messages)
(def divider-date quo2.components.dividers.date/date)
(def strength-divider quo2.components.dividers.strength-divider.view/view)
;;;; DRAWERS
(def action-drawer quo2.components.drawers.action-drawers.view/action-drawer)
(def drawer-buttons quo2.components.drawers.drawer-buttons.view/view)
(def permission-context quo2.components.drawers.permission-context.view/view)
;;;; INPUTS
(def input quo2.components.input.view/input)
;;;; LIST ITEMS
(def channel-list-item quo2.components.list-items.channel/list-item)
(def menu-item quo2.components.list-items.menu-item/menu-item)
(def preview-list quo2.components.list-items.preview-list/preview-list)
(def user-list quo2.components.list-items.user-list/user-list)
;;;; NOTIFICATIONS
(def activity-log quo2.components.notifications.activity-log.view/view)
@@ -141,8 +155,12 @@
(def notification-dot quo2.components.notifications.notification-dot/notification-dot)
(def count-down-circle quo2.components.notifications.count-down-circle/circle-timer)
;;;; PASSWORD
(def tips quo2.components.password.tips.view/view)
;;;; PROFILE
(def profile-card quo2.components.profile.profile-card.view/profile-card)
(def select-profile quo2.components.profile.select-profile.view/view)
;;;; SETTINGS
(def privacy-option quo2.components.settings.privacy-option/card)
+6 -1
View File
@@ -1,14 +1,19 @@
(ns quo2.core-spec
(:require [quo2.components.banners.banner.component-spec]
(:require [quo2.components.avatars.user-avatar.component-spec]
[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.dividers.strength-divider.component-spec]
[quo2.components.drawers.action-drawers.component-spec]
[quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.permission-context.component-spec]
[quo2.components.colors.color-picker.component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
[quo2.components.password.tips.component-spec]
[quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec]
[quo2.components.record-audio.soundtrack.--tests--.soundtrack-component-spec]
[quo2.components.profile.select-profile.component-spec]
[quo2.components.selectors.--tests--.selectors-component-spec]
[quo2.components.selectors.filter.component-spec]))
+31 -12
View File
@@ -60,6 +60,7 @@
;;Blur
(def neutral-5-opa-70 (alpha neutral-5 0.7))
(def neutral-80-blur-opa-80 "rgba(25,36,56,0.8)")
(def neutral-90-opa-70 (alpha neutral-90 0.7))
;;80 with transparency
@@ -152,6 +153,10 @@
(def success-60-opa-40 (alpha success-60 0.4))
;;;;Danger
(def danger "#E95460")
;; Danger with transparency
(def danger-opa-40 (alpha danger 0.4))
;;Solid
(def danger-50 "#E65F5C")
@@ -170,26 +175,40 @@
(def customization
{:primary {50 primary-50 ;; User can also use primary color as customisation color
60 primary-60}
:purple {50 "#8661C1"
60 "#5E478C"}
:purple {50 "#7140FD"
60 "#5A33CA"}
:indigo {50 "#496289"
60 "#3D5273"}
:turquoise {50 "#448EA2"
60 "#397788"}
:blue {50 "#4CB4EF"
60 "#4097C9"}
:turquoise {50 "#2A799B"
60 "#22617C"}
:blue {50 "#2A4AF5"
60 "#223BC4"}
:green {50 "#5BCC95"
60 "#4CAB7D"}
:yellow {50 "#FFCB53"
60 "#D6AA46"}
:orange {50 "#FB8F61"
60 "#D37851"}
:yellow {50 "#F6B03C"
60 "#C58D30"}
:orange {50 "#FF7D46"
60 "#CC6438"}
:red {50 "#F46666"
60 "#CD5656"}
:pink {50 "#FC7BAB"
60 "#D46790"}
:pink {50 "#F66F8F"
60 "#C55972"}
:brown {50 "#99604D"
60 "#805141"}
:sky {50 "#1992D7"
60 "#1475AC"}
:army {50 "#216266"
60 "#1A4E52"}
:magenta {50 "#EC266C"
60 "#BD1E56"}
:copper {50 "#CB6256"
60 "#A24E45"}
:camel {50 "#C78F67"
60 "#9F7252"}
:yin {50 "#09101C"
60 "#1D232E"}
:yang {50 "#FFFFFF"
60 "#EBEBEB"}
:beige {50 "#CAAE93"
60 "#AA927C"}})
@@ -1,4 +1,4 @@
(ns status-im.audio.core
(ns react-native.audio-toolkit
(:require ["@react-native-community/audio-toolkit" :refer (Player Recorder MediaStates)]))
;; get mediastates from react module
+4
View File
@@ -10,6 +10,10 @@
(def app-state ^js (.-AppState ^js react-native))
;; Only use this component for exceptional cases, otherwise use Reanimated, e.g.
;; when using interpolated values exposed by RN Gesture Handler > Swipeable.
(def animated-view (reagent/adapt-react-class react-native/Animated.View))
(def view (reagent/adapt-react-class (.-View ^js react-native)))
(def scroll-view (reagent/adapt-react-class (.-ScrollView ^js react-native)))
(def image (reagent/adapt-react-class (.-Image ^js react-native)))
+2 -2
View File
@@ -19,8 +19,8 @@
(defn- wrap-key-fn
[f]
(fn [data index]
{:post [(some? %)]}
(f data index)))
(when f
(f data index))))
(defn base-list-props
[{:keys [key-fn render-fn empty-component header footer separator data render-data on-drag-end-fn]
+53 -15
View File
@@ -1,27 +1,65 @@
(ns react-native.gesture
(:require ["react-native-gesture-handler" :refer
(GestureDetector Gesture gestureHandlerRootHOC TapGestureHandler State)]
[reagent.core :as reagent]
[oops.core :refer [oget]]))
(Gesture
GestureDetector
RectButton
Swipeable
TouchableWithoutFeedback
gestureHandlerRootHOC)]
[reagent.core :as reagent]))
(def gesture-detector (reagent/adapt-react-class GestureDetector))
(def gesture-handler-root-hoc gestureHandlerRootHOC)
(defn gesture-tap [] (.Tap ^js Gesture))
(defn gesture-pan [] (.Pan ^js Gesture))
(defn on-update [^js pan handler] (.onUpdate pan handler))
(defn gesture-pinch [] (.Pinch ^js Gesture))
(defn on-start [^js pan handler] (.onStart pan handler))
(defn on-begin [gesture handler] (.onBegin ^js gesture handler))
(defn on-end [^js pan handler] (.onEnd pan handler))
(defn on-start [gesture handler] (.onStart ^js gesture handler))
(def tap-gesture-handler
(reagent/adapt-react-class TapGestureHandler))
(defn on-update [gesture handler] (.onUpdate ^js gesture handler))
(def states
{:began (oget State "BEGAN")
:active (oget State "ACTIVE")
:cancelled (oget State "CANCELLED")
:end (oget State "END")
:failed (oget State "FAILED")
:undetermined (oget State "UNDETERMINED")})
(defn on-end [gesture handler] (.onEnd ^js gesture handler))
(defn on-finalize [gesture handler] (.onFinalize ^js gesture handler))
(defn number-of-taps [gesture count] (.numberOfTaps ^js gesture count))
(defn enabled [gesture enabled?] (.enabled ^js gesture enabled?))
(defn average-touches [gesture average-touches?] (.averageTouches ^js gesture average-touches?))
(defn simultaneous
([g1 g2] (.Simultaneous ^js Gesture g1 g2))
([g1 g2 g3] (.Simultaneous ^js Gesture g1 g2 g3)))
(defn exclusive [g1 g2] (.Exclusive ^js Gesture g1 g2))
;; RN Gesture Handler touchables are drop-in replacements for the RN ones. In
;; some cases, it's the only touchable that works with Swipeable components.
(def touchable-without-feedback (reagent/adapt-react-class TouchableWithoutFeedback))
(def rect-button (reagent/adapt-react-class RectButton))
(def ^:private swipeable-component
(reagent/adapt-react-class Swipeable))
(defn swipeable
[{:keys [render-left-actions render-right-actions] :as props} & children]
(into [swipeable-component
(cond-> props
render-left-actions
(assoc :render-left-actions
(fn [& args]
(reagent/as-element (apply render-left-actions args))))
render-right-actions
(assoc :render-right-actions
(fn [& args]
(reagent/as-element (apply render-right-actions args)))))]
children))
+32
View File
@@ -0,0 +1,32 @@
(ns react-native.orientation
(:require ["react-native-orientation-locker" :default orientation :refer (useDeviceOrientationChange)]
[react-native.navigation :as navigation]))
(def use-device-orientation-change useDeviceOrientationChange)
(def get-auto-rotate-state (.-getAutoRotateState orientation))
(def portrait-options
(clj->js {:layout {:orientation ["portrait"]}
:statusBar {:visible true}}))
(def landscape-option-1 (clj->js {:layout {:orientation ["landscape"]}}))
(def landscape-option-2 (clj->js {:statusBar {:visible false}}))
(defn lock-to-portrait
[id]
(navigation/merge-options id portrait-options))
(defn lock-to-landscape
[id]
(navigation/merge-options id landscape-option-1)
;; On Android, hiding the status-bar while changing orientation causes a flicker, so we enqueue it
(js/setTimeout #(navigation/merge-options id landscape-option-2) 0))
(def ^:const portrait "PORTRAIT")
(def ^:const landscape "LANDSCAPE")
(def ^:const landscape-left "LANDSCAPE-LEFT")
(def ^:const landscape-right "LANDSCAPE-RIGHT")
+26 -1
View File
@@ -9,6 +9,7 @@
withDelay
withSpring
withRepeat
withDecay
Easing
Keyframe
cancelAnimation
@@ -48,6 +49,7 @@
(def with-timing withTiming)
(def with-delay withDelay)
(def with-spring withSpring)
(def with-decay withDecay)
(def key-frame Keyframe)
(def with-repeat withRepeat)
(def cancel-animation cancelAnimation)
@@ -55,9 +57,12 @@
;; Easings
(def bezier (.-bezier ^js Easing))
(def in-out
(.-inOut ^js Easing))
(def easings
{:linear (bezier 0 0 1 1)
:easing1 (bezier 0.25 0.1 0.25 1) ;; TODO(parvesh) - rename easing functions, (design team input)
:easing1 (bezier 0.25 0.1 0.25 1)
:easing2 (bezier 0 0.3 0.6 0.9)
:easing3 (bezier 0.3 0.3 0.3 0.9)})
@@ -107,6 +112,14 @@
(js-obj "duration" duration
"easing" (get easings easing))))))
(defn animate-shared-value-with-delay-default-easing
[anim val duration delay]
(set-shared-value anim
(with-delay delay
(with-timing val
(js-obj "duration" duration
"easing" (in-out (.-quad ^js Easing)))))))
(defn animate-shared-value-with-repeat
[anim val duration easing number-of-repetitions reverse?]
(set-shared-value anim
@@ -137,3 +150,15 @@
(js-obj "mass" mass
"damping" damping
"stiffness" stiffness))))
(defn animate-shared-value-with-decay
[anim velocity clamp]
(set-shared-value anim
(with-decay (clj->js {:velocity velocity
:clamp clamp}))))
(defn with-timing-duration
[val duration]
(with-timing val
(clj->js {:duration duration
:easing (in-out (.-quad ^js Easing))})))
+2
View File
@@ -7,3 +7,5 @@
(def rect (reagent/adapt-react-class Svg/Rect))
(def clippath (reagent/adapt-react-class Svg/ClipPath))
(def defs (reagent/adapt-react-class Svg/Defs))
(def circle (reagent/adapt-react-class Svg/Circle))
+2 -2
View File
@@ -3,7 +3,7 @@
[re-frame.core :as re-frame]
[status-im.add-new.db :as db]
[status-im2.contexts.chat.events :as chat]
[status-im.contact.core :as contact]
[status-im2.contexts.contacts.events :as contact]
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.ens :as ens]
[status-im.ethereum.stateofus :as stateofus]
@@ -91,7 +91,7 @@
(i18n/label :t/use-valid-contact-code)
:yourself
(i18n/label :t/can-not-add-yourself))
:on-dismiss #(re-frame/dispatch [:pop-to-root-tab :shell-stack])}})))
:on-dismiss #(re-frame/dispatch [:pop-to-root :shell-stack])}})))
(rf/defn qr-code-scanned
{:events [:contact/qr-code-scanned]}
+16 -7
View File
@@ -305,9 +305,10 @@
(rf/merge cofx
{:db (assoc db
:browser/options
{:browser-id (:browser-id browser)})}
(navigation/change-tab :browser)
(navigation/set-stack-root :browser-stack :browser)
{:browser-id (:browser-id browser)}
:browser/screen-id :browser)}
(navigation/pop-to-root :shell-stack)
(navigation/change-tab :browser-stack)
(update-browser browser)
(resolve-url nil)))))
@@ -319,11 +320,19 @@
(rf/merge cofx
{:db (assoc db
:browser/options
{:browser-id browser-id})}
{:browser-id browser-id}
:browser/screen-id :browser)}
(update-browser browser)
(navigation/set-stack-root :browser-stack :browser)
(navigation/change-tab :browser-stack)
(resolve-url nil))))
(rf/defn open-browser-tabs
{:events [:browser.ui/open-browser-tabs]}
[{:keys [db] :as cofx}]
(rf/merge cofx
{:db (assoc db :browser/screen-id :browser-tabs)}
(navigation/change-tab :browser-stack)))
(rf/defn web3-error-callback
{:events [:browser.dapp/transaction-on-error]}
[_ message-id message]
@@ -573,9 +582,9 @@
(rf/defn open-empty-tab
{:events [:browser.ui/open-empty-tab]}
[cofx]
[{:keys [db]}]
(debounce/clear :browser/navigation-state-changed)
(navigation/set-stack-root cofx :browser-stack :empty-tab))
{:db (assoc db :browser/screen-id :empty-tab)})
(rf/defn url-input-pressed
{:events [:browser.ui/url-input-pressed]}
+7 -3
View File
@@ -31,7 +31,9 @@
(fn [^js resized-image]
(let [path (.-path resized-image)
path (if (string/starts-with? path "file") path (str "file://" path))]
(cb path)))
(cb {:resized-uri path
:width width
:height height})))
#(log/error "could not resize image" %))))))
(defn result->id
@@ -238,13 +240,15 @@
(rf/defn image-selected
{:events [:chat.ui/image-selected]}
[{:keys [db]} current-chat-id original uri]
[{:keys [db]} current-chat-id original {:keys [resized-uri width height]}]
{:db
(update-in db
[:chat/inputs current-chat-id :metadata :sending-image (:uri original)]
merge
original
{:resized-uri uri})})
{:resized-uri resized-uri
:width width
:height height})})
(rf/defn image-unselected
{:events [:chat.ui/image-unselected]}
+6 -7
View File
@@ -41,11 +41,11 @@
(rf/defn select-mention
{:events [:chat.ui/select-mention]}
[{:keys [db] :as cofx} text-input-ref {:keys [alias name searched-text match] :as user}]
[{:keys [db] :as cofx} text-input-ref {:keys [primary-name searched-text match] :as user}]
(let [chat-id (:current-chat-id db)
new-text (mentions/new-input-text-with-mention cofx user)
at-sign-idx (get-in db [:chats/mentions chat-id :mentions :at-sign-idx])
cursor (+ at-sign-idx (count name) 2)]
cursor (+ at-sign-idx (count primary-name) 2)]
(rf/merge
cofx
{:db (-> db
@@ -63,15 +63,14 @@
;; NOTE(roman): on-text-input event is not dispatched when we change input
;; programmatically, so we have to call `on-text-input` manually
(mentions/on-text-input
(let [match-len (count match)
searched-text-len (count searched-text)
start (inc at-sign-idx)
end (+ start match-len)]
(let [match-len (count match)
start (inc at-sign-idx)
end (+ start match-len)]
{:new-text match
:previous-text searched-text
:start start
:end end}))
(mentions/recheck-at-idxs {alias user}))))
(mentions/recheck-at-idxs {primary-name user}))))
(rf/defn disable-chat-cooldown
"Turns off chat cooldown (protection against message spamming)"
+18 -20
View File
@@ -120,7 +120,7 @@
(get-in db [:pagination-info chat-id :messages-initialized?])))
(let [already-loaded-messages (get-in db [:messages chat-id])
;; We remove those messages that are already loaded, as we might get some duplicates
{:keys [all-messages new-messages senders contacts]}
{:keys [all-messages new-messages contacts]}
(reduce (fn [{:keys [all-messages] :as acc}
{:keys [message-id from]
:as message}]
@@ -143,25 +143,23 @@
:cursor-clock-value])
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]
#(if (and (seq cursor) (or (not %) (< clock-value %)))
clock-value
%))
(update-in [:pagination-info chat-id :cursor]
#(if (or (empty? cursor)
(not current-clock-value)
(< clock-value current-clock-value))
cursor
%))
(assoc-in [:pagination-info chat-id :loading-messages?] false)
(assoc-in [:messages chat-id] all-messages)
(update-in [:message-lists chat-id] message-list/add-many new-messages)
(assoc-in [:pagination-info chat-id :all-loaded?]
(empty? cursor))
(update :contacts/contacts merge contacts))})))
{:db (-> db
(update-in [:pagination-info chat-id :cursor-clock-value]
#(if (and (seq cursor) (or (not %) (< clock-value %)))
clock-value
%))
(update-in [:pagination-info chat-id :cursor]
#(if (or (empty? cursor)
(not current-clock-value)
(< clock-value current-clock-value))
cursor
%))
(assoc-in [:pagination-info chat-id :loading-messages?] false)
(assoc-in [:messages chat-id] all-messages)
(update-in [:message-lists chat-id] message-list/add-many new-messages)
(assoc-in [:pagination-info chat-id :all-loaded?]
(empty? cursor))
(update :contacts/contacts merge contacts))})))
(rf/defn load-more-messages
{:events [:chat.ui/load-more-messages]}
+38 -71
View File
@@ -9,13 +9,10 @@
[status-im.native-module.core :as status]
[utils.re-frame :as rf]
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
(def at-sign "@")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn re-pos
[re s]
(loop [res []
@@ -177,43 +174,25 @@
:else (recur data (inc idx)))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn add-searchable-phrases
[{:keys [alias name nickname] :as user}]
(reduce
(fn [user s]
(if (nil? s)
user
(let [new-words (concat
[s]
(rest (string/split s " ")))]
(update user :searchable-phrases (fnil concat []) new-words))))
user
[alias name nickname]))
(defn add-searchable-phrases-to-contact
[{:keys [alias name added? blocked? identicon public-key nickname ens-verified]} community-chat?]
(when (and alias
(not (string/blank? alias))
(or name
nickname
added?
community-chat?)
(not blocked?))
(add-searchable-phrases
{:alias alias
:name (or (and ens-verified (utils/safe-replace name ".stateofus.eth" "")) alias)
:identicon identicon
:nickname nickname
:ens-verified ens-verified
:public-key public-key})))
[{:keys [primary-name secondary-name blocked?] :as contact}]
(when (not blocked?)
(reduce
(fn [user s]
(if (nil? s)
user
(let [new-words (concat
[s]
(rest (string/split s " ")))]
(update user :searchable-phrases (fnil concat []) new-words))))
contact
[primary-name secondary-name])))
(defn mentionable-contacts
[contacts]
(reduce
(fn [acc [key contact]]
(let [mentionable-contact (add-searchable-phrases-to-contact contact false)]
(let [mentionable-contact (add-searchable-phrases-to-contact contact)]
(if (nil? mentionable-contact)
acc
(assoc acc key mentionable-contact))))
@@ -223,17 +202,8 @@
(defn mentionable-contacts-from-identites
[contacts my-public-key identities]
(reduce (fn [acc identity]
(let [contact (multiaccounts/contact-by-identity
contacts
identity)
contact (if (string/blank? (:alias contact))
(assoc contact
:alias
(get-in contact [:names :three-words-name]))
contact)
mentionable-contact (add-searchable-phrases-to-contact
contact
true)]
(let [contact (multiaccounts/contact-by-identity contacts identity)
mentionable-contact (add-searchable-phrases-to-contact contact)]
(if (nil? mentionable-contact)
acc
(assoc acc identity mentionable-contact))))
@@ -247,9 +217,9 @@
mentionable-contacts (mentionable-contacts all-contacts)
mentionable-users (assoc users
public-key
{:alias name
:name (or preferred-name name)
:public-key public-key})]
{:secondary-name name
:primary-name (or preferred-name name)
:public-key public-key})]
(cond
(= chat-type constants/private-group-chat-type)
(merge mentionable-users
@@ -273,30 +243,31 @@
(= chat-type constants/public-chat-type)
(merge mentionable-users (select-keys mentionable-contacts (keys mentionable-users)))
:else mentionable-users)))
:else
mentionable-users)))
(def ending-chars "[\\s\\.,;:]")
(def ending-chars-regex (re-pattern ending-chars))
(def word-regex (re-pattern (str "^[\\w\\d]*" ending-chars "|^[\\S]*$")))
(defn mentioned?
[{:keys [alias name]} text]
(let [lcase-name (string/lower-case name)
lcase-alias (string/lower-case alias)
[{:keys [primary-name secondary-name]} text]
(let [lcase-fname (string/lower-case primary-name)
lcase-sname (when secondary-name (string/lower-case secondary-name))
regex (re-pattern
(string/join
"|"
[(str "^" lcase-name ending-chars)
(str "^" lcase-name "$")
(str "^" lcase-alias ending-chars)
(str "^" lcase-alias "$")]))
[(str "^" lcase-fname ending-chars)
(str "^" lcase-fname "$")
(str "^" lcase-sname ending-chars)
(str "^" lcase-sname "$")]))
lcase-text (string/lower-case text)]
(re-find regex lcase-text)))
(defn get-user-suggestions
[users searched-text]
(reduce
(fn [acc [k {:keys [alias name nickname searchable-phrases] :as user}]]
(fn [acc [k {:keys [primary-name secondary-name searchable-phrases] :as user}]]
(if-let [match
(if (seq searchable-phrases)
(when (some
@@ -305,27 +276,23 @@
(string/lower-case s)
searched-text))
searchable-phrases)
(or name alias))
(or primary-name secondary-name))
(cond
(and nickname
(and primary-name
(string/starts-with?
(string/lower-case nickname)
(string/lower-case primary-name)
searched-text))
(or name alias)
(or primary-name secondary-name)
(and alias
(and secondary-name
(string/starts-with?
(string/lower-case alias)
(string/lower-case secondary-name)
searched-text))
alias
(string/starts-with?
(string/lower-case name)
searched-text)
name))]
secondary-name))]
(assoc acc
k
(assoc user
:key k
:match match
:searched-text searched-text))
acc))
@@ -642,7 +609,7 @@
(assoc-in [:chats/mention-suggestions chat-id] mentions))}))))
(defn new-input-text-with-mention
[{:keys [db]} {:keys [name]}]
[{:keys [db]} {:keys [primary-name]}]
(let [chat-id (:current-chat-id db)
text (get-in db [:chat/inputs chat-id :input-text])
{:keys [mention-end at-sign-idx]}
@@ -652,7 +619,7 @@
new-input-text-with-mention)
(string/join
[(subs text 0 (inc at-sign-idx))
name
primary-name
(let [next-char (get text mention-end)]
(when (or (not next-char)
(and next-char
+9 -9
View File
@@ -9,6 +9,7 @@
"@helpinghand.eth"]
[:text
" "]])
(def ->info-expected
{:at-sign-idx 2
:mention-end 19
@@ -75,17 +76,16 @@
(test/deftest test-replace-mentions
(let [users {"User Number One"
{:name "User Number One"
:alias "User Number One"
:public-key "0xpk1"}
{:primary-name "User Number One"
:public-key "0xpk1"}
"User Number Two"
{:name "user2"
:alias "User Number Two"
:public-key "0xpk2"}
{:primary-name "user2"
:secondary-name "User Number Two"
:public-key "0xpk2"}
"User Number Three"
{:name "user3"
:alias "User Number Three"
:public-key "0xpk3"}}]
{:primary-name "user3"
:secondary-name "User Number Three"
:public-key "0xpk3"}}]
(test/testing "empty string"
(let [text ""
result (mentions/replace-mentions text users)]
+2 -26
View File
@@ -2,10 +2,8 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.chat.models.loading :as chat.loading]
[status-im.chat.models.mentions :as mentions]
[status-im.data-store.messages :as data-store.messages]
[status-im.transport.message.protocol :as protocol]
[status-im.utils.gfycat.core :as gfycat]
[status-im.utils.platform :as platform]
[status-im.utils.types :as types]
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
@@ -34,26 +32,6 @@
;; TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
(message-list/rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id))
(rf/defn add-senders-to-chat-users
{:events [:chat/add-senders-to-chat-users]}
[{:keys [db]} messages]
(reduce (fn [acc {:keys [chat-id alias name identicon from]}]
(let [alias (if (string/blank? alias)
(gfycat/generate-gfy from)
alias)]
(update-in acc
[:db :chats chat-id :users]
assoc
from
(mentions/add-searchable-phrases
{:alias alias
:name (or name alias)
:identicon identicon
:public-key from
:nickname (get-in db [:contacts/contacts from :nickname])}))))
{:db db}
messages))
(defn add-message
[{:keys [db] :as acc} message-js chat-id message-id cursor-clock-value]
(let [{:keys [replace from clock-value] :as message}
@@ -118,7 +96,7 @@
(defn receive-many
[{:keys [db]} ^js response-js]
(let [messages-js ^js (.splice (.-messages response-js) 0 (if platform/low-device? 3 10))
{:keys [db senders]}
{:keys [db]}
(reduce reduce-js-messages
{:db db :chats #{} :senders {} :transactions #{}}
messages-js)]
@@ -128,9 +106,7 @@
:utils/dispatch-later
(concat [{:ms 20 :dispatch [:process-response response-js]}]
(when (and (:current-chat-id db) (= "active" (:app-state db)))
[{:ms 100 :dispatch [:chat/mark-all-as-read (:current-chat-id db)]}])
(when (seq senders)
[{:ms 100 :dispatch [:chat/add-senders-to-chat-users (vals senders)]}]))}))
[{:ms 100 :dispatch [:chat/mark-all-as-read (:current-chat-id db)]}]))}))
(rf/defn update-db-message-status
[{:keys [db] :as cofx} chat-id message-id status]
+15 -11
View File
@@ -4,17 +4,17 @@
[clojure.walk :as walk]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[utils.i18n :as i18n]
[status-im.async-storage.core :as async-storage]
[status-im2.common.bottom-sheet.events :as bottom-sheet]
[status-im2.constants :as constants]
[status-im.ui.components.emoji-thumbnail.styles :as emoji-thumbnail-styles]
[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.bottom-sheet.events :as bottom-sheet]
[status-im2.common.toasts.events :as toasts]
[status-im2.constants :as constants]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def crop-size 1000)
@@ -71,7 +71,11 @@
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?})
:isMember :is-member?
:adminSettings :admin-settings})
(update :admin-settings
set/rename-keys
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :categories <-categories-rpc)))
@@ -115,7 +119,7 @@
(let [community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :placeholder
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/left-community {:community community-name})})
(navigation/navigate-back)
@@ -128,7 +132,7 @@
community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :placeholder
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label (if (= event-name ::joined)
:t/joined-community
@@ -427,7 +431,7 @@
(navigation/navigate-to :community-create nil)))
(rf/defn open-edit-community
{:events [::open-edit-community]}
{:events [::open-edit-community :communities/open-edit-community]}
[{:keys [db] :as cofx} id]
(let [{:keys [name description images permissions color]} (get-in db [:communities id])
{:keys [access]} permissions]
@@ -742,7 +746,7 @@
{:events [:communities/navigate-to-community]}
[cofx community-id]
(rf/merge cofx
(navigation/pop-to-root-tab :shell-stack)
(navigation/pop-to-root :shell-stack)
(navigation/navigate-to-nav2 :community community-id true)))
(rf/defn member-role-updated
+16 -22
View File
@@ -3,14 +3,14 @@
[status-im2.contexts.chat.messages.list.events :as message-list]
[status-im.contact.db :as contact.db]
[status-im.data-store.chats :as chats-store]
[status-im.data-store.contacts :as contacts-store]
[status-im2.contexts.contacts.events :as contacts-store]
[utils.re-frame :as rf]
[status-im.utils.types :as types]
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]))
(rf/defn clean-up-chat
[{:keys [db] :as cofx}
[{:keys [db]}
public-key
{:keys [chat-id
unviewed-messages-count
@@ -35,18 +35,18 @@
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))}))
(rf/defn contact-blocked
{:events [::contact-blocked]}
[{:keys [db] :as cofx} {:keys [public-key]} chats]
(let [fxs (when chats
{:events [:contacts/blocked]}
[{:keys [db] :as cofx} {:keys [public-key]} chats-js]
(let [fxs (when chats-js
(map #(->> (chats-store/<-rpc %)
(clean-up-chat public-key))
(types/js->clj chats)))]
(types/js->clj chats-js)))]
(apply rf/merge
cofx
{:db (-> db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key :added] false))
(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?])]}
@@ -59,34 +59,28 @@
(let [contact (-> (contact.db/public-key->contact
(:contacts/contacts db)
public-key)
(assoc :blocked true
:added false))
(assoc :blocked? true
:added? false))
from-one-to-one-chat? (not (get-in db [:chats (:current-chat-id db) :group-chat]))]
(rf/merge cofx
{:db (-> db
;; add the contact to blocked contacts
(update :contacts/blocked (fnil conj #{}) public-key)
;; update the contact in contacts list
(assoc-in [:contacts/contacts public-key] contact))}
{:db (assoc-in db [:contacts/contacts public-key] contact)}
(contacts-store/block
public-key
(fn [^js block-contact]
(re-frame/dispatch [::contact-blocked contact (.-chats block-contact)])
(re-frame/dispatch [:contacts/blocked contact (.-chats block-contact)])
(re-frame/dispatch [:sanitize-messages-and-process-response block-contact])
(re-frame/dispatch [:hide-popover])))
;; reset navigation to avoid going back to non existing one to one chat
(if from-one-to-one-chat?
(navigation/pop-to-root-tab :shell-stack)
(navigation/pop-to-root :shell-stack)
(navigation/navigate-back)))))
(rf/defn contact-unblocked
{:events [::contact-unblocked]}
{:events [:contacts/unblocked]}
[{:keys [db]} contact-id]
(let [contact (-> (get-in db [:contacts/contacts contact-id])
(assoc :blocked false))]
{:db (-> db
(update :contacts/blocked disj contact-id)
(assoc-in [:contacts/contacts contact-id] contact))}))
(assoc :blocked? false))]
{:db (assoc-in db [:contacts/contacts contact-id] contact)}))
(rf/defn unblock-contact
{:events [:contact.ui/unblock-contact-pressed]}
@@ -94,4 +88,4 @@
(contacts-store/unblock
cofx
contact-id
#(re-frame/dispatch [::contact-unblocked contact-id])))
#(re-frame/dispatch [:contacts/unblocked contact-id])))
+1 -1
View File
@@ -1,6 +1,6 @@
(ns status-im.contact.chat
(:require [re-frame.core :as re-frame]
[status-im.contact.core :as contact]
[status-im2.contexts.contacts.events :as contact]
[utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))

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