Compare commits

...
Author SHA1 Message Date
Omar Basem bc3e3d30bd updates 2023-03-16 10:11:57 +04:00
Omar Basem 9f9124aa0b updates 2023-03-16 09:51:43 +04:00
Omar Basem 33674861d0 updates 2023-03-16 09:39:07 +04:00
Omar Basem 32d8a52acf updates 2023-03-16 09:23:18 +04:00
Omar Basem d3635b7c91 updates 2023-03-16 09:22:32 +04:00
yqrashawn 9723479634 refactor: chat message list context related (#15313) 2023-03-16 10:52:47 +08:00
Alexander dabe8285be Bugfixes for the style of "New to Status" screen (#15353)
* Bugfixes for the style of "New to Status" screen

* Updates
2023-03-15 20:02:26 +01:00
Ibrahem Khalil f981021a1f Code Improvements of 15048 (#15351) 2023-03-15 20:08:59 +02:00
Churikova Tetiana b5781a7a83 e2e: minor fixes 2023-03-15 16:49:37 +01:00
Icaro Motta e8556a9abf Show AC unread indicator with counter and seen state color (#15304)
- Display Activity Center unread badge with the unread counter.
- Use the new seen state stored in `status-go` to change the color of the
  notification.
- Performance: split the `top-nav` component into left and right section
  components and render the unread indicator in a separate component to not
  trigger the re-render of the entire `top-nav` (as was before).
  
Fixes https://github.com/status-im/status-mobile/issues/14851

Demo: https://user-images.githubusercontent.com/46027/224299978-770dd5f1-302b-4375-af2b-3cd181ffdc9d.webm

Notes
=====

- Fix/improve: `quo/counter` displayed `NaN` to the user if the input value was
  an empty string.
- In Figma, there's a border around the unread indicator. I didn't implement
  this because the ideal solution IMO involves changing the `quo/counter`
  component a little bit because the width of the component varies according to
  the content displayed (1, 9, 99, 100, etc) and I wanted to the right thing in
  a separate PR.

Design notes
============

There's an ongoing conversation with the Design team to decide what to do with
the gray indicator on top of the bell icon, since there's little contrast when
it's is in the `seen` state.

Platforms
=========

- Android
- iOS

Steps to test
=============

- Open Status
- Receive one or more notifications in the Home screen and check the unread
  indicator is blue and has a counter.
- Open the AC and close it, notice the unread indicator is now in the `seen`
  state. You can close the app and re-open and the state is persisted.
- Mark notifications as read/unread at will, check the unread counter is
  correct.
2023-03-15 12:41:34 -03:00
Omar Basem f640eb8c8f feat: drag to dismiss lightbox (#15349)
* feat: drag to dismiss lightbox
2023-03-15 16:37:01 +04:00
Alexander 8546727f84 Spacing between codeblocks and regular text + fixes for "edited at" message (#15307)
* Spacing between codeblocks and regular text + fixes for "edited at" message

Fixes

Post-review updates

* Lint fixes
2023-03-15 11:53:20 +01:00
Jamie Caprani de6a736c10 feat: add ability to cancel a request to join a community (#14973)
https://github.com/status-im/status-go/compare/80d350ad...5d818669
2023-03-14 16:14:37 -07:00
Roman Volosovskyi 61600a534b [#15152] SHow ENS name on adding contact via ENS name 2023-03-14 19:34:39 +01:00
Ibrahem Khalil 181e5c2266 Flexsurfers' comments on status-tags (#15345) 2023-03-14 18:46:35 +01:00
Icaro Motta 9473d3f40c Swipe gestures for Activity Center notifications with CTA (#15284)
Implements swipe actions for notifications with call to action (e.g. pending
contact requests, unverified identity verifications, etc).

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

According to the Design team, the goal is to deliver a consistent experience to
users, so whenever the user sees a notification with buttons, the same actions
can be taken via the swipe buttons.

Note: swipe buttons are using placeholder icons while the Design team works out
which ones to use

Additionally, a bunch of fixes:

- Fix: outgoing pending contact requests were not being removed from the UI when
  cancelled.
- Fix: Membership tab not showing unread indicator.
- Fix: dismissed membership notification not marked as read.
- Fix: dismissed membership notification was displaying decline/accept buttons.
  Regression came from changes in status-go related to soft deletion of
  notifications.
- Fix: incorrect check for the pending state of a contact request.
- Fixed lots of bugs for identity verification notifications, as it was
  completely broken. Unfortunately, somebody made lots of changes without
  actually testing the flows.
- Add basic error handling and log if accepting, declining or canceling contact
  requests fail.

The demo shows an identity verification with swipe actions to reply or decline.
[identity-verification-swipe-to-reply.webm](https://user-images.githubusercontent.com/46027/223565755-b2ca3f68-12e2-4e1e-9e52-edd52cfcc971.webm)

Out of scope: The old quo input is still in use in the identity verification
notification. This will eventually be solved by issue
https://github.com/status-im/status-mobile/issues/14364

### Steps to test

Notifications with one or more buttons (actions) are affected by this change,
because now the user can also swipe left/right to act on them.

- Membership notifications: private group chat. The following PR explains how to
  generate them https://github.com/status-im/status-mobile/pull/14785
- Contact requests, and community gated requests to join (Admin tab).
- Identity verifications. I believe the only way to test identity verification
  flows at the moment is to use the Desktop app, since initiating the challenge
  is not implemented in Mobile yet.
- Mentions and replies don't have new swipe buttons because they don't have call
  to action buttons throughout their lifecycle.

Steps to test identity verification flows:

#### Identity verification flow 1

- `A` and `B` are mutual contacts.
- `A` sends a verification request to `B`.
- `A` should not see any notification yet.
- `B` should receive an identity verification notification. `B` can either
  decline or reply.
- `B` declines and the status `Declined` is shown instead of buttons.
- `B` can now either swipe to toggle read/unread or swipe delete the
  notification.
- `A` should not receive any notification after `A` declined.

#### Identity verification flow 2

- `A` and `B` are mutual contacts.
- `A` sends a verification request to `B`.
- `A` should not see any notification yet.
- `B` should receive an identity verification notification. `B` can either
  decline or reply.
- `B` press `Reply` and a bottom sheet is displayed with a text input.
- `B` sends the reply/answer message and the status `Replied` is shown instead
  of buttons.
- `B` can now either swipe to toggle read/unread or swipe to delete the
  notification.
- `A` should receive a notification with the reply from `B`.
- `A` can either mark the answer as untrustworthy or accept it (trust it) via
  the normal buttons, as well as via the swipe left/right buttons.
- If `A` accepts the answer, then the status `Confirmed` is shown instead of
  buttons. On the other hand, if `A` marks as untrustworthy, then the status
  `Untrustworthy` is shown instead of buttons.
- `B` should receive no further notifications due to `A`s actions.
- `A` can now either swipe to toggle read/unread or swipe delete the
  notification.
2023-03-14 12:34:13 -03:00
Jamie Caprani e98ce54830 feat: add profile input to quo2 (#15323) 2023-03-14 06:52:15 -07:00
Alexander 4097aba39b Fetch details of user when adding a contact (#15070)
* Fixes

* Fixes

* Final fixes

* Lint fixes
2023-03-14 11:40:38 +01:00
Omar Basem 64dde1c9d1 feat: improve lightbox transition (#15315)
* feat: improve lightbox transition
2023-03-14 08:24:14 +04:00
flexsurfer 0fe6fea7e4 Improve home animations (#15247) 2023-03-13 19:47:04 +01:00
Ibrahem Khalil 4810e1d7bf Prevent #links to work except in community chats and allow redirection from channel to another when clicked (#15135) 2023-03-13 20:09:38 +02:00
Ulises Manuel Cárdenas 9e4d9a05a7 Add new onboarding screen - I'm new to status 2023-03-13 10:25:04 -06:00
Churikova Tetiana ee62ffdc2c e2e: AC actions 2023-03-13 14:29:26 +01:00
Jamie Caprani d8c110bf85 feat: add title input component to quo2 (#15133) 2023-03-11 08:29:11 -08:00
jakub ff3249c514 nix: add procps to default shell, and tcl for darwin
Cocoapod installations can fail with errors like:
```
tclsh /Users/jenkins/Library/Caches/CocoaPods/Pods/Release/SQLCipher/3.4.2-f9fcf/tool/addopcodes.tcl parse.h.temp >parse.h
./configure: line 11729: tclsh: command not found
./configure: line 12262: tclsh: command not found
./configure: line 12276: tclsh: command not found
```
If a pure shell is used. Also `pgrep` would be missing from a pure shell.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-10 16:19:11 +01:00
jakub 5380f83cab ci: ugprade Jenkins library to use narrow shell
Depends on:
https://github.com/status-im/status-jenkins-lib/pull/59

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-10 16:19:10 +01:00
Brian Sztamfater 7332f483a4 feat: integrate record audio component into composer
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-03-10 12:05:12 -03:00
Mohamed Javid f67f205fa9 Status Tag UI and usage update (#15282)
* [Feature][#15267] Status Tag UI Update

* [Fix] Typo in comment

* [Fix] Feedback from PR

* [Fix] Feedback from PR

* [Fix] Blur Type on Preview Screen

* [Fix] Blur Type on Preview Screen
2023-03-10 15:31:54 +05:30
Yevheniia Berdnyk bd54b05fd0 test_community_mentions_push_notification 2023-03-09 20:37:52 +02:00
jakub 73c32eacb3 ios: add README file to ios/logs directory
Allows us to get rid of the `.gitkeep` file.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-09 14:55:01 +01:00
jakub a073812a9f ios: create logs/ios folder in advance
Otherwise in some cases we can get:
``
.../Script.sh: line 6: ./logs/react-native-xcode.log: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code
```

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-09 13:50:19 +01:00
jakub 8cd5e3f6e3 ios: direct logs to ios/logs, archive on failure
This way people don't have to ask me for access to logs from CI hosts to
be acquired using SSH access, but instead they will be simply included
in Jenkins build artifacts.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-09 12:23:51 +01:00
Churikova Tetiana 8d7224d972 e2e: fix failures 2023-03-09 12:06:24 +01:00
flexsurfer 81212573d7 🧈 Transparent modal support 🧈 (#15268) 2023-03-09 10:37:10 +01:00
Parvesh Monu de8c294c9a fix android multi-account root initialization after app relaunch (#15292) 2023-03-08 23:31:41 +05:30
Ulises Manuel Cárdenas 8478ac74ab Refactor user-avatar & add tests 2023-03-08 11:07:37 -06:00
Parvesh Monu e9310a2ace fix mention turns into unknown in community (#15285) 2023-03-08 20:15:05 +05:30
Churikova Tetiana 0345871b66 e2e: block user test 2023-03-08 12:21:10 +01:00
Ibrahem Khalil 7a299b9b86 [15166] Show message edited status (#15190) 2023-03-08 12:42:12 +02:00
yqrashawn 5fe3029ad8 feat: allow group admin to delete others message (#15256) 2023-03-08 10:08:40 +08:00
Roman Volosovskyi c6e63ff5a5 [#15241] Proper system message on being not a member of a group 2023-03-07 09:35:36 +01:00
andrey 998b40ec4f podfile.lock 2023-03-06 15:57:26 +01:00
Jamie CapraniandChurikova Tetiana 2861190e5b New intro screen (#15127)
* feat: add new intro page

* e2e: new intro fix

---------

Co-authored-by: Churikova Tetiana <tatiana@status.im>
2023-03-06 06:42:30 -08:00
Churikova Tetiana 404ae82cfe e2e: fix deep link profile test
Signed-off-by: Parvesh Monu <parvesh.dhullmonu@gmail.com>
2023-03-06 17:26:29 +05:30
Parvesh Monu 9ffefe74bb fix navigation to user profile 2023-03-06 17:16:49 +05:30
Vitaliy Vlasov 9959d537f3 Emoji hash is now in settings
Signed-off-by: Vitaliy Vlasov <siphiuel@protonmail.com>
2023-03-06 13:27:15 +02:00
John Ngeiandjo-mut 7a9018ae11 replaced mocked community-tags and images with real data
Co-authored-by: jo-mut <jo_ngei@Johns-MacBook-Air.local>
2023-03-06 13:57:58 +03:00
Parvesh Monu 8454ce2e11 Onboarding add background screen (#15231) 2023-03-06 16:07:07 +05:30
Parvesh Monu f314806b83 Improve profile card (#15264) 2023-03-06 14:24:34 +05:30
Omar Basem 16ffc23509 Lightbox improvements (#15243)
* feat: lightbox polishing and improvements
2023-03-06 08:35:36 +04:00
jakub 80a75c5232 nix: patch all Gradle configs of nodejs deps
Before we were patching only `build.gradle`, which is not the only type
of Gradle config file. If we do not cover them all we can encounter
errors about missing package because they will continue using remote
repositories instead of `mavenLocal()`, to which pass Nix store path.

We also need to cover `gradlePluginPortal()` to provide plugins.

This is also necessary for the React Native upgrade:
https://github.com/status-im/status-mobile/pull/15203

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-04 13:01:26 +01:00
jakub 20a0cc01f6 nix: refactor Gradle deps to be more generic
Refactoring the derivation that fetches all the POMs, JARs,
and AARs in order to make it more generic and easier to extend.
The main change is adding `files` key in `deps.json` which contains
a dict of all the files reletad to given package.

This way we can more easily include other files that might be available
for download, like AARs with ASC suffix, or `nodeps` JARs.

This is also necessary for the React Native upgrade:
https://github.com/status-im/status-mobile/pull/15203

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-03-04 12:41:29 +01:00
279 changed files with 14512 additions and 11145 deletions
+2 -3
View File
@@ -100,9 +100,8 @@ Statusgo.xcframework
#ios
/ios/Pods/
/ios/logs/
/ios/StatusIm.xcworkspace
/ios/react-native-xcode.log
/ios/set_xcode_version.log
.ruby-version
status-e2e/
@@ -183,4 +182,4 @@ test/appium/tests/users.py
/.calva/
## component-tests
*.log
*.log
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
agent { label 'linux' }
+4 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -63,6 +63,9 @@ pipeline {
steps {
script { api = ios.bundle() }
}
post {
failure { archiveArtifacts 'ios/logs/*' }
}
}
stage('Parallel Upload') {
parallel {
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
agent { label params.AGENT_LABEL }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
agent { label 'linux' }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.6'
library 'status-jenkins-lib@v1.6.9'
pipeline {
agent {
+14
View File
@@ -116,6 +116,20 @@ deref'ed atoms.
{:background-color (colors/theme-colors colors/white colors/neutral-90)})
```
### Custom Colors
The Status designs have a lot of customization of user and group colors with components and pages. For consistency it is best to use `customization-color` as the prop key on pages and components. This will help easily identify what pages and components in the application are using customized colors.
```clojure
;; bad
(defn community-card [{keys [custom-color]}]
...)
;; good
(defn community-card [{keys [customization-color]}]
...)
```
### Using TODOs comments
_TODO_ comments are used extensively in the codebase, but prefer to use them
+3
View File
@@ -123,6 +123,7 @@ def build_ios_adhoc(readonly: false, pr_build: false)
export_method: 'ad-hoc',
output_name: 'StatusIm',
output_directory: 'status-ios',
buildlog_path: 'ios/logs',
export_options: {
signingStyle: 'manual',
provisioningProfiles: {
@@ -162,6 +163,7 @@ def build_ios_e2e
# 3. directory where to up StatusIm.app
derived_data_path: 'status-ios',
output_name: 'StatusIm.app',
buildlog_path: 'ios/logs',
# -------------------------------------
# Normal stuff
scheme: 'StatusIm',
@@ -239,6 +241,7 @@ platform :ios do
clean: true,
export_method: 'app-store',
output_directory: 'status-ios',
buildlog_path: 'ios/logs',
include_symbols: false,
export_options: {
"combileBitcode": true,
+8 -2
View File
@@ -228,6 +228,8 @@ PODS:
- React-Core
- react-native-netinfo (4.7.0):
- React
- react-native-orientation-locker (1.5.0):
- React-Core
- react-native-randombytes (3.6.1):
- React-Core
- react-native-safe-area-context (2.0.0):
@@ -238,7 +240,7 @@ PODS:
- React
- react-native-status (1.0.0):
- React
- react-native-status-keycard (2.5.38):
- react-native-status-keycard (2.5.39):
- Keycard
- React
- react-native-webview (11.16.0):
@@ -433,6 +435,7 @@ DEPENDENCIES:
- react-native-lottie-splash-screen (from `../node_modules/react-native-lottie-splash-screen`)
- react-native-mail (from `../node_modules/react-native-mail`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-shake (from `../node_modules/react-native-shake`)
@@ -545,6 +548,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-mail"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-orientation-locker:
:path: "../node_modules/react-native-orientation-locker"
react-native-randombytes:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
@@ -666,12 +671,13 @@ SPEC CHECKSUMS:
react-native-lottie-splash-screen: 068688c15dd478301fda00f8d87d7fb7d5b9a93e
react-native-mail: 8fdcd3aef007c33a6877a18eb4cf7447a1d4ce4a
react-native-netinfo: ddaca8bbb9e6e914b1a23787ccb879bc642931c9
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: 60f654e00b6cc416573f6d5dbfce3839958eb57a
react-native-shake: de052eaa3eadc4a326b8ddd7ac80c06e8d84528c
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
react-native-status: 21f75d492fd311dc111303da38a7a2b23a8a8466
react-native-status-keycard: f60ca57d789aad6875c64ece81ab06ef0609e0d3
react-native-status-keycard: f1c1227b2d5984c10fb44db68e4bfd2937f31e98
react-native-webview: 28a8636d97ee641f2ee8f20492d7a6c269c1d703
React-RCTActionSheet: e911b99f0d6fa7711ffc2f62d236b12a32771835
React-RCTAnimation: ad8b853170a059faf31d6add34f67d22391bbe01
+4 -4
View File
@@ -526,7 +526,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
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";
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 > ./logs/react-native-xcode.log 2>&1";
};
0F876BD5356F61BF142A01A0 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -584,7 +584,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
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";
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 > ./logs/react-native-xcode.log 2>&1";
};
3AAD2AD724A3A60E0075D594 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
@@ -598,7 +598,7 @@
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./logs/set_xcode_version.log 2>&1";
};
3C1038075AE5E6FB86AC2319 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
@@ -678,7 +678,7 @@
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = "/usr/bin/env sh";
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./logs/set_xcode_version.log 2>&1";
};
E732E3E1B024946173BF6D3D /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
+14
View File
@@ -0,0 +1,14 @@
# Description
This directory is the destination of logs created by Fastlane and React Native Xcode script.
# Logs
* `react-native-xcode.log` - Output from `node_modules/react-native/scripts/react-native-xcode.sh`.
- Created by redirecting output of `shellScript` in `ios/StatusIm.xcodeproj/project.pbxproj`.
* `Status PR-StatusImPR.log - Created by [Fastlane Gym](https://docs.fastlane.tools/actions/gym/).
- Configred via [`Fastfile`](../Fastfile) using `buildlog_path` argument for `build_ios_app`.
# CI
These log files are uploaded to Jenkins as CI job artifacts on failure using `archiveArtifacts`.
@@ -1139,11 +1139,6 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
executeRunnableStatusGoMethod(() -> Statusgo.generateAlias(seed), callback);
}
@ReactMethod
public void emojiHash(final String publicKey, final Callback callback) throws JSONException {
executeRunnableStatusGoMethod(() -> Statusgo.emojiHash(publicKey), callback);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String identicon(final String seed) {
return Statusgo.identicon(seed);
@@ -866,12 +866,6 @@ RCT_EXPORT_METHOD(generateAliasAsync:(NSString *)publicKey
callback(@[result]);
}
RCT_EXPORT_METHOD(emojiHash:(NSString *)publicKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoEmojiHash(publicKey);
callback(@[result]);
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(identicon:(NSString *)publicKey) {
return StatusgoIdenticon(publicKey);
}
+10 -4
View File
@@ -24,6 +24,7 @@ Generating scripts:
- `get_deps.sh` - Calls Gradle to get all the dependencies of sub-projects.
- `gradle_parser.awk` - An AWK script that parses above Gradle output.
- `url2json.sh` - Converts the list of URLs into a format consumable by Nix.
- `add_package.sh` - Allows for adding a missing package manually.
Finally we have the Nix derivation in `default.nix` which produces a derivation with all of the Gradle project dependencies:
```
@@ -66,9 +67,14 @@ You can use the `add_package.sh` script to add missing Gradle dependencies:
> make shell TARGET=gradle
Configuring Nix shell for target 'gradle'...
[nix-shell:~/status-mobile]$ nix/deps/gradle/add_package.sh com.android.tools.build:gradle:3.4.0
[nix-shell:~/work/status-mobile]$ nix/deps/gradle/add_package.sh com.android.tools.build:gradle:3.5.3
Changes made:
nix/deps/gradle/deps.urls | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
Regenerating Nix files...
Found 548 direct dependencies...
Successfully added: com.android.tools.build:gradle:3.4.0
Successfully added: com.android.tools.build:gradle:3.5.3
NOTICE: Running 'make nix-update-gradle' in a new shell is recommended.
```
This may take a bit longer than normal `make nix-update-gradle` but should add the missing package.
Keep in mind that the changes made by this script do not affect the already spawned shell.
+12 -5
View File
@@ -1,6 +1,10 @@
#!/usr/bin/env bash
set -Eeu
# This script allows for adding a package by providing a Maven full name.
# Such name consists of 3 sections separated by the colon character.
# Example: com.android.tools.build:gradle:3.5.3
set -Eeuo pipefail
if [[ $# -ne 1 ]]; then
echo "Usage: add_package.sh <package>" >&2
@@ -18,12 +22,15 @@ source "${GIT_ROOT}/scripts/colors.sh"
echo "${1}" | go-maven-resolver >> nix/deps/gradle/deps.urls
# Remove duplicates and sort.
sort -uo nix/deps/gradle/deps.urls nix/deps/gradle/deps.urls
sort -uVo nix/deps/gradle/deps.urls nix/deps/gradle/deps.urls
echo -e "${GRN}Changes made:${RST}" >&2
git diff --stat nix/deps/gradle/deps.urls
echo
# Re-generate dependencies JSON.
"${GIT_ROOT}/nix/deps/gradle/generate.sh" gen_deps_json
# Re-generate dependencies list.
"${GIT_ROOT}/nix/deps/gradle/generate.sh" gen_deps_list
echo -e "${GRN}Successfully added:${RST} ${BLD}${1}${RST}" >&2
echo
echo -e "${YLW}NOTICE:${RST} Running '${BLD}make nix-update-gradle${RST}' in a new shell is recommended."
+25 -63
View File
@@ -1,82 +1,44 @@
{ stdenv, lib, pkgs, fetchurl, writeShellScriptBin }:
let
inherit (lib)
removeSuffix optionalString splitString concatMapStrings
attrByPath attrValues last makeOverridable importJSON;
inherit (lib) concatStrings concatMapStrings mapAttrsToList makeOverridable;
inherit (pkgs) aapt2;
deps = importJSON ./deps.json;
# some .jar files have an `-aot` suffix that doesn't work for .pom files
getPOM = jarUrl: "${removeSuffix "-aot" jarUrl}.pom";
deps = lib.importJSON ./deps.json;
script = writeShellScriptBin "create-local-maven-repo" (''
mkdir -p $out
cd $out
'' +
# TODO: Generalize this section to not repeat the same code.
(concatMapStrings (dep:
let
url = "${dep.host}/${dep.path}";
pom = {
sha1 = attrByPath [ "pom" "sha1" ] "" dep;
sha256 = attrByPath [ "pom" "sha256" ] "" dep;
};
pom-download = optionalString (pom.sha256 != "") (
fetchurl { url = getPOM url; inherit (pom) sha256; }
);
jar = {
sha1 = attrByPath [ "jar" "sha1" ] "" dep;
sha256 = attrByPath [ "jar" "sha256" ] "" dep;
};
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
''
mkdir -p ${directory}
${optionalString (pom-download != "") ''
ln -s "${pom-download}" "${getPOM dep.path}"
''}
${optionalString (pom.sha1 != "") ''
echo "${pom.sha1}" > "${getPOM dep.path}.sha1"
''}
${optionalString (jar-download != "") ''
ln -s "${jar-download}" "${dep.path}.${dep.type}"
''}
${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"
''}
# For each dependency in deps.json.
(concatMapStrings (dep: concatStrings
# And for each file in the 'files' dict of given dependency.
(mapAttrsToList (filename: hashes: let
# Download given file(POM, JAR, nodeps JAR, or AAR).
download = fetchurl {
url = "${dep.repo}/${dep.path}/${filename}";
inherit (hashes) sha256;
};
# And symlink it in the correct folder along with SHA1.
in ''
mkdir -p "${dep.path}"
ln -s "${download}" "${dep.path}/${filename}"
echo "${hashes.sha1}" > "${dep.path}/${filename}.sha1"
'')
deps));
dep.files)
) deps)
);
in makeOverridable stdenv.mkDerivation {
name = "status-mobile-maven-deps";
buildInputs = [ aapt2 ];
buildInputs = [ pkgs.aapt2 ];
phases = [ "buildPhase" "patchPhase" ];
buildPhase = "${script}/bin/create-local-maven-repo";
# Patched AAPT2
# Replace AAPT2 package only with our patched version from overlay.
patchPhase = ''
aapt2_dir=$out/com/android/tools/build/aapt2/${aapt2.version}
aapt2_dir=$out/com/android/tools/build/aapt2/${pkgs.aapt2.version}
mkdir -p $aapt2_dir
ln -sf ${aapt2}/* $aapt2_dir
ln -sf ${pkgs.aapt2}/* $aapt2_dir
'';
}
+8377 -7566
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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.31.0/checker-qual-3.31.0.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.32.0/checker-qual-3.32.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
+22 -22
View File
@@ -1,18 +1,16 @@
#!/usr/bin/env bash
# Stop on any failures, including in pipes
set -e
set -o pipefail
# This script takes care of generating/updating the maven-sources.nix file
# representing the offline Maven repo containing the dependencies
# required to build the project
set -Eeo pipefail
if [[ -z "${IN_NIX_SHELL}" ]]; then
echo "Remember to call 'make shell'!"
exit 1
fi
# This script takes care of generating/updating the maven-sources.nix file
# representing the offline Maven repo containing the dependencies
# required to build the project
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/scripts/colors.sh"
@@ -27,41 +25,43 @@ ulimit -n 16384
# Generate list of Gradle sub-projects.
function gen_proj_list() {
${CUR_DIR}/get_projects.sh | sort -u -o ${PROJ_LIST}
echo -e "Found ${GRN}$(wc -l < ${PROJ_LIST})${RST} sub-projects..."
"${CUR_DIR}/get_projects.sh" | sort -u -o "${PROJ_LIST}"
echo -e "Found ${GRN}$(wc -l < "${PROJ_LIST}")${RST} sub-projects..."
}
# Check each sub-project in parallel, the ":" is for local deps.
function gen_deps_list() {
PROJECTS=$(cat ${PROJ_LIST})
${CUR_DIR}/get_deps.sh ":" ${PROJECTS[@]} | sort -uV -o ${DEPS_LIST}
echo -e "${CLR}Found ${GRN}$(wc -l < ${DEPS_LIST})${RST} direct dependencies..."
PROJECTS=$(cat "${PROJ_LIST}")
# WARNING: The ${PROJECTS[@]} needs to remain unquoted to expand correctly.
# shellcheck disable=SC2068
"${CUR_DIR}/get_deps.sh" ":" ${PROJECTS[@]} | sort -uV -o "${DEPS_LIST}"
echo -e "${CLR}Found ${GRN}$(wc -l < "${DEPS_LIST}")${RST} direct dependencies..."
}
# Find download URLs for each dependency.
function gen_deps_urls() {
cat ${DEPS_LIST} | go-maven-resolver | sort -uV -o ${DEPS_URLS}
echo -e "${CLR}Found ${GRN}$(wc -l < ${DEPS_URLS})${RST} dependency URLs..."
go-maven-resolver < "${DEPS_LIST}" | sort -uV -o "${DEPS_URLS}"
echo -e "${CLR}Found ${GRN}$(wc -l < "${DEPS_URLS}")${RST} dependency URLs..."
}
# Generate the JSON that Nix will consume.
function gen_deps_json() {
# Open the Nix attribute set.
echo -n "[" > ${DEPS_JSON}
echo -n "[" > "${DEPS_JSON}"
# Format URLs into a Nix consumable file.
URLS=$(cat ${DEPS_URLS})
URLS=$(cat "${DEPS_URLS}")
# Avoid rate limiting by using 4 of the available threads.
parallel --will-cite --keep-order --jobs 4 \
"${CUR_DIR}/url2json.sh" \
::: ${URLS} \
>> ${DEPS_JSON}
::: "${URLS}" \
>> "${DEPS_JSON}"
# Drop tailing comma on last object, stupid JSON
sed -i '$ s/},/}/' ${DEPS_JSON}
sed -i '$ s/},/}/' "${DEPS_JSON}"
# Close the Nix attribute set
echo "]" >> ${DEPS_JSON}
echo "]" >> "${DEPS_JSON}"
}
# ------------------------------------------------------------------------------
@@ -74,7 +74,7 @@ cd "${GIT_ROOT}/android"
./gradlew --stop >/dev/null
# A way to run a specific stage of generation
if [[ -n "${1}" ]] && type ${1} > /dev/null; then
if [[ -n "${1}" ]] && type "${1}" > /dev/null; then
${1}; exit 0
elif [[ -n "${1}" ]]; then
echo "No such function: ${1}"; exit 1
@@ -86,6 +86,6 @@ gen_deps_list
gen_deps_urls
gen_deps_json
REL_DEPS_JSON=$(realpath --relative-to=${PWD} ${DEPS_JSON})
REL_DEPS_JSON=$(realpath --relative-to="${PWD}" "${DEPS_JSON}")
echo -e "${CLR}Generated Nix deps file: ${REL_DEPS_JSON#../}"
echo -e "${GRN}Done${RST}"
+14 -12
View File
@@ -1,12 +1,19 @@
#!/usr/bin/env bash
set -Eeu
# This script generates a list of dependencies for the main project and its
# sub-projects defined using Gradle config files. It parses Gradle output of
# 'dependencies' and 'buildEnvironment` tasks using AWK.
set -Eeuo pipefail
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
# Gradle needs to be run in 'android' subfolder
# Gradle needs to be run in 'android' subfolder.
cd "${GIT_ROOT}/android"
AWK_SCRIPT="${GIT_ROOT}/nix/deps/gradle/gradle_parser.awk"
# Show Gradle log in case of failure.
GRADLE_LOG_FILE='/tmp/gradle.log'
function show_gradle_log() { cat "${GRADLE_LOG_FILE}" >&2; }
trap show_gradle_log ERR
# Run the gradle command for a project:
# - ':buildEnvironment' to get build tools
@@ -20,16 +27,11 @@ for i in "${!DEPS[@]}"; do
NORMAL_DEPS[${i}]="${DEPS[${i}]}:dependencies"
done
# And clean up the output by:
# - keep only lines that start with \--- or +---
# - drop lines that end with (*) or (n) but don't start with (+)
# - drop lines that refer to a project
# - drop entries starting with `status-im:` like `status-go`
# - drop entries that aren't just the name of the dependency
# - extract the package name and version, ignoring version range indications,
# such as in `com.google.android.gms:play-services-ads:[15.0.1,16.0.0) -> 15.0.1`
# And clean up the output using AWK script.
AWK_SCRIPT="${GIT_ROOT}/nix/deps/gradle/gradle_parser.awk"
./gradlew --no-daemon --console plain \
"${BUILD_DEPS[@]}" \
"${NORMAL_DEPS[@]}" \
| awk -f ${AWK_SCRIPT}
| tee "${GRADLE_LOG_FILE}" \
| awk -f "${AWK_SCRIPT}"
+12 -2
View File
@@ -1,12 +1,22 @@
#!/usr/bin/env bash
set -Eeu
# This script generates a list of Gradle sub-projects by parsing the output
# of Gradle 'projects' task using grep and sed. It is necessary in order to
# collect list of dependencies for main project and its sub-projects.
set -Eeuo pipefail
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
# Gradle needs to be run in 'android' subfolder
# Gradle needs to be run in 'android' subfolder.
cd "${GIT_ROOT}/android"
# Show Gradle log in case of failure.
GRADLE_LOG_FILE='/tmp/gradle.log'
function show_gradle_log() { cat "${GRADLE_LOG_FILE}" >&2; }
trap show_gradle_log ERR
# Print all our sub-projects
./gradlew projects --no-daemon --console plain 2>&1 \
| tee "${GRADLE_LOG_FILE}" \
| grep "Project ':" \
| sed -E "s;^.--- Project '\:([@_a-zA-Z0-9\-]+)';\1;"
+1
View File
@@ -26,6 +26,7 @@ react-native-lottie-splash-screen
react-native-mail
react-native-navigation
react-native-nfc-manager
react-native-orientation-locker
react-native-permissions
react-native-randombytes
react-native-reanimated
+53 -73
View File
@@ -6,8 +6,6 @@
# a local Maven repository.
#
CUR_DIR=$(cd "${BASH_SOURCE%/*}" && pwd)
# This defines URLs of Maven repos we know about and use.
declare -a REPOS=(
"https://repo.maven.apache.org/maven2"
@@ -37,105 +35,87 @@ function match_repo_url() {
}
function pom_has_nodeps_jar() {
grep '<shadedClassifierName>nodeps</shadedClassifierName>' $1 \
2>&1 >/dev/null
grep '<shadedClassifierName>nodeps</shadedClassifierName>' "${1}" \
>/dev/null 2>&1
}
function fetch_and_template_file() {
local FILENAME="${1}"
local OBJ_URL OBJ_NIX_FETCH_OUT OBJ_NAME OBJ_PATH
OBJ_URL="${REPO_URL}/${PKG_PATH}/${FILENAME}"
if ! OBJ_NIX_FETCH_OUT=$(nix_fetch "${OBJ_URL}"); then
echo " ! Failed to fetch: ${OBJ_URL}" >&2
exit 1
fi
OBJ_NAME="${FILENAME}"
OBJ_PATH=$(get_nix_path "${OBJ_NIX_FETCH_OUT}")
echo -n ",
\"${OBJ_NAME}\": {
\"sha1\": \"$(get_sha1 "${OBJ_PATH}")\",
\"sha256\": \"$(get_nix_sha "${OBJ_NIX_FETCH_OUT}")\"
}"
}
if [[ -z "${1}" ]]; then
echo "Required argument not given!" >&2
echo "Required POM URL argument not given!" >&2
exit 1
fi
POM_URL=${1}
# Drop the POM extension
OBJ_REL_URL=${POM_URL%.pom}
# Drop the POM extension.
PKG_URL_NO_EXT="${POM_URL%.pom}"
# Name of package without extension.
PKG_NAME="$(basename "${PKG_URL_NO_EXT}")"
echo -en "${CLR} - Nix entry for: ${1##*/}\r" >&2
REPO_URL=$(match_repo_url "${OBJ_REL_URL}")
REPO_URL=$(match_repo_url "${PKG_URL_NO_EXT}")
if [[ -z "${REPO_URL}" ]]; then
echo "\r\n ? REPO_URL: ${REPO_URL}" >&2
echo " ! Repo URL not found: %s" "${REPO_URL}" >&2
exit 1
fi
# Get the relative path without full URL
OBJ_REL_NAME="${OBJ_REL_URL#${REPO_URL}/}"
PKG_PATH="${PKG_URL_NO_EXT#"${REPO_URL}/"}"
PKG_PATH="$(dirname "${PKG_PATH}")"
# Both JARs and AARs have a POM
POM_NIX_FETCH_OUT=$(nix_fetch "${OBJ_REL_URL}.pom")
POM_NIX_FETCH_OUT=$(nix_fetch "${PKG_URL_NO_EXT}.pom")
POM_PATH=$(get_nix_path "${POM_NIX_FETCH_OUT}")
POM_NAME=$(basename "${PKG_URL_NO_EXT}.pom")
if [[ -z "${POM_PATH}" ]]; then
echo " ! Failed to fetch: ${OBJ_REL_URL}.pom" >&2
echo " ! Failed to fetch: ${PKG_URL_NO_EXT}.pom" >&2
exit 1
fi
POM_SHA256=$(get_nix_sha "${POM_NIX_FETCH_OUT}")
POM_SHA1=$(get_sha1 "${POM_PATH}")
# Identify packaging type, JAR, AAR, or just POM.
OBJ_TYPE_RAW=$(grep -oP '<packaging>\K[^<]+' "${POM_PATH}")
# Bundle is a JAR made using maven-bundle-plugin.
case "${OBJ_TYPE_RAW}" in
''|'bundle') OBJ_TYPE=jar;;
'aar.asc') OBJ_TYPE=aar;;
*) OBJ_TYPE="${OBJ_TYPE_RAW}"
esac
# Identify packaging type, JAR, AAR, bundle, or just POM.
OBJ_TYPE=$(grep -oP '<packaging>\K[^<]+' "${POM_PATH}")
# Some deps are Eclipse plugins, and we don't need those.
if [[ "${OBJ_TYPE}" == "eclipse-plugin" ]]; then
exit 0
fi
# Some deps are just POMs, in which case there is no JAR to fetch.
if [[ "${OBJ_TYPE}" != "pom" ]]; then
OBJ_NIX_FETCH_OUT=$(nix_fetch "${OBJ_REL_URL}.${OBJ_TYPE}")
# If type was a JAR or other, not getting one is an error.
if [[ ${?} -ne 0 ]]; then
# POMs without packaging type defined can still include JARs.
if [[ "${OBJ_TYPE_RAW}" != "" ]]; then
echo " ! Failed to fetch: ${OBJ_REL_URL}.${OBJ_TYPE}" >&2
exit 1
fi
else
OBJ_PATH=$(get_nix_path "${OBJ_NIX_FETCH_OUT}")
OBJ_SHA256=$(get_nix_sha "${OBJ_NIX_FETCH_OUT}")
OBJ_SHA1=$(get_sha1 "${OBJ_PATH}")
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 "
{
\"path\": \"${OBJ_REL_NAME}\",
\"host\": \"${REPO_URL}\",
\"type\": \"${OBJ_TYPE}\","
if [[ -n "${POM_SHA256}" ]]; then
echo -n "
\"pom\": {
\"sha1\": \"${POM_SHA1}\",
\"sha256\": \"${POM_SHA256}\"
}";[[ -n "${OBJ_SHA256}" ]] && echo -n ","
fi
if [[ -n "${OBJ_SHA256}" ]]; then
echo -n "
\"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 },"
\"path\": \"${PKG_PATH}\",
\"repo\": \"${REPO_URL}\",
\"files\": {
\"${POM_NAME}\": {
\"sha1\": \"${POM_SHA1}\",
\"sha256\": \"${POM_SHA256}\"
}"
# Some deps are just POMs, in which case there is no JAR to fetch.
[[ "${OBJ_TYPE}" == "" ]] && fetch_and_template_file "${PKG_NAME}.jar"
[[ "${OBJ_TYPE}" == "jar" ]] && fetch_and_template_file "${PKG_NAME}.jar"
[[ "${OBJ_TYPE}" == "bundle" ]] && fetch_and_template_file "${PKG_NAME}.jar"
[[ "${OBJ_TYPE}" =~ aar* ]] && fetch_and_template_file "${PKG_NAME}.aar"
[[ "${OBJ_TYPE}" == "aar.asc" ]] && fetch_and_template_file "${PKG_NAME}.${OBJ_TYPE}"
pom_has_nodeps_jar "${POM_PATH}" && fetch_and_template_file "${PKG_NAME}-nodeps.jar"
echo -e '\n }\n },'
+8 -1
View File
@@ -29,7 +29,14 @@ stdenv.mkDerivation {
# maven and google central repositories with our own local directories.
# This prevents the builder from downloading Maven artifacts
patchGradlePhase = ''
for modBuildGradle in $(find -L ./node_modules -name build.gradle); do
gradleConfigs=$(
find -L ./node_modules \
-name build.gradle -or \
-name build.gradle.kts -or \
-name settings.gradle -or \
-name settings.gradle.kts
)
for modBuildGradle in $gradleConfigs; do
relativeToNode=''${modBuildGradle#*node_modules/}
moduleName=''${relativeToNode%%/*}
if [[ -L ./node_modules/$moduleName ]]; then
+4 -3
View File
@@ -16,7 +16,8 @@ writeScript "patch-maven-srcs" (''
gradleFile="$1"
# Some of those find something, some don't, that's fine.
patchMavenSource "$gradleFile" 'mavenCentral()' 'mavenLocal()'
patchMavenSource "$gradleFile" 'google()' 'mavenLocal()'
patchMavenSource "$gradleFile" 'jcenter()' 'mavenLocal()'
patchMavenSource "$gradleFile" 'mavenCentral()' 'mavenLocal()'
patchMavenSource "$gradleFile" 'google()' 'mavenLocal()'
patchMavenSource "$gradleFile" 'jcenter()' 'mavenLocal()'
patchMavenSource "$gradleFile" 'gradlePluginPortal()' 'mavenLocal()'
'')
+2 -2
View File
@@ -12,7 +12,7 @@ in mkShell {
buildInputs = with pkgs; lib.unique ([
# core utilities that should always be present in a shell
bash curl wget file unzip flock
bash curl wget file unzip flock procps
git gnumake jq ncurses gnugrep parallel
lsof # used in start-react-native.sh
# build specific utilities
@@ -22,7 +22,7 @@ in mkShell {
# other nice to have stuff
yarn nodejs python27
] # and some special cases
++ lib.optionals stdenv.isDarwin [ cocoapods clang ]
++ lib.optionals stdenv.isDarwin [ cocoapods clang tcl ]
++ lib.optionals (!stdenv.isDarwin) [ gcc8 ]
);
Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 KiB

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

+10
View File
@@ -0,0 +1,10 @@
import { useDerivedValue } from 'react-native-reanimated';
export function infoLayout(input, isTop) {
return useDerivedValue(
function () {
'worklet'
return isTop ? input.value : -input.value
}
);
}
+7
View File
@@ -0,0 +1,7 @@
import {useAnimatedScrollHandler} from "react-native-reanimated";
export function useAnimatedScrollHandlerWorklet(scrollY) {
return useAnimatedScrollHandler((event) => {
scrollY.value = event.contentOffset.y;
})
}
+10 -10
View File
@@ -147,7 +147,10 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
:SvgXml #js {:render identity}
:default #js {:render identity}})
(def react-native-webview #js {:default {}})
(def react-native-audio-toolkit #js {:MediaStates {}})
(def react-native-audio-toolkit
#js
{:MediaStates {}
:PlaybackCategories {}})
(def net-info #js {})
(def touchid #js {})
(def react-native-image-viewing #js {:default {}})
@@ -352,11 +355,6 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def worklet-factory
#js {:applyAnimationsToStyle (fn [])})
(def shell-worklets #js {})
(def bottom-sheet #js {})
(def record-audio-worklets #js {})
;; Update i18n_resources.cljs
(defn mock
[module]
@@ -404,10 +402,12 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
"@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
"../src/js/record_audio_worklets.js" record-audio-worklets
"../src/js/worklets/core.js" worklet-factory
"../src/js/worklets/shell.js" #js {}
"../src/js/worklets/bottom_sheet.js" #js {}
"../src/js/worklets/record_audio.js" #js {}
"../src/js/worklets/scroll_view.js" #js {}
"../src/js/worklets/lightbox.js" #js {}
"./fleets.js" default-fleets
"@walletconnect/client" wallet-connect-client
"../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json"))
@@ -1,138 +0,0 @@
(ns quo2.components.avatars.user-avatar
(:require [clojure.string :as string]
[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
[{:keys [size online? ring? dark?]}]
(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 -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 initials-style
[inner-dimensions outer-dimensions]
{: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)})
(defn outer-styles
[outer-dimensions]
{:width outer-dimensions
:height outer-dimensions
:border-radius outer-dimensions})
(def one-initial-letter-sizes #{:xs :xxs :xxxs})
(def valid-ring-sizes #{:big :medium :small})
(defn initials-avatar
[{:keys [full-name size inner-dimensions outer-dimensions]}]
(let [amount-initials (if (one-initial-letter-sizes size) 1 2)
initials (as-> full-name $
(string/split $ " ")
(map (comp string/upper-case first) $)
(take amount-initials $)
(string/join $))
font-size (get-in sizes [size :font-size])]
[rn/view {:style (initials-style inner-dimensions outer-dimensions)}
[text/text
{:style {:color colors/white-opa-70}
:weight :semi-bold
:size font-size}
initials]]))
(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 over it."
[{: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-dimensions (get-in sizes [size :outer])
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
[rn/view
{:style (outer-styles outer-dimensions)
: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
{:style (outer-styles outer-dimensions)
:source image}])
(when-not profile-picture
[initials-avatar
{:full-name full-name
:size size
:inner-dimensions inner-dimensions
:outer-dimensions outer-dimensions}])
(when status-indicator?
[dot-indicator
{:size size
:online? online?
:ring? draw-ring?
:dark? (dark?)}])]))
@@ -0,0 +1,129 @@
(ns quo2.components.avatars.user-avatar.component-spec
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[test-helpers.component :as h]))
(defonce mock-picture (js/require "../resources/images/mock2/user_picture_male4.png"))
(h/describe "user avatar"
(h/test "Default render"
(h/render [user-avatar/user-avatar])
(h/is-truthy (h/get-by-label-text :user-avatar))
(h/is-truthy (h/get-by-text "EN")))
(h/describe "Profile picture"
(h/test "Renders"
(h/render
[user-avatar/user-avatar {:profile-picture mock-picture}])
(h/is-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 mock-picture
:full-name "New User1"}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-null (h/query-by-label-text :initials-avatar)))
(h/describe "Status indicator"
(h/test "Render"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:status-indicator? true}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-truthy (h/get-by-label-text :status-indicator)))
(h/test "Do not render"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:status-indicator? false}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-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))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(h/is-truthy (h/get-by-text "NU"))))
(h/describe "One letter"
(h/test "Size :xs"
(h/render (user-avatar-component :xs))
(h/is-truthy (h/get-by-text "N")))
(h/test "Size :xxs"
(h/render (user-avatar-component :xxs))
(h/is-truthy (h/get-by-text "N")))
(h/test "Size :xxxs"
(h/render (user-avatar-component :xxxs))
(h/is-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 mock-picture
:size size}])]
(h/describe "Passed and drawn"
(h/test "Size :big"
(h/render (user-avatar-component :big))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-truthy (h/get-by-label-text :ring-background)))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-truthy (h/get-by-label-text :ring-background)))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-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))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-null (h/query-by-label-text :ring-background)))
(h/test "Size :xxs"
(h/render (user-avatar-component :xxs))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-null (h/query-by-label-text :ring-background)))
(h/test "Size :xxxs"
(h/render (user-avatar-component :xxxs))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-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}])
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-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}])
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-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? customization-color]
(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 customization-color 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,61 @@
(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? customization-color]}]
(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? customization-color)}
[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
customization-color]
:or {status-indicator? true
online? true
size :big
customization-color :turquoise}}]
(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?
:customization-color customization-color}])
(when status-indicator?
[rn/view
{:accessibility-label :status-indicator
:style (style/dot size online? draw-ring?)}])]))
+5 -4
View File
@@ -204,7 +204,7 @@
[button opts \"label\"]
opts
{:type :primary/:secondary/:grey/:dark-grey/:outline/:ghost/
:danger/:photo-bg/:blur-bg/:blur-bg-ouline/:shell/:community
:danger/:photo-bg/:blur-bg/:blur-bg-outline/:shell/:community
:size 40/32/24
:icon true/false
:community-color '#FFFFFF'
@@ -213,14 +213,14 @@
:after :icon-keyword}
only icon
[button {:icon true} :main-icons/close-circle]"
[button {:icon true} :i/close-circle]"
[_ _]
(let [pressed (reagent/atom false)]
(fn
[{:keys [on-press disabled type size community-color community-text-color before after above
width
override-theme override-background-color
on-long-press accessibility-label icon icon-no-color style test-ID]
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
:or {type :primary
size 40}}
children]
@@ -275,7 +275,8 @@
(community-themed? type community-color)
(merge
{:background-color community-color}
(when (= state :pressed) {:opacity 0.9}))))}
(when (= state :pressed) {:opacity 0.9})))
inner-style)}
(when above
[rn/view
[quo2.icons/icon above
@@ -5,8 +5,8 @@
[react-native.core :as rn]))
(defn community-card-view-item
[{:keys [name description locked images
status tokens cover tags width]} on-press]
[{:keys [name description locked images cover
status tokens tags width]} on-press]
[rn/touchable-without-feedback
{:accessibility-label :community-card-item
:on-press on-press}
@@ -18,16 +18,16 @@
:on-press on-press}
[rn/view
{:flex 1}
[rn/view (style/community-cover-container 40)
[rn/view (style/community-cover-container 60)
[rn/image
{:source cover
:style
{:flex 1
:border-radius 20}}]]
{:flex 1
:border-top-right-radius 20
:border-top-left-radius 20}}]]
[rn/view (style/card-view-content-container 12)
[rn/view (style/card-view-chat-icon 48)
[icon/community-icon {:images images} 48]]
(when (= status :gated)
[rn/view (style/permission-tag-styles)
[community-view/permission-tag-container
@@ -78,42 +78,42 @@
[props
{:keys [name
muted?
unread-messages?
unread-mentions-count
unviewed-messages-count
unviewed-mentions-count
status
community-icon
images
tokens
locked?]}]
locked?
style]}]
[rn/touchable-highlight
(merge {:underlay-color (colors/theme-colors
colors/neutral-5
colors/neutral-95)
:style {:border-radius 12}}
props)
[rn/view {:flex 1}
[rn/view (style/membership-info-container)
[community-icon/community-icon
{:images community-icon} 32]
[rn/view
{:flex 1
:margin-left 12
:justify-content :center}
[text/text
{:accessibility-label :chat-name-text
:number-of-lines 1
:ellipsize-mode :tail
:weight :semi-bold
:size :paragraph-1}
name]]
[rn/view (merge (style/membership-info-container) style)
[community-icon/community-icon
{:images images} 32]
[rn/view
{:flex 1
:margin-left 12
:justify-content :center}
[text/text
{:accessibility-label :chat-name-text
:number-of-lines 1
:ellipsize-mode :tail
:weight :semi-bold
:size :paragraph-1}
name]]
[rn/view
{:justify-content :center
:margin-right 16}
(if (= status :gated)
[community-view/permission-tag-container
{:locked? locked?
:tokens tokens}]
[notification-view
{:muted? muted?
:unread-mentions-count unread-mentions-count
:unread-messages? unread-messages?}])]]]])
[rn/view
{:justify-content :center
:margin-right 16}
(if (= status :gated)
[community-view/permission-tag-container
{:locked? locked?
:tokens tokens}]
[notification-view
{:muted? muted?
:unread-mentions-count unviewed-mentions-count
:unread-messages? (pos? unviewed-messages-count)}])]]])
@@ -42,16 +42,15 @@
(defn community-tags
[tags]
[rn/view (style/community-tags-container)
(for [{:keys [id tag-label resource]} tags]
^{:key id}
(for [{:keys [name emoji]} tags]
^{:key name}
[rn/view {:margin-right 8}
[tag/tag
{:id id
:size 24
:label tag-label
{:size 24
:label name
:type :emoji
:labelled? true
:resource resource}]])])
:resource emoji}]])])
(defn community-title
[{:keys [title description size] :or {size :small}}]
@@ -82,6 +81,5 @@
colors/neutral-80)
:locked? locked?
:tokens tokens
:size 24
:on-press on-press}])
@@ -92,6 +92,7 @@
colors/neutral-90)}
{:flex-direction :row
:margin-horizontal 20
:margin-vertical 8
:height 56
:padding-right 12})
[card-title-and-description title description]
+13 -9
View File
@@ -15,9 +15,9 @@
:shadow-radius radius
:shadow-opacity 1
:shadow-color colors/shadow
:elevation 1
:border-radius radius
:justify-content :space-between
:elevation 2
:background-color (colors/theme-colors
colors/white
colors/neutral-90)})
@@ -57,14 +57,18 @@
(defn card-view-content-container
[padding-horizontal]
{:flex 1
:height 20
:padding-left padding-horizontal
:padding-right padding-horizontal
:border-radius 16
:background-color (colors/theme-colors
colors/white
colors/neutral-90)})
{:position :absolute
:top 40
:bottom 0
:left 0
:right 0
:height 20
:padding-horizontal padding-horizontal
:border-top-right-radius 16
:border-top-left-radius 16
:background-color (colors/theme-colors
colors/white
colors/neutral-90)})
(defn card-view-chat-icon
[icon-size]
@@ -1,34 +1,29 @@
(ns quo2.components.counter.--tests--.counter-component-spec
(:require ["@testing-library/react-native" :as rtl]
[quo2.components.counter.counter :as counter]
[reagent.core :as reagent]))
(:require [quo2.components.counter.counter :as counter]
[test-helpers.component :as h]))
(defn render-counter
([]
(render-counter {} nil))
([opts value]
(rtl/render (reagent/as-element [counter/counter opts value]))))
(h/describe "counter component"
(h/test "default render of counter component"
(h/render [counter/counter {} nil])
(-> (h/expect (h/get-by-test-id :counter-component))
(h/is-truthy)))
(js/global.test "default render of counter component"
(fn []
(render-counter)
(-> (js/expect (rtl/screen.getByTestId "counter-component"))
(.toBeTruthy))))
(h/test "renders counter with a string value"
(h/render [counter/counter {} "1"])
(-> (h/expect (h/get-by-text "1"))
(h/is-truthy)))
(js/global.test "renders counter with a string value"
(fn []
(render-counter {} "1")
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(h/test "renders counter with an integer value"
(h/render [counter/counter {} 1])
(-> (h/expect (h/get-by-text "1"))
(h/is-truthy)))
(js/global.test "renders counter with an integer value"
(fn []
(render-counter {} 1)
(-> (js/expect (rtl/screen.getByText "1"))
(.toBeTruthy))))
(h/test "renders counter with max value 99+ by default"
(h/render [counter/counter {} 100])
(-> (h/expect (h/get-by-text "99+"))
(h/is-truthy)))
(js/global.test "renders counter with value 99+ when the value is greater than 99"
(fn []
(render-counter {} "100")
(-> (js/expect (rtl/screen.getByText "99+"))
(.toBeTruthy))))
(h/test "renders counter with custom max value when set to 150"
(h/render [counter/counter {:max-value 150} 151])
(-> (h/expect (h/get-by-text "150+"))
(h/is-truthy))))
+13 -13
View File
@@ -1,8 +1,10 @@
(ns quo2.components.counter.counter
(:require [quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(:require
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[utils.number :as utils-number]))
(def themes
{:light {:default colors/primary-50
@@ -19,9 +21,9 @@
(get-in themes [(theme/get-theme) key]))
(defn counter
"type: default, secondary, grey, outline
value: integer"
[{:keys [type override-text-color override-bg-color style accessibility-label]} value]
[{:keys [type override-text-color override-bg-color style accessibility-label max-value]
:or {max-value 99}}
value]
(let [type (or type :default)
text-color (or override-text-color
(if (or
@@ -29,11 +31,9 @@
(= type :default))
colors/white
colors/neutral-100))
value (if (integer? value)
value
(js/parseInt value))
label (if (> value 99)
"99+"
value (utils-number/parse-int value)
label (if (> value max-value)
(str max-value "+")
(str value))
width (case (count label)
1 16
@@ -59,7 +59,7 @@
(or override-bg-color
(get-color type)))
(> value 99)
(> value max-value)
(assoc :padding-left 0.5))}
[text/text
{:weight :medium
@@ -4,22 +4,24 @@
(def outer-container {:height 216})
(def top-card
{:flex 1
:padding-vertical 12
:padding-horizontal 20
:border-radius 20
:background-color colors/neutral-80})
{:flex 1
:padding-vertical 12
:padding-horizontal 20
:border-top-left-radius 20
:border-top-right-radius 20
:background-color colors/neutral-80})
(def bottom-card
{:position :absolute
:top 80
:left 0
:right 0
:bottom 0
:padding-vertical 12
:padding-horizontal 20
:border-radius 20
:background-color (colors/alpha colors/white 0.05)})
{:position :absolute
:top 80
:left 0
:right 0
:bottom 0
:padding-vertical 12
:padding-horizontal 20
:border-top-left-radius 20
:border-top-right-radius 20
:background-color (colors/alpha colors/white 0.05)})
(def bottom-container
{:flex-direction :row
@@ -39,13 +39,14 @@
children))
(defn card
[{:keys [on-press style heading gap top?]} children]
[{:keys [on-press style heading gap accessibility-label top?]} children]
[rn/touchable-highlight
{:on-press on-press
:border-radius 20
:style style
:underlay-color (:background-color style)}
[rn/view {}
{:accessibility-label accessibility-label
:on-press on-press
:border-radius 20
:style style
:underlay-color (:background-color style)}
[rn/view
[text/text
{:size :heading-1
:style (style/heading-text gap)
@@ -60,9 +61,11 @@
opts
{:container-style style-object
:top-card { :on-press event
:heading string}
:heading string
:accessibility-label keyword}
:bottom-card { :on-press event
:heading string}}
:heading string
:accessibility-label keyword}}
child-1 string, keyword or hiccup
child-2 string, keyword or hiccup
"
@@ -1,4 +1,4 @@
(ns quo2.components.input.style
(ns quo2.components.inputs.input.style
(:require [quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]))
@@ -1,7 +1,7 @@
(ns quo2.components.input.view
(ns quo2.components.inputs.input.view
(:require [oops.core :as oops]
[quo2.components.icon :as icon]
[quo2.components.input.style :as style]
[quo2.components.inputs.input.style :as style]
[quo2.components.markdown.text :as text]
[react-native.core :as rn]
[reagent.core :as reagent]))
@@ -0,0 +1,29 @@
(ns quo2.components.inputs.profile-input.component-spec
(:require [quo2.components.inputs.profile-input.view :as profile-input]
[test-helpers.component :as h]))
(h/describe "Profile Input"
(h/test "renders user avatar with placeholder name if no value is specified"
(h/render [profile-input/profile-input
{:placeholder "Your Name"}])
(-> (js/expect (h/get-by-text "YN"))
(.toBeTruthy)))
(h/test "renders user avatar with full name if a value is specified"
(let [event (h/mock-fn)]
(h/render [profile-input/profile-input
{:on-change event
:placeholder "Your Name"
:image-picker-props {:full-name "Test Name"}}])
(h/fire-event :change (h/get-by-text "TN"))
(-> (js/expect (h/get-by-text "TN"))
(.toBeTruthy))))
(h/test "on press event fires"
(let [event (h/mock-fn)]
(h/render [profile-input/profile-input
{:placeholder "Your Name"
:on-press event}])
(h/fire-event :press (h/get-by-label-text :select-profile-picture-button))
(-> (js/expect event)
(.toHaveBeenCalledTimes 1)))))
@@ -0,0 +1,29 @@
(ns quo2.components.inputs.profile-input.style
(:require [quo2.foundations.colors :as colors]))
(defn container
[customization-color]
{:background-color (colors/custom-color customization-color 50 40)
:padding-horizontal 12
:padding-top 12
:padding-bottom 10
:border-radius 16
:height 102
:flex 1})
(def button
{:position :absolute
:top 23
:bottom 0
:left 33
:right 0
:width 24
:height 24
:border-radius 24})
(def button-inner {:border-radius 24})
(def input-container
{:flex-direction :row
:margin-top 4
:align-items :center})
@@ -0,0 +1,51 @@
(ns quo2.components.inputs.profile-input.view
(:require
[quo2.components.buttons.button :as buttons]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.inputs.profile-input.style :as style]
[quo2.components.inputs.title-input.view :as title-input]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.hole-view :as hole-view]))
(defn profile-input
[{:keys [customization-color
placeholder
on-press
title-input-props
image-picker-props]}]
(let [full-name (:full-name image-picker-props)]
[rn/view
{:style (style/container customization-color)}
[rn/view
[hole-view/hole-view
{:holes [{:x 33
:y 23
:width 24
:height 24
:borderRadius 12}]}
[user-avatar/user-avatar
(merge image-picker-props
{:customization-color customization-color
:full-name (if (seq full-name)
full-name
placeholder)
:status-indicator? false
:size :medium})]]
[buttons/button
{:accessibility-label :select-profile-picture-button
:type :grey
:override-theme :dark
:override-background-color (colors/alpha colors/white 0.05)
:on-press on-press
:icon-size 20
:width 24
:size 24
:icon :i/camera
:style style/button
:inner-style style/button-inner} :i/camera]]
[rn/view {:style style/input-container}
[title-input/title-input
(merge title-input-props
{:placeholder placeholder
:customization-color customization-color})]]]))
@@ -0,0 +1,40 @@
(ns quo2.components.inputs.title-input.component-spec
(:require [quo2.components.inputs.title-input.view :as title-input]
[test-helpers.component :as h]))
(h/describe "profile: title-input"
(h/test "renders empty"
(h/render [title-input/title-input
{:value ""
:on-change-text (h/mock-fn)}])
(-> (js/expect (h/get-by-label-text :profile-title-input))
(.toBeTruthy)))
(h/test "empty text renders with max length digits and 00"
(h/render [title-input/title-input
{:value ""
:max-length 24
:on-change-text (h/mock-fn)}])
(-> (js/expect (h/get-by-text "00"))
(.toBeTruthy))
(-> (js/expect (h/get-by-text "/24"))
(.toBeTruthy)))
(h/test "renders with max length digits and character count"
(h/render [title-input/title-input
{:default-value "abc"
:max-length 24
:on-change-text (h/mock-fn)} "abc"])
(-> (js/expect (h/get-by-text "03"))
(.toBeTruthy))
(-> (js/expect (h/get-by-text "/24"))
(.toBeTruthy)))
(h/test "text updates on change"
(let [on-change-text (h/mock-fn)]
(h/render [title-input/title-input
{:value "mock text"
:on-change-text on-change-text}])
(h/fire-event :change-text (h/get-by-label-text :profile-title-input) "mock-text-new")
(-> (js/expect on-change-text)
(.toHaveBeenCalled)))))
@@ -0,0 +1,52 @@
(ns quo2.components.inputs.title-input.style
(:require [quo2.foundations.colors :as colors]))
(defn get-focused-placeholder-color
[blur?]
(if blur?
(colors/theme-colors colors/neutral-80-opa-20 (colors/alpha colors/white 0.2))
(colors/theme-colors colors/neutral-30 colors/neutral-60)))
(defn get-placeholder-color
[blur?]
(if blur?
(colors/theme-colors colors/neutral-80-opa-40 (colors/alpha colors/white 0.3))
(colors/theme-colors colors/neutral-40 colors/neutral-50)))
(defn- get-disabled-color
[blur?]
(if blur?
(colors/theme-colors colors/neutral-80-opa-40 (colors/alpha colors/white 0.3))
(colors/theme-colors colors/neutral-40 colors/neutral-50)))
(defn- get-char-count-color
[blur?]
(if blur?
(colors/theme-colors colors/neutral-80-opa-40 (colors/alpha colors/white 0.4))
(colors/theme-colors colors/neutral-40 colors/neutral-50)))
(defn get-selection-color
[customization-color blur?]
(if blur?
(colors/theme-colors colors/neutral-100 colors/white)
(colors/custom-color customization-color (if colors/dark? 60 50))))
(def text-input-container {:flex 1})
(defn title-text
[disabled? blur?]
{:text-align-vertical :bottom
:color (when disabled? (get-disabled-color blur?))})
(defn char-count
[blur?]
{:color (get-char-count-color blur?)})
(def container
{:flex-direction :row
:flex 1
:justify-content :center
:align-items :center})
(def counter-container
{:padding-top 8})
@@ -0,0 +1,65 @@
(ns quo2.components.inputs.title-input.view
(:require
[quo2.components.inputs.title-input.style :as style]
[quo2.components.markdown.text :as text]
[reagent.core :as reagent]
[react-native.core :as rn]))
(defn- pad-0
[value]
(if (<= (count value) 1)
(str 0 value)
value))
(defn title-input
[{:keys [blur?
on-change-text
placeholder
max-length
default-value]
:or {max-length 0
default-value ""}}]
(let [focused? (reagent/atom false)
value (reagent/atom default-value)
on-change (fn [v]
(reset! value v)
(when on-change-text
(on-change-text v)))]
(fn [{:keys [customization-color disabled?]}]
[rn/view
{:style style/container}
[rn/view {:style style/text-input-container}
[rn/text-input
{:style
(text/text-style
{:size :heading-2
:weight :semi-bold
:style (style/title-text disabled? blur?)})
:default-value default-value
:accessibility-label :profile-title-input
:on-focus #(swap! focused? (fn [] true))
:on-blur #(swap! focused? (fn [] false))
:input-mode :text
:on-change-text on-change
:editable (not disabled?)
:max-length max-length
:placeholder placeholder
:selection-color (style/get-selection-color customization-color blur?)
:placeholder-text-color (if @focused?
(style/get-focused-placeholder-color blur?)
(style/get-placeholder-color blur?))}]]
[rn/view
{:style style/counter-container}
[text/text
[text/text
{:style (style/char-count blur?)
:size :paragraph-2}
(pad-0
(str
(count @value)))]
[text/text
{:style (style/char-count blur?)
:size :paragraph-2}
(str "/"
(pad-0
(str max-length)))]]]])))
@@ -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]
@@ -1,6 +1,6 @@
(ns quo2.components.list-items.user-list
(:require [react-native.core :as rn]
[quo2.components.avatars.user-avatar :as user-avatar]
[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]
@@ -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]

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