Compare commits

..
Author SHA1 Message Date
Vitaliy Vlasov ca569a7bd8 Fix for empty display-name 2023-02-17 17:29:32 +02:00
andrey de7cfe9242 remove red borders from messages 2023-02-17 13:02:21 +01:00
Andrea Maria Piana 1e224217f7 Fix contact request state 2023-02-17 10:20:23 +00:00
Andrea Maria Piana 9b15705f4a Upgrade status-go to 0.131.7+hotfix.1 2023-02-17 10:13:50 +00:00
Vitaliy Vlasov 5ad6f6a256 Use display-name in profile view
https://github.com/status-im/status-go/compare/97579ee3...97579ee3

Signed-off-by: Vitaliy Vlasov <siphiuel@protonmail.com>
2023-02-17 11:37:23 +02:00
Parvesh Monu 70bd57a1d1 fix deep links to user profiles don't do anything on tap
(cherry picked from commit 5cea66647e)
2023-02-15 23:31:25 +05:30
Andrea Maria Piana 9c1cd317ab Upgrade status-go to 0.131.4 2023-02-15 12:16:08 +00:00
andrey 31371ac9e5 [#15056] Can't see display/ens/name when mentioning in community hotfix 2023-02-15 12:38:17 +01:00
Andrea Maria Piana 087a02c8a0 Upgrade status-go to 0.131.2 2023-02-14 14:51:57 +00:00
Parvesh Monu c825fa6634 fix new chat button is not visible in small screen devices
(cherry picked from commit 5e87d7eefd)
2023-02-14 16:59:13 +05:30
jakub b6c55097c3 ci: update ITSEncryptionExportComplianceCode
We were using old ID for the encryption compliance from old Org.
Because of this the iOS release builds failed at TestFlight upload:
```
Error: Asset validation failed Invalid Export Compliance Code.
The export compliance key value [1aa92c4d-6194-4d7d-b70a-16b48256b87e]
in the app's Info.plist doesn’t match the key value of the app’s export
compliance documentation.
To find the correct value, go to My Apps on App Store Connect. (90592)
```
Related:
- https://stackoverflow.com/questions/53326492/
- https://help.apple.com/app-store-connect/#/dev38f592ac9

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-14 11:50:01 +01:00
jakub 57a81fbca0 ci: fix Jenkins lib function for reading version
Otherwise we just get `UNKNOWN` in release filenames.

Depends on: https://github.com/status-im/status-jenkins-lib/pull/56

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-13 18:47:38 +01:00
Andrea Maria Piana d3f6cbf687 Upgrade status-go to 0.131.1 2023-02-13 16:13:37 +00:00
Alexander 5e84446f9d The [Cancel] and [Join] buttons are hidden within 'Join Community' overlay (#14971)
* The [Cancel] and [Join] buttons are hidden within 'Join Community' overlay

* Lint

* Fixes

* Lint fix
2023-02-10 14:23:24 +00:00
Andrea Maria Piana 3a299e2c7f Bump version to 0.130.3 2023-02-10 14:15:55 +00:00
flexsurfer cbaf5db674 [#15046] Contacts in contact list are sorted by 3-random name (#15051)
(cherry picked from commit b1d4368154)
2023-02-10 10:48:42 +01:00
Andrea Maria Piana 59d122d6e3 Bump status-go to 0.130.1 2023-02-09 15:33:12 +00:00
Omar Basem 4d99227036 fix: image actions (#14996)
* fix: image actions and reactions
2023-02-09 11:01:12 +00:00
Andrea Maria Piana 574e69acae Bump version to 1.21.0 2023-02-08 17:50:26 +00:00
Andrea Maria Piana feae148ec8 Fix contact updates state recovery
https://github.com/status-im/status-go/compare/7360e072...dea21f44
2023-02-08 17:49:36 +00:00
jakub 8ebad39c25 ci: add cleanup step to all e2e Jenkins jobs
Otherwise we get multiple APKs in the `results` folder.
```
admin@linux-01.he-eu-hel1.ci.devel:/home/jenkins/workspace/status-mobile/e2e/status-app-prs % ls -l result
total 502236
-rw-r--r-- 1 jenkins jenkins 57334087 Feb  7 10:25 StatusIm-Mobile-230207-101618-991339-pr14988-x86.apk
-rw-r--r-- 1 jenkins jenkins 57080127 Feb  7 13:18 StatusIm-Mobile-230207-131114-098c05-pr14977-x86.apk
-rw-r--r-- 1 jenkins jenkins 57088322 Feb  7 14:19 StatusIm-Mobile-230207-141155-05cc4c-pr15002-x86.apk
...
```
And `utils.findFile()` just pick the first one alphabeticlly.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-08 18:26:45 +01:00
Brian Sztamfater 8cfc6ecb4f chore: add accessiblity ids to message status views
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-02-08 14:06:28 -03:00
Roman Volosovskyi cc348fda99 [#14962] Update AC notification on EditMessage 2023-02-08 16:43:40 +01:00
Volodymyr Kozieiev 5f119c4b3a added unread mentions counter 2023-02-08 13:01:04 +00:00
Parvesh Monu bf932e6825 Add jump-to button to community-overview screen (#15003) 2023-02-08 16:13:14 +05:30
Icaro Motta 0c59ed5ceb Improve guidelines (#15008)
- New section: Use [] instead of () in Reagent components: New section after
  this comment https://github.com/status-im/status-mobile/pull/15005#discussion_r1098220176
- Updated section "Don't use percents to define width/height": reworded to
  follow the style of the rest of the document.
- Update section "Accessibility labels": added example about avoiding dynamic
  labels.
2023-02-07 10:05:38 -03:00
jakub 875f9f1acc ci: fix absolute path of APK for e2e PR jobs
Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-07 13:07:23 +01:00
Icaro Motta 98b219191f Fix segmented tab component (#15001)
Fixes #14999 

Fix UI regression in the segmented tab component, introduced by PR https://github.com/status-im/status-mobile/pull/14883.

No area was impacted because segmented tabs are not used yet.
2023-02-07 08:27:27 -03:00
John Ngei f8b5b35063 Update community home scrolling to support sticky header and tabs (#14929)
* communities home sticky tabs

* Communities home screen scroll behaviours

* refactored scroll-page component
2023-02-07 12:58:38 +03:00
erikseppanen 7315dc8914 Support join.status.im links for adding a contact (#14964)
* Support join.status.im links for adding a contact (#14814)

* refactor tests, add caret to regex
2023-02-06 17:23:34 -05:00
jakub e61bd769a8 ci: fetch E2E APK from android-e2e jobs
Using `copyArtifacts()` is more reliable and faster then fetching APKs
based on URLs acquired by parsing GitHub comments from Jenkins builds.

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-06 18:37:53 +01:00
Parvesh Monu b9ac26edd7 fix selected members are not shown on the group creation screen (#14991) 2023-02-06 22:13:45 +05:30
Parvesh Monu 739d10a9ef Add tests for bottom-tabs-notifications-data subscription (#14992) 2023-02-06 20:40:46 +05:30
jakub 361ddb338e ci: drop uploading e2e builds to SauceLabs
Since uploads to SauceLabs were dropped from `Fastfile` in:
https://github.com/status-im/status-mobile/pull/14969

Also dropped:
- Useless Diawi upload of APK
- Useless DO Spaces upload of IPA

Signed-off-by: Jakub Sokołowski <jakub@status.im>
2023-02-06 15:15:51 +01:00
John Ngei 91d0e106f2 showing sticky bar on scrolling discover screen (#14825) 2023-02-06 15:41:34 +03:00
Churikova Tetiana 89039cd79a e2e: remove upload to sauce from fastlane and fix in e2e 2023-02-03 14:03:15 +01:00
Brian Sztamfater 0202af8070 feat: style delivery states
Signed-off-by: Brian Sztamfater <brian@status.im>
2023-02-03 09:53:15 -03:00
frank 0472140f02 fix: Unable to add new contact on receiver device after local pairing until app relaunch (#14936) 2023-02-03 16:07:27 +08:00
87 changed files with 1465 additions and 881 deletions
+1 -1
View File
@@ -1 +1 @@
1.20.2
1.21.0
+3 -11
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -75,20 +75,12 @@ pipeline {
stage('Upload') {
steps { script {
def urls = apks.collect { s3.uploadArtifact(it) }
/* return only the universal APK */
if (urls.size() > 1) {
if (urls.size() > 1) { /* Return only the universal APK. */
env.PKG_URL = urls.find { it.contains('universal') }
} else { /* if no universal is available pick first */
} else { /* If no universal is available pick first. */
env.PKG_URL = urls.first()
}
jenkins.setBuildDesc(APK: env.PKG_URL)
/* e2e builds get tested in SauceLabs */
if (utils.isE2EBuild()) {
env.SAUCE_URL = android.uploadToSauceLabs()
}
if (utils.isNightlyBuild()) {
env.DIAWI_URL = android.uploadToDiawi()
}
} }
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
pipeline {
agent { label 'linux' }
@@ -105,7 +105,7 @@ pipeline {
e2eApk = utils.getEnv(apke2e, 'SAUCE_URL')
build(
job: 'status-mobile/e2e/status-app-nightly',
parameters: [string(name: 'APK_NAME', value: e2eApk)],
parameters: [string(name: 'APK_URL', value: e2eApk)],
wait: false
)
} }
+4 -8
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
@@ -72,15 +72,11 @@ pipeline {
}
}
stage('Upload') {
when { expression { !utils.isReleaseBuild() } }
steps { script {
env.PKG_URL = s3.uploadArtifact(api)
env.DIAWI_URL = ios.uploadToDiawi()
env.PKG_URL = env.DIAWI_URL
jenkins.setBuildDesc(IPA: env.PKG_URL)
/* e2e builds get tested in SauceLabs */
if (utils.isE2EBuild()) {
env.SAUCE_URL = ios.uploadToSauceLabs()
} else if (!utils.isReleaseBuild()) {
env.DIAWI_URL = ios.uploadToDiawi()
}
} }
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
pipeline {
agent { label params.AGENT_LABEL }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()
+14 -2
View File
@@ -4,8 +4,8 @@ pipeline {
parameters {
string(
name: 'APK_NAME',
description: 'Filename of APK uploaded to SauceLabs.',
name: 'APK_URL',
description: 'URL of APK uploaded to SauceLabs.',
)
string(
name: 'KEYWORD_EXPRESSION',
@@ -20,6 +20,14 @@ pipeline {
stages {
stage('Prep') {
steps { script {
if (params.PR_ID == null) {
error("PR_ID parameter not set!")
}
} }
}
stage('Setup') {
steps { script {
dir('test/appium') {
@@ -27,6 +35,7 @@ pipeline {
}
} }
}
stage('Test') {
steps {
withCredentials([
@@ -88,5 +97,8 @@ pipeline {
)
}
}
cleanup {
sh 'make purge'
}
}
}
+37 -16
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
pipeline {
@@ -10,16 +10,6 @@ pipeline {
description: 'Name of the branch to checkout and build.',
defaultValue: 'develop',
)
/* Commented to use TEST_MARKERS values from job params
string(
name: 'TEST_MARKERS',
description: 'Marker expression for matching tests to run.',
defaultValue: 'new_ui_critical',
) */
string(
name: 'APK_NAME',
description: 'Filename of APK uploaded to SauceLabs, path, or URL.',
)
string(
name: 'PR_ID',
description: 'ID of the Pull Request triggering this build.',
@@ -34,6 +24,19 @@ pipeline {
description: 'IDs of the TestRail case, separated by a comma (Optional)',
defaultValue: '',
)
/* FIXME: Remove this no longer relevant argument */
string(
name: 'APK_NAME',
description: 'OBSOLETE ARGUMENT TO BE REMOVED',
defaultValue: 'DUMMY',
)
/* Commented to use TEST_MARKERS values from job params
string(
name: 'TEST_MARKERS',
description: 'Marker expression for matching tests to run.',
defaultValue: 'new_ui_critical',
)
*/
}
options {
@@ -41,12 +44,25 @@ pipeline {
}
stages {
stage('Checks') {
stage('Prep') {
steps { script {
if (params.APK_NAME == null) { error("APK_NAME parameter not set!") }
if (params.PR_ID == null) { error("PR_ID parameter not set!") }
currentBuild.displayName = "PR-${params.PR_ID}"
if (params.PR_ID == null) {
error("PR_ID parameter not set!")
}
} }
}
stage('Fetch') {
steps { script { /* WARNING: This copies the latest available artifact. */
copyArtifacts(
projectName: "status-mobile/prs/android-e2e/PR-${params.PR_ID}",
selector: lastWithArtifacts(),
)
apk_path = "${env.WORKSPACE}/${utils.findFile('result/*.apk')}"
} }
}
stage('Setup') {
steps { script {
dir('test/appium') {
@@ -54,9 +70,9 @@ pipeline {
}
} }
}
stage('Test') {
steps { script {
currentBuild.displayName = "PR-${params.PR_ID}"
/* for managing optional arguments */
def extraPytestOpts = ''
if (params.TR_CASE_IDS != '') {
@@ -103,7 +119,7 @@ pipeline {
--rerun_count=2 \
--testrail_report=True \
-k \"${params.KEYWORD_EXPRESSION}\" \
--apk=${params.APK_NAME} \
--apk=${apk_path} \
--build=PR-${params.PR_ID}-${utils.timestamp()} \
--pr_number=${params.PR_ID} \
${extraPytestOpts}
@@ -113,4 +129,9 @@ pipeline {
} }
}
}
post {
cleanup {
sh 'make purge'
}
}
}
+21 -6
View File
@@ -4,12 +4,12 @@ pipeline {
parameters {
string(
name: 'APK_NAME',
description: 'Filename of APK uploaded to SauceLabs (base for upgrade, usually release build)',
name: 'APK_URL',
description: 'URL of APK to be tested(base for upgrade, usually release build)',
)
string(
name: 'APK_NAME_UPGRADE',
description: 'Filename of APK of upgraded application (installed on top of base)',
name: 'APK_URL_UPGRADE',
description: 'URL of APK of upgraded application (installed on top of base)',
)
string(
name: 'KEYWORD_EXPRESSION',
@@ -29,6 +29,17 @@ pipeline {
stages {
stage('Prep') {
steps { script {
if (params.APK_URL == null) {
error("APK_URL parameter not set!")
}
if (params.APK_URL_UPGRADE == null) {
error("APK_URL_UPGRADE parameter not set!")
}
} }
}
stage('Setup') {
steps { script {
dir('test/appium') {
@@ -36,6 +47,7 @@ pipeline {
}
} }
}
stage('Test') {
steps { script {
/* for managing optional arguments */
@@ -77,8 +89,8 @@ pipeline {
--numprocesses 4 \
--rerun_count=2 \
--testrail_report=True \
--apk=${params.APK_NAME} \
--apk_upgrade=${params.APK_NAME_UPGRADE} \
--apk=${params.APK_URL} \
--apk_upgrade=${params.APK_URL_UPGRADE} \
${extraPytestOpts}
"""
}
@@ -103,5 +115,8 @@ pipeline {
)
}
}
cleanup {
sh 'make purge'
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.6.3'
library 'status-jenkins-lib@v1.6.6'
pipeline {
agent { label 'linux' }
+45 -6
View File
@@ -63,12 +63,19 @@ the source file. For a real example, see
### Don't use percents to define width/height
We shouldn't use percentage:
- because 100% doesn't make sense in flexbox
- because we always have fixed margins or paddings in the design. For example, Instead of using `80%` we should use `padding-horizontal 20`. This is because `%` will be different on different devices in pixels, but we should always have same the paddings in pixels on all devices.
In ReactNative, all layouts use the [flexbox
model](https://reactnative.dev/docs/flexbox), so percentages are unnecessary the
vast majority of the time, don't use them. Check out this great [interactive
flexbox guide](https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/) by
Joshua Comeau.
```clojure
;; bad
[rn/view {:style {:width "80%"}}]
;; good
[rn/view {:style {:padding-horizontal 20}}]
```
#### Styles def vs defn
@@ -163,6 +170,26 @@ Use the simple `defn` to declare components. Don't use `utils.views/defview` and
(do-something window-width)))
```
#### Use `[]` instead of `()` in Reagent components
- The `()` version [does NOT work with Form-2 and
Form-3](https://github.com/reagent-project/reagent/blob/master/doc/UsingSquareBracketsInsteadOfParens.md#a-further-significant-why)
components.
- Components defined with `[]` will be [more efficient at re-render
time](https://github.com/reagent-project/reagent/blob/master/doc/UsingSquareBracketsInsteadOfParens.md#which-and-why)
because they're interpreted by Reagent and transformed into distinct React
components, with their own lifecycle.
```clojure
;; bad
[rn/view
(message-card message)]
;; good
[rn/view
[message-card message]]
```
### Using re-frame subscriptions and dispatching events
Use the `utils.re-frame` namespace instead of `re-frame.core` to subscribe and
@@ -300,8 +327,8 @@ core interop macros.
### Accessibility labels
Use keywords instead of strings. As a bonus, remember keywords are cached in
memory.
Accessibility labels are currently used only for end-to-end tests. Use keywords
instead of strings (remember keywords are cached).
```clojure
;; bad
@@ -313,6 +340,18 @@ memory.
"Markov"]
```
Avoid dynamic labels, for example to specify an element's index because
[Appium](https://appium.io/) already supports element selection based on
indices.
```clojure
;; bad
[button {:accessibility-label (str "do-something" index)}]
;; good
[button {:accessibility-label :do-something}]
```
### Icons
Use the appropriate keyword qualification/namespace and don't directly require
-42
View File
@@ -50,25 +50,6 @@ def retry_curl_upload(url, file, auth, conn_timeout = 5, timeout = 60, retries =
end
end
# uploads `file` to sauce labs (overwrites if there is anoter file from the
# same commit)
def upload_to_saucelabs(file)
key = ENV['SAUCE_ACCESS_KEY']
username = ENV['SAUCE_USERNAME']
unique_name = ENV['SAUCE_LABS_NAME']
url = "https://eu-central-1.saucelabs.com/rest/v1/storage/#{username}/#{unique_name}?overwrite=true"
upload_result = retry_curl_upload(url, file, "#{username}:#{key}")
# fail the lane if upload fails
unless upload_result.include? 'filename'
UI.user_error!(
"failed to upload file to saucelabs despite retries: #{upload_result}"
)
end
end
# Creates and unlocks a keychain into which Fastlane match imports signing keys and certs.
class Keychain
attr_accessor :name, :pass
@@ -353,27 +334,4 @@ platform :android do
version_code: '2020042307'
)
end
desc '`fastlane android upload_diawi` - upload .apk to diawi'
desc 'expects to have an .apk prepared: `result/app.apk`'
desc 'expects to have a diawi token as DIAWI_TOKEN env variable'
desc 'expects to have a github token as GITHUB_TOKEN env variable'
desc "will fails if file isn't there"
desc '---'
desc 'Output: writes `fastlane/diawi.out` file url of the uploded file'
lane :upload_diawi do
uniApk = APK_PATHS.detect { |a| a.include? 'universal' }
upload_to_diawi(uniApk)
end
desc '`fastlane android saucelabs` - upload .apk to sauce labs'
desc 'expects to have an .apk prepared: `result/app.apk`'
desc 'expects to have a saucelabs access key as SAUCE_ACCESS_KEY env variable'
desc 'expects to have a saucelabs username token as SAUCE_USERNAME env variable'
desc 'expects to have a saucelabs destination name as SAUCE_LABS_NAME env variable'
desc "will fails if file isn't there"
lane :saucelabs do
e2eApk = APK_PATHS.detect { |a| a.include? 'x86' }
upload_to_saucelabs(e2eApk)
end
end
+4 -4
View File
@@ -210,8 +210,8 @@ PODS:
- React
- react-native-blob-util (0.13.18):
- React-Core
- react-native-blur (3.6.1):
- React
- react-native-blur (4.3.0):
- React-Core
- react-native-camera-kit (8.0.4):
- React
- react-native-cameraroll (4.0.4):
@@ -640,7 +640,7 @@ SPEC CHECKSUMS:
FBLazyVector: 352a8ca9bbc8e2f097d680747a8c97ecef12d469
FBReactNativeSpec: 7dfb84f624136a45727c813ed21d130cd3e61beb
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 6934faae5afbec23475648c8aeb6047ce973af65
glog: 997518ea2aa2d8cd5df9797b641b758d52ecf2bc
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c
@@ -658,7 +658,7 @@ SPEC CHECKSUMS:
React-jsinspector: fdbc08866b34ae8e1b788ea1cbd9f9d1ca2aa3d6
react-native-background-timer: 1f7d560647b40e6a60b01c452ba29c54bf581fc4
react-native-blob-util: 600972b1782380a5a7d5db61a3817ea32349dae9
react-native-blur: 4568dd93d1d82748c180df8beb2d929c97b13b47
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
react-native-camera-kit: 498a6d111a904834e0824e9073cfadef7303235f
react-native-cameraroll: 88f4e62d9ecd0e1f253abe4f685474f2ea14bfa2
react-native-config: c98128a72bc2c3a1ca72caec0b021f0fa944aa29
+1 -1
View File
@@ -52,7 +52,7 @@
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>
<string>1aa92c4d-6194-4d7d-b70a-16b48256b87e</string>
<string>37d5ac79-0eb2-4e66-9117-8a8515185a7f</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>whatsapp</string>
+1 -1
View File
@@ -48,7 +48,7 @@
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>
<string>1aa92c4d-6194-4d7d-b70a-16b48256b87e</string>
<string>37d5ac79-0eb2-4e66-9117-8a8515185a7f</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>whatsapp</string>
Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

+1 -1
View File
@@ -82,7 +82,7 @@
:optimizations :simple
:target :node-test
;; When running tests without a REPL you can uncomment below line to `make test-watch` a specific file
;;:ns-regexp "status-im2.subs.subs-test$"
;; :ns-regexp "status-im2.subs.chat.messages-test$"
:main
status-im.test-runner/main
;; set :ui-driven to true to let shadow-cljs inject node-repl
+2 -1
View File
@@ -255,7 +255,8 @@
{:background-color
(if (= state :pressed)
(colors/theme-colors colors/neutral-100 colors/white)
:transparent)}
:transparent)
:width width}
style)}
[rn/view
{:style (merge
@@ -7,7 +7,7 @@
(defn community-card-view-item
[{:keys [name description locked images
status tokens cover tags width]} on-press]
[rn/touchable-opacity
[rn/touchable-without-feedback
{:accessibility-label :community-card-item
:on-press on-press}
[rn/view {:style (style/community-card 20)}
+2 -1
View File
@@ -224,7 +224,8 @@
{:style {:flex 1
:flex-direction :row
:align-items :center}}
[left-section-view left-section put-middle-section-on-left?]
(when left-section
[left-section-view left-section put-middle-section-on-left?])
(when put-middle-section-on-left?
[mid-section-view
(assoc mid-section-props
@@ -3,8 +3,7 @@
(defn container
[]
{:flex 1
:flex-direction :row
{:flex-direction :row
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-80-opa-40)
:padding 11
:align-self :stretch
+8 -7
View File
@@ -29,11 +29,12 @@
{:margin-left (if (= 0 indx) 0 2)
:flex 1}
[tab/view
{:id id
:segmented true
:size size
:active (= id active-id)
:on-press #(do (reset! active-tab-id %)
(when on-change
(on-change %)))}
{:id id
:segmented? true
:size size
:active (= id active-id)
:on-press (fn [tab-id]
(reset! active-tab-id tab-id)
(when on-change
(on-change tab-id)))}
label]])]))))
+8 -1
View File
@@ -31,11 +31,16 @@
{:flex-direction :row})
(defn tab
[{:keys [size disabled background-color show-notification-dot?]}]
[{:keys [background-color
disabled
segmented?
show-notification-dot?
size]}]
(let [border-radius (size->border-radius size)
padding (size->padding-left size)]
(merge {:height size
:align-items :center
:justify-content :center
:flex-direction :row
:border-top-left-radius border-radius
:border-bottom-left-radius border-radius
@@ -48,6 +53,8 @@
{:padding-right 1}
{:border-radius border-radius
:padding-right padding})
(when segmented?
{:flex 1})
(when disabled
{:opacity tab-background-opacity}))))
+2
View File
@@ -55,6 +55,7 @@
id
on-press
override-theme
segmented?
size
notification-dot?]
:or {size 32}}
@@ -80,6 +81,7 @@
[rn/view
{:style (style/tab {:size size
:disabled disabled
:segmented? segmented?
:background-color background-color
:show-notification-dot? show-notification-dot?})}
(when before
+6 -2
View File
@@ -193,17 +193,21 @@
[alias name nickname]))
(defn add-searchable-phrases-to-contact
[{:keys [alias name added? blocked? identicon public-key nickname ens-verified]} community-chat?]
[{:keys [alias name added? blocked? identicon public-key nickname ens-verified display-name]}
community-chat?]
(when (and alias
(not (string/blank? alias))
(or name
display-name
nickname
added?
community-chat?)
(not blocked?))
(add-searchable-phrases
{:alias alias
:name (or (and ens-verified (utils/safe-replace name ".stateofus.eth" "")) alias)
:name (or (and ens-verified (utils/safe-replace name ".stateofus.eth" ""))
(when-not (string/blank? display-name) display-name)
alias)
:identicon identicon
:nickname nickname
:ens-verified ens-verified
+2 -2
View File
@@ -43,8 +43,8 @@
(defn sort-contacts
[contacts]
(sort (fn [c1 c2]
(let [name1 (or (:name c1) (:address c1) (:public-key c1))
name2 (or (:name c2) (:address c2) (:public-key c2))]
(let [name1 (first (:two-names c1))
name2 (first (:two-names c2))]
(compare (string/lower-case name1)
(string/lower-case name2))))
(vals contacts)))
+44 -25
View File
@@ -1,5 +1,5 @@
(ns status-im.integration-test
(:require [cljs.test :refer [deftest is run-tests]]
(:require [cljs.test :refer [deftest is]]
[clojure.string :as string]
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
@@ -10,7 +10,7 @@
[status-im.transport.core :as transport]
[status-im.utils.test :as utils.test]
status-im2.navigation.core
status-im2.subs.root ;;so integration tests can run independently
status-im2.subs.root ; so integration tests can run independently
[taoensso.timbre :as log]
[utils.security.core :as security]))
@@ -107,9 +107,7 @@
[::transport/messenger-started]
(assert-messenger-started)
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))
(deftest create-community-test
@@ -156,9 +154,7 @@
[:wallet.accounts/account-stored]
(assert-new-account-created) ; assert account was created
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(deftest back-up-seed-phrase-test
@@ -191,9 +187,7 @@
[:my-profile/finish-success]
(is (nil? @(rf/subscribe [:mnemonic]))) ; assert seed phrase has been removed
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not
; in
; an inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout)))))))))
(def multiaccount-name "Narrow Frail Lemming")
@@ -226,9 +220,7 @@
[::transport/messenger-started]
(assert-messenger-started)
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(def chat-id
@@ -254,9 +246,7 @@
(rf/dispatch-sync [:chat/navigate-to-chat chat-id])
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in
; an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(deftest delete-chat-test
@@ -282,9 +272,7 @@
(rf/dispatch-sync [:chat.ui/show-remove-confirmation chat-id])
(rf/dispatch-sync [:chat.ui/remove-chat chat-id])
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not
; in an
; inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))
(deftest mute-chat-test
@@ -316,10 +304,41 @@
[:chat/mute-successfully]
(is (not @(rf/subscribe [:chats/muted chat-id])))
(logout!)
(rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is
; not in
; an inconsistent state between tests
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))))
(comment
(run-tests))
(deftest add-contact-test
(log/info "========= add-contact-test ==================")
(let
[compressed-key "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA"
public-key
"0x048a6773339d11ccf5fd81677b7e54daeec544a1287bd92b725047ad6faa9a9b9f8ea86ed5a226d2a994f5f46d0b43321fd8de7b7997a166e67905c8c73cd37cea"
three-words-name "Rich Total Pondskater"]
(rf-test/run-test-async
(initialize-app!)
(rf-test/wait-for
[:setup/initialize-view]
(generate-and-derive-addresses!)
(rf-test/wait-for
[:multiaccount-generate-and-derive-addresses-success]
(assert-multiaccount-loaded)
(create-multiaccount!)
(rf-test/wait-for
[::transport/messenger-started]
(assert-messenger-started)
;; search for contact using compressed key
(rf/dispatch [:contacts/set-new-identity compressed-key])
(rf-test/wait-for
[:contacts/set-new-identity-success]
(let [new-identity @(rf/subscribe [:contacts/new-identity])]
(is (= public-key (:public-key new-identity)))
(is (= :valid (:state new-identity))))
;; click 'view profile' button
(rf/dispatch [:chat.ui/show-profile public-key])
(rf-test/wait-for
[:contacts/contact-built]
(let [contact @(rf/subscribe [:contacts/current-contact])]
(is (= three-words-name (:three-words-name (:names contact)))))
(logout!)
(rf-test/wait-for [::logout/logout-method]
(assert-logout))))))))))
+15 -16
View File
@@ -40,11 +40,8 @@
:three-words-name (or alias (gfycat/generate-gfy public-key))}
;; Preferred name is our own otherwise we make sure it's verified
(or preferred-name (and ens-verified name))
(assoc :ens-name (str "@" (or (stateofus/username ens-name) ens-name))))))
(assoc :ens-name (or (stateofus/username ens-name) ens-name)))))
;; NOTE: this does a bit of unnecessary work, we could short-circuit the work
;; once the first two are found, i.e don't calculate short key if 2 are already
;; available
(defn contact-two-names
"Returns vector of two names in next order nickname, ens name, display-name, three word name, public key"
[{:keys [names
@@ -56,28 +53,30 @@
display-name
three-words-name]}
(or names (contact-names contact))
short-public-key (when public-key?
(utils/get-shortened-address (or compressed-key
public-key)))]
(->> [nickname ens-name display-name three-words-name short-public-key]
(remove string/blank?)
(take 2))))
non-empty-names (remove string/blank? [nickname ens-name display-name three-words-name])]
(if (> (count non-empty-names) 1)
(vec (take 2 non-empty-names))
[(first non-empty-names)
(when public-key? (utils/get-shortened-address (or compressed-key public-key)))])))
(defn contact-with-names
"Returns contact with :names map "
[contact]
(assoc contact :names (contact-names contact)))
(let [contact' (assoc contact :names (contact-names contact))]
(assoc contact' :two-names (contact-two-names contact' true))))
(defn displayed-name
"Use preferred name, name or alias in that order"
[{:keys [name preferred-name alias public-key ens-verified]}]
(let [ens-name (or preferred-name
"Use preferred name, display-name, name or alias in that order"
[{:keys [name display-name preferred-name alias public-key ens-verified]}]
(let [display-name (if (string/blank? display-name) nil display-name)
ens-name (or preferred-name
display-name
name)]
;; Preferred name is our own otherwise we make sure it's verified
(if (or preferred-name (and ens-verified name))
(let [username (stateofus/username ens-name)]
(str "@" (or username ens-name)))
(or alias (gfycat/generate-gfy public-key)))))
(or username ens-name))
(or display-name alias (gfycat/generate-gfy public-key)))))
(defn contact-by-identity
[contacts identity]
+2 -2
View File
@@ -29,11 +29,11 @@
(testing "names is nil"
(testing "nickname has precedence"
(is
(= [nickname formatted-ens]
(= [nickname ens-name]
(ma/contact-two-names contact public-key))))
(testing "ens name is second option"
(is
(= [formatted-ens display-name]
(= [ens-name display-name]
(ma/contact-two-names
(dissoc contact :nickname)
public-key))))
+18 -4
View File
@@ -8,6 +8,8 @@
[status-im.ethereum.core :as ethereum]
[status-im.ethereum.eip681 :as eip681]
[status-im.ethereum.ens :as ens]
[status-im.utils.types :as types]
[status-im.native-module.core :as status]
[status-im.ethereum.stateofus :as stateofus]
[status-im2.utils.validators :as validators]
[status-im.utils.http :as http]
@@ -71,15 +73,27 @@
(defn match-contact-async
[chain {:keys [user-id ens-name]} callback]
(let [valid-key (and (validators/valid-public-key? user-id)
(not= user-id ens/default-key))]
(let [valid-public-key? (and (validators/valid-public-key? user-id)
(not= user-id ens/default-key))
valid-compressed-key? (validators/valid-compressed-key? user-id)]
(cond
valid-key
valid-public-key?
(callback {:type :contact
:public-key user-id
:ens-name ens-name})
(and (not valid-key)
valid-compressed-key?
(status/compressed-key->public-key
user-id
(fn [response]
(let [{:keys [error]} (types/json->clj response)]
(when-not error
(match-contact-async
chain
{:user-id (str "0x" (subs response 5)) :ens-name ens-name}
callback)))))
(and (not valid-public-key?)
(string? user-id)
(not (string/blank? user-id))
(not= user-id "0x"))
+4 -4
View File
@@ -54,9 +54,9 @@
:peers-count (count (:peers peer-stats)))}))
(defn handle-local-pairing-signals
[signal-type]
(log/info "local pairing signal received"
{:signal-type signal-type}))
[event]
(log/debug "local pairing signal received"
{:event event}))
(rf/defn process
{:events [:signals/signal-received]}
@@ -110,5 +110,5 @@
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
cofx
(js->clj event-js :keywordize-keys true))
"localPairing" (handle-local-pairing-signals event-str)
"localPairing" (handle-local-pairing-signals (js->clj event-js :keywordize-keys true))
(log/debug "Event " type " not handled"))))
@@ -3,7 +3,8 @@
[quo2.foundations.colors :as quo2.colors]
[status-im2.constants :as constants]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.styles.photos :as photos]))
[status-im.ui.screens.chat.styles.photos :as photos]
[quo2.foundations.typography :as typography]))
(defn style-message-text
[]
@@ -311,6 +312,17 @@
assoc
:text-decoration-line :line-through)))
(defn edited-style
[]
(cond->
(update (default-text-style)
:style
assoc
:color (quo2.colors/theme-colors quo2.colors/neutral-40 quo2.colors/neutral-50)
:font-size 13
:line-height 18.2
:letter-spacing (typography/tracking 13))))
(def code-block-background "#2E386B")
(defn inline-code-style
@@ -76,8 +76,10 @@
:icon-color (colors/theme-colors colors/neutral-50 colors/neutral-40)
:accessibility-label :start-a-new-chat
:icon :i/new-message
:on-press #(hide-sheet-and-dispatch [:bottom-sheet/show-sheet
:start-a-new-chat {}])}]
:on-press (fn []
(rf/dispatch [:group-chat/clear-contacts])
(hide-sheet-and-dispatch [:bottom-sheet/show-sheet
:start-a-new-chat {}]))}]
[quo2/menu-item
{:type :transparent
:title (i18n/label :t/add-a-contact)
+6 -2
View File
@@ -259,7 +259,9 @@
(views/letsubs [logging-in? [:multiaccounts/login]]
[components.plus-button/plus-button-old
{:on-press (when-not logging-in?
#(re-frame/dispatch [:bottom-sheet/show-sheet :start-a-new-chat {}]))
(fn []
(re-frame/dispatch [:group-chat/clear-contacts])
(re-frame/dispatch [:bottom-sheet/show-sheet :start-a-new-chat {}])))
:loading logging-in?
:accessibility-label :new-chat-button}]))
@@ -268,7 +270,9 @@
(views/letsubs [logging-in? [:multiaccounts/login]]
[components.plus-button/plus-button-old
{:on-press (when-not logging-in?
#(re-frame/dispatch [:bottom-sheet/show-sheet :start-a-new-chat {}]))
(fn []
(re-frame/dispatch [:group-chat/clear-contacts])
(re-frame/dispatch [:bottom-sheet/show-sheet :start-a-new-chat {}])))
:loading logging-in?
:accessibility-label :new-chat-button}]))
@@ -16,6 +16,7 @@
:justify-content :center
:align-items :center})
(defn chat-button
[{:keys [bottom]}]
{:bottom (- bottom 50)})
(def chat-button
{:position :absolute
:bottom 30
:align-self :center})
@@ -6,15 +6,12 @@
[reagent.core :as reagent]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[status-im.ui.components.react :as react]
[react-native.core :as rn]
[utils.re-frame :as rf]
[status-im.ui.components.toolbar :as toolbar]
[status-im2.common.contact-list.view :as contact-list]
[quo2.components.markdown.text :as text]
[status-im.ui.components.invite.events :as invite.events]
[status-im.ui2.screens.chat.components.new-chat.styles :as style]
[quo.react :as quo.react]
[quo.components.safe-area :as safe-area]
[status-im.react-native.resources :as resources]))
(defn- hide-sheet-and-dispatch
@@ -34,11 +31,11 @@
(defn- no-contacts-view
[]
[react/view
[rn/view
{:style {:justify-content :center
:align-items :center
:margin-top 120}}
[react/image
[rn/image
{:source (resources/get-image (if (quo2.colors/dark?) :no-contacts-dark :no-contacts))}]
[text/text
{:weight :semi-bold
@@ -65,7 +62,6 @@
[]
[:f>
(fn []
(quo.react/effect! #(rf/dispatch [:group-chat/clear-contacts]) [])
(let [contacts (rf/sub
[:contacts/sorted-and-grouped-by-first-letter])
selected-contacts-count (rf/sub [:selected-contacts-count])
@@ -76,9 +72,8 @@
added? (reagent/atom '())
{:keys [nickname ens-name three-words-name]} names
first-username (or ens-name nickname three-words-name)
no-contacts? (empty? contacts)
safe-area (safe-area/use-safe-area)]
[react/view {:style {:height (* window-height 0.9)}}
no-contacts? (empty? contacts)]
[rn/view {:style {:height (* window-height 0.9)}}
[quo2/button
{:type :grey
:icon true
@@ -87,7 +82,7 @@
:override-background-color (quo2.colors/theme-colors quo2.colors/neutral-10
quo2.colors/neutral-90)}
:i/close]
[react/view style/contact-selection-heading
[rn/view style/contact-selection-heading
[quo2/text
{:weight :semi-bold
:size :heading-1
@@ -101,9 +96,8 @@
(i18n/label :t/selected-count-from-max
{:selected (inc selected-contacts-count)
:max constants/max-group-chat-participants})])]
[react/view
{:style {:height 430
:margin-bottom -20}}
[rn/view
{:style {:flex 1}}
(if no-contacts?
[no-contacts-view]
[contact-list/contact-list
@@ -112,21 +106,19 @@
:added? added?
:search? false
:start-a-new-chat? true
:on-toggle on-toggle}])]
:on-toggle on-toggle}
70])]
(when contacts-selected?
[toolbar/toolbar
{:size :default
:show-border? false
:center [button/button
{:type :primary
:accessibility-label :next-button
:style (style/chat-button safe-area)
:on-press (fn []
(if one-contact-selected?
(hide-sheet-and-dispatch [:chat.ui/start-chat
public-key])
(hide-sheet-and-dispatch [:navigate-to
:new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user first-username})
(i18n/label :t/setup-group-chat))]}])]))])
[button/button
{:type :primary
:style style/chat-button
:accessibility-label :next-button
:on-press (fn []
(if one-contact-selected?
(hide-sheet-and-dispatch [:chat.ui/start-chat
public-key])
(hide-sheet-and-dispatch [:navigate-to
:new-group])))}
(if one-contact-selected?
(i18n/label :t/chat-with {:selected-user first-username})
(i18n/label :t/setup-group-chat))])]))])
@@ -88,11 +88,14 @@
"#"
literal])
"edited"
(conj acc [rn/text (style/edited-style) (str " (" (i18n/label :t/edited) ")")])
(conj acc literal)))
;; TEXT
(defn render-block
[{:keys [content content-type in-popover?]} acc
[{:keys [content content-type edited-at in-popover?]} acc
{:keys [type ^js literal children]}]
(case type
@@ -101,7 +104,10 @@
(reduce
(fn [acc e] (render-inline (:text content) content-type acc e))
[rn/text (style/text-style content-type in-popover?)]
children))
(conj
children
(when edited-at
{:type "edited"}))))
"blockquote"
(conj acc
@@ -123,17 +129,6 @@
[:<>]
(:parsed-text content)))
(defn message-status
[{:keys [outgoing-status edited-at]}]
(when (or edited-at outgoing-status)
[rn/view {:flex-direction :row}
[rn/text {:style (style/message-status-text)}
(str "["
(if edited-at
"edited"
(or outgoing-status ""))
" DEBUG]")]]))
(defn quoted-message
[{:keys [message-id chat-id]} reply pin?]
(let [{:keys [deleted? deleted-for-me?]} (get @(re-frame/subscribe [:chats/chat-messages chat-id])
+83 -82
View File
@@ -27,101 +27,102 @@
(def status
(clj->js
{:openAccounts (fn [callback]
(callback
(.openAccounts
native-status
test-dir)))
:multiAccountStoreDerived (fn [json callback]
(callback (.multiAccountStoreDerivedAccounts
native-status
json)))
{:openAccounts
(fn [callback]
(callback (.openAccounts native-status test-dir)))
:multiAccountStoreDerived
(fn [json callback]
(callback (.multiAccountStoreDerivedAccounts native-status json)))
:clearCookies identity
:clearStorageAPIs identity
:setBlankPreviewFlag identity
:callPrivateRPC (fn [payload callback]
(callback
(.callPrivateRPC
native-status
payload)))
:saveAccountAndLogin (fn [multiaccount-data password settings config
accounts-data]
(.saveAccountAndLogin
native-status
multiaccount-data
password
settings
config
accounts-data))
:logout (fn []
(.logout native-status))
:generateAlias (fn [seed]
(.generateAlias native-status seed))
:generateAliasAndIdenticonAsync (fn [seed callback]
(let [generated-identicon (.identicon native-status seed)
generated-alias (.generateAlias native-status
seed)]
(callback generated-alias generated-identicon)))
:multiAccountGenerateAndDeriveAddresses (fn [json callback]
(callback
(.multiAccountGenerateAndDeriveAddresses
native-status
json)))
:multiAccountImportMnemonic (fn [json callback]
(callback
(.multiAccountImportMnemonic
native-status
json)))
:multiAccountLoadAccount (fn [json callback]
(callback
(.multiAccountLoadAccount
native-status
json)))
:multiAccountDeriveAddresses (fn [json callback]
(callback
(.multiAccountDeriveAddresses
native-status
json)))
:initKeystore (fn [key-uid callback]
(callback
(.initKeystore
native-status
(str test-dir "/keystore/" key-uid))))
:identicon (fn [pk]
(.identicon native-status pk))
:callPrivateRPC
(fn [payload callback]
(callback (.callPrivateRPC native-status payload)))
:encodeTransfer (fn [to-norm amount-hex]
(.encodeTransfer native-status to-norm amount-hex))
:saveAccountAndLogin
(fn [multiaccount-data password settings config accounts-data]
(.saveAccountAndLogin native-status multiaccount-data password settings config accounts-data))
:encodeFunctionCall (fn [method params-json]
(.encodeFunctionCall native-status method params-json))
:logout
(fn [] (.logout native-status))
:decodeParameters (fn [decode-param-json]
(.decodeParameters native-status decode-param-json))
:generateAlias
(fn [seed] (.generateAlias native-status seed))
:hexToNumber (fn [hex]
(.hexToNumber native-status hex))
:generateAliasAndIdenticonAsync
(fn [seed callback]
(let [generated-identicon (.identicon native-status seed)
generated-alias (.generateAlias native-status seed)]
(callback generated-alias generated-identicon)))
:numberToHex (fn [num-str]
(.numberToHex native-status num-str))
:multiAccountGenerateAndDeriveAddresses
(fn [json callback]
(callback (.multiAccountGenerateAndDeriveAddresses native-status json)))
:checkAddressChecksum (fn [address]
(.checkAddressChecksum native-status address))
:multiAccountImportMnemonic
(fn [json callback]
(callback (.multiAccountImportMnemonic native-status json)))
:sha3 (fn [str]
(.sha3 native-status str))
:multiAccountLoadAccount
(fn [json callback]
(callback (.multiAccountLoadAccount native-status json)))
:toChecksumAddress (fn [address]
(.toChecksumAddress native-status address))
:multiAccountDeriveAddresses
(fn [json callback]
(callback (.multiAccountDeriveAddresses native-status json)))
:isAddress (fn [address]
(.isAddress native-status address))
:multiformatDeserializePublicKey
(fn [public-key deserialization-key callback]
(callback (.multiformatDeserializePublicKey
native-status
public-key
deserialization-key)))
:validateMnemonic (fn [json callback]
(callback
(.validateMnemonic
native-status
json)))
:initKeystore
(fn [key-uid callback]
(callback (.initKeystore native-status
(str test-dir "/keystore/" key-uid))))
:identicon
(fn [pk] (.identicon native-status pk))
:encodeTransfer
(fn [to-norm amount-hex]
(.encodeTransfer native-status to-norm amount-hex))
:encodeFunctionCall
(fn [method params-json]
(.encodeFunctionCall native-status method params-json))
:decodeParameters
(fn [decode-param-json]
(.decodeParameters native-status decode-param-json))
:hexToNumber
(fn [hex] (.hexToNumber native-status hex))
:numberToHex
(fn [num-str] (.numberToHex native-status num-str))
:checkAddressChecksum
(fn [address] (.checkAddressChecksum native-status address))
:sha3
(fn [str] (.sha3 native-status str))
:toChecksumAddress
(fn [address] (.toChecksumAddress native-status address))
:isAddress
(fn [address] (.isAddress native-status address))
:validateMnemonic
(fn [json callback] (callback (.validateMnemonic native-status json)))
:startLocalNotifications identity}))
@@ -113,11 +113,7 @@
:pop-to-root-tab-fx :profile-stack}
public-key
(navigation/navigate-to-cofx (-> cofx
(assoc-in [:db :contacts/identity] public-key)
(assoc-in [:db :contacts/ens-name] ens-name))
:profile
{})))
{:dispatch [:chat.ui/show-profile public-key ens-name]}))
(rf/defn handle-eip681
[cofx data]
@@ -31,13 +31,13 @@
:overflow :hidden})
(defn content-style
[insets]
[insets bottom-safe-area-spacing?]
{:position :absolute
:left 0
:right 0
:top 0
:padding-top border-radius
:padding-bottom (:bottom insets)})
:padding-bottom (if bottom-safe-area-spacing? (:bottom insets) 0)})
(defn selected-background
[]
+16 -14
View File
@@ -81,23 +81,25 @@
(defn bottom-sheet
[props children]
(let [{on-cancel :on-cancel
disable-drag? :disable-drag?
show-handle? :show-handle?
visible? :visible?
backdrop-dismiss? :backdrop-dismiss?
expandable? :expandable?
selected-item :selected-item
is-initially-expaned? :expanded?
:or {show-handle? true
backdrop-dismiss? true
expandable? false
is-initially-expaned? false}}
(let [{on-cancel :on-cancel
disable-drag? :disable-drag?
show-handle? :show-handle?
visible? :visible?
backdrop-dismiss? :backdrop-dismiss?
expandable? :expandable?
bottom-safe-area-spacing? :bottom-safe-area-spacing?
selected-item :selected-item
is-initially-expanded? :expanded?
:or {show-handle? true
backdrop-dismiss? true
expandable? false
bottom-safe-area-spacing? true
is-initially-expanded? false}}
props
content-height (reagent/atom nil)
show-bottom-sheet? (reagent/atom nil)
keyboard-was-shown? (reagent/atom false)
expanded? (reagent/atom is-initially-expaned?)
expanded? (reagent/atom is-initially-expanded?)
gesture-running? (reagent/atom false)
reset-atoms (fn []
(reset! show-bottom-sheet? nil)
@@ -226,7 +228,7 @@
{:behaviour (if platform/ios? :padding :height)
:style {:flex 1}}
[rn/view
{:style (styles/content-style insets)
{:style (styles/content-style insets bottom-safe-area-spacing?)
:on-layout (when-not (and
(some? @content-height)
(> @content-height 0))
+2 -2
View File
@@ -9,7 +9,7 @@
[quo/divider-label {:label title}])
(defn contact-list
[data]
[data padding-bottom]
(let [contacts (if (:group data)
(rf/sub [:contacts/grouped-by-first-letter])
(rf/sub [:contacts/filtered-active-sections]))]
@@ -18,6 +18,6 @@
:sticky-section-headers-enabled false
:sections contacts
:render-section-header-fn contacts-section-header
:content-container-style {:padding-bottom 20}
:content-container-style {:padding-bottom (or padding-bottom 20)}
:render-data data
:render-fn contact-list-item/contact-list-item}]))
+2 -2
View File
@@ -5,8 +5,8 @@
:align-items :center
:height 56
:padding-vertical 12
:margin-bottom 8
:padding-horizontal 20})
:padding-horizontal 20
:background-color :transparent})
(def title-column-text
{:accessibility-label :communities-screen-title
+17 -10
View File
@@ -12,23 +12,30 @@
:flex 1})
(defn blur-slider
[animation]
[animation height]
(reanimated/apply-animations-to-style
{:transform [{:translateY animation}]}
{:z-index 5
:top 0
:position :absolute
:height (if platform/ios? 100 124)
:width "100%"
:flex 1}))
{:z-index 5
:position :absolute
:top 0
:height height
:right 0
:left 0
:background-color (if platform/ios?
(colors/theme-colors
colors/white-opa-70
colors/neutral-95-opa-70)
:transparent)}))
(defn scroll-view-container
[border-radius]
{:position :absolute
{:flex 1
:position :absolute
:top -48
:left 0
:right 0
:overflow :scroll
:border-radius border-radius
:height "100%"})
:border-radius border-radius})
(defn sticky-header-title
[animation]
+67 -43
View File
@@ -27,9 +27,17 @@
(min maximum)))
(defn scroll-page-header
[scroll-height name page-nav cover sticky-header]
(let [input-range (if platform/ios? [-47 10] [0 150])
output-range (if platform/ios? [-100 0] [-169 -45])
[scroll-height
height
name
page-nav
cover
sticky-header
top-nav
title-colum
navigate-back?]
(let [input-range (if platform/ios? [-47 10] [0 92])
output-range (if platform/ios? [-208 0] [-208 -45])
y (reanimated/use-shared-value scroll-height)
translate-animation (reanimated/interpolate y
input-range
@@ -47,35 +55,41 @@
[scroll-height])
[:<>
[reanimated/blur-view
{:blur-amount 32
:blur-type :xlight
:overlay-color (if platform/ios? colors/white-opa-70 :transparent)
:style (style/blur-slider translate-animation)}]
{:blur-amount 20
:blur-type :transparent
:overlay-color :transparent
:style (style/blur-slider translate-animation height)}]
[rn/view
{:style {:z-index 6
:margin-top (if platform/ios? 44 0)}}
[reanimated/view
{:style (style/sticky-header-title opacity-animation)}
[rn/image
{:source cover
:style style/sticky-header-image}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style {:line-height 21}}
name]]
[quo/page-nav
{:horizontal-description? true
:one-icon-align-left? true
:align-mid? false
:page-nav-color :transparent
:mid-section {:type :text-with-description
:main-text nil
:description-img nil}
:right-section-buttons page-nav
:left-section {:icon :i/close
(when cover
[reanimated/view
{:style (style/sticky-header-title opacity-animation)}
[rn/image
{:source cover
:style style/sticky-header-image}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style {:line-height 21}}
name]])
(if top-nav
[top-nav]
[quo/page-nav
(merge {:horizontal-description? true
:one-icon-align-left? true
:align-mid? false
:page-nav-color :transparent
:mid-section {:type :text-with-description
:main-text nil
:description-img nil}
:right-section-buttons page-nav}
(when navigate-back?
{:left-section {:icon :i/close
:icon-background-color (icon-color)
:on-press #(rf/dispatch [:navigate-back])}}]
:on-press #(rf/dispatch [:navigate-back])}}))])
(when title-colum
[title-colum])
sticky-header]]))
@@ -101,14 +115,23 @@
(defn scroll-page
[_ _ _]
(let [scroll-height (reagent/atom negative-scroll-position-0)]
(fn [{:keys [cover-image page-nav-right-section-buttons name on-scroll]}
sticky-header
children]
(fn
[{:keys [cover-image
page-nav-right-section-buttons
name
on-scroll
height
top-nav
title-colum
background-color
navigate-back?]}
sticky-header
children]
[:<>
[:f> scroll-page-header @scroll-height name page-nav-right-section-buttons cover-image
sticky-header]
[:f> scroll-page-header @scroll-height height name page-nav-right-section-buttons
cover-image sticky-header top-nav title-colum navigate-back?]
[rn/scroll-view
{:style (style/scroll-view-container
{:content-container-style (style/scroll-view-container
(diff-with-max-min @scroll-height 16 0))
:shows-vertical-scroll-indicator false
:scroll-event-throttle 16
@@ -119,17 +142,18 @@
"nativeEvent.contentOffset.y")))
(when on-scroll
(on-scroll @scroll-height)))}
[rn/view {:style {:height 151}}
[rn/image
{:source cover-image
:style {:overflow :visible
:flex 1}}]]
(when cover-image
[rn/view {:style {:height 151}}
[rn/image
{:source cover-image
:style {:overflow :visible
:flex 1}}]])
(when children
[rn/view
{:flex 1
:border-radius (diff-with-max-min @scroll-height 16 0)
:background-color (colors/theme-colors
colors/white
colors/neutral-90)}
[:f> display-picture @scroll-height cover-image]
:background-color background-color
:padding-top 48}
(when cover-image
[:f> display-picture @scroll-height cover-image])
children])]])))
+8 -2
View File
@@ -214,8 +214,8 @@
{2 {0 image-size
1 image-size}
3 {0 [(* image-size 2) (* image-size 1.5)]
1 [(- image-size 1) (- (* image-size 0.67) 1)]
2 [(- image-size 1) (- (* image-size 0.67) 1)]}
1 [(- image-size 0.5) (- (* image-size 0.67) 1)]
2 [(- image-size 0.5) (- (* image-size 0.67) 1)]}
4 {0 image-size
1 image-size
2 image-size
@@ -273,3 +273,9 @@
(def ^:const theme-type-light 1)
(def ^:const theme-type-dark 2)
(def ^:const bottom-sheet-animation-delay 450)
(def ^:const local-pair-event-process-success "process-success")
(def ^:const local-pair-event-process-error "process-error")
(def ^:const local-pair-action-connect 1)
(def ^:const local-pair-action-pairing-account 2)
(def ^:const local-pair-action-sync-device 3)
@@ -41,7 +41,7 @@
{:type :negative :label (i18n/label :t/declined)}
nil)}
(case (:contact-request-state message)
constants/contact-request-state-mutual
constants/contact-request-message-state-pending
{:button-1 {:label (i18n/label :t/decline)
:accessibility-label :decline-contact-request
:type :danger
@@ -12,7 +12,7 @@
(into [rn/touchable-opacity
{:on-press (fn []
(rf/dispatch [:hide-popover])
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]))}]
(rf/dispatch [:chat/navigate-to-chat chat-id]))}]
children)
(into [:<>] children)))
@@ -9,11 +9,6 @@
[status-im2.utils.validators :as validators]
[status-im.utils.utils :as utils]))
(re-frame/reg-fx
:contacts/resolve-public-key-from-ens-name
(fn [{:keys [chain-id ens-name on-success on-error]}]
(ens/pubkey chain-id ens-name on-success on-error)))
(re-frame/reg-fx
:contacts/decompress-public-key
(fn [{:keys [public-key on-success on-error]}]
@@ -23,50 +18,73 @@
(let [{:keys [error]} (types/json->clj resp)]
(if error
(on-error error)
(on-success
(str "0x" (subs resp 5)))))))))
(on-success (str "0x" (subs resp 5)))))))))
(re-frame/reg-fx
:contacts/resolve-public-key-from-ens-name
(fn [{:keys [chain-id ens-name on-success on-error]}]
(ens/pubkey chain-id ens-name on-success on-error)))
(defn fx-callbacks
[input ens-name]
{:on-success (fn [pubkey]
(rf/dispatch
[:contacts/set-new-identity-success
input ens-name pubkey]))
:on-error (fn [err]
(rf/dispatch
[:contacts/set-new-identity-error err input]))})
(defn identify-type
[input]
(let [regex #"^https?://join.status.im/u/(.+)"
id (as-> (utils/safe-trim input) $
(if-some [[_ match] (re-matches regex $)]
match
$)
(if (empty? $) nil $))
public-key? (validators/valid-public-key? id)
compressed-key? (validators/valid-compressed-key? id)
type (cond (empty? id) :empty
public-key? :public-key
compressed-key? :compressed-key
:else :ens-name)
ens-name (when (= type :ens-name)
(stateofus/ens-name-parse id))]
{:input input
:id id
:type type
:ens-name ens-name}))
(rf/defn set-new-identity
{:events [:contacts/set-new-identity]}
[{:keys [db]} input]
(let [input (utils/safe-trim input)
public-key? (validators/valid-public-key? input)
compressed-key? (validators/valid-compressed-key? input)
ens-name (if compressed-key? nil (stateofus/ens-name-parse input))
on-success (fn [pubkey]
(rf/dispatch
[:contacts/set-new-identity-success
input ens-name pubkey]))
on-error (fn [err]
(rf/dispatch
[:contacts/set-new-identity-error err input]))]
(cond
(empty? input) {:db (dissoc db :contacts/new-identity)}
public-key? {:db (assoc db
:contacts/new-identity
{:input input
:public-key input
:ens-name nil
:state :error
:error :uncompressed-key})}
:else
(cond->
{:db (assoc db
:contacts/new-identity
{:input input
:public-key nil
:ens-name nil
:state :searching
:error nil})}
compressed-key? (assoc :contacts/decompress-public-key
{:public-key input
:on-success on-success
:on-error on-error})
(not compressed-key?) (assoc :contacts/resolve-public-key-from-ens-name
{:chain-id (ethereum/chain-id db)
:ens-name ens-name
:on-success on-success
:on-error on-error})))))
(let [{:keys [input id type ens-name]} (identify-type input)]
(case type
:empty {:db (dissoc db :contacts/new-identity)}
:public-key {:db (assoc db
:contacts/new-identity
{:input input
:public-key id
:state :error
:error :uncompressed-key})}
:compressed-key {:db
(assoc db
:contacts/new-identity
{:input input
:state :searching})
:contacts/decompress-public-key
(merge {:public-key id}
(fx-callbacks id ens-name))}
:ens-name {:db
(assoc db
:contacts/new-identity
{:input input
:state :searching})
:contacts/resolve-public-key-from-ens-name
(merge {:chain-id (ethereum/chain-id db)
:ens-name ens-name}
(fx-callbacks id ens-name))})))
(rf/defn set-new-identity-success
{:events [:contacts/set-new-identity-success]}
@@ -76,19 +94,16 @@
{:input input
:public-key pubkey
:ens-name ens-name
:state :valid
:error nil})})
:state :valid})})
(rf/defn set-new-identity-error
{:events [:contacts/set-new-identity-error]}
[{:keys [db]} error input]
{:db (assoc db
:contacts/new-identity
{:input input
:public-key nil
:ens-name nil
:state :error
:error :invalid})})
{:input input
:state :error
:error :invalid})})
(rf/defn clear-new-identity
{:events [:contacts/clear-new-identity :contacts/new-chat-focus]}
@@ -1,53 +1,56 @@
(ns status-im2.contexts.add-new-contact.events-test
(:require [cljs.test :refer-macros [deftest is]]
(:require [cljs.test :refer-macros [deftest is are]]
[status-im2.contexts.add-new-contact.events :as core]))
(def init-db
{:networks/current-network "mainnet_rpc"
:networks/networks {"mainnet_rpc"
{:id "mainnet_rpc"
:config {:NetworkId 1}}}})
(def ukey
"0x045596a7ff87da36860a84b0908191ce60a504afc94aac93c1abd774f182967ce694f1bf2d8773cd59f4dd0863e951f9b7f7351c5516291a0fceb73f8c392a0e88")
(def ckey "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA")
(def ens "esep")
(def ens-stateofus-eth (str ens ".stateofus.eth"))
(def link-ckey (str "https://join.status.im/u/" ckey))
(def link-ens (str "https://join.status.im/u/" ens))
(defn search-db
[input]
{:contacts/new-identity {:input input
:public-key nil
:ens-name nil
:state :searching
:error nil}})
(deftest identify-type-test
(are [input expected] (= (core/identify-type input) expected)
"" {:input ""
:id nil
:type :empty
:ens-name nil}
(deftest search-empty-string
(let [input ""
expected {:db init-db}
actual (core/set-new-identity {:db init-db} input)]
(is (= actual expected))))
ukey {:input ukey
:id ukey
:type :public-key
:ens-name nil}
(deftest search-ens
(let [input "esep"
clean (fn [db]
(-> db
(assoc-in [:contacts/resolve-public-key-from-ens-name :on-success] nil)
(assoc-in [:contacts/resolve-public-key-from-ens-name :on-error] nil)))
expected {:db (merge init-db (search-db input))
:contacts/resolve-public-key-from-ens-name
{:chain-id 1
:ens-name (str input ".stateofus.eth")
:on-success nil
:on-error nil}}
actual (core/set-new-identity {:db init-db} input)]
(is (= (clean actual) expected))))
ens {:input ens
:id ens
:type :ens-name
:ens-name ens-stateofus-eth}
(deftest search-compressed-key
(let [input "zQ3shWj4WaBdf2zYKCkXe6PHxDxNTzZyid1i75879Ue9cX9gA"
clean (fn [db]
(-> db
(assoc-in [:contacts/decompress-public-key :on-success] nil)
(assoc-in [:contacts/decompress-public-key :on-error] nil)))
expected {:db (merge init-db (search-db input))
:contacts/decompress-public-key
{:public-key input
:on-success nil
:on-error nil}}
actual (core/set-new-identity {:db init-db} input)]
(is (= (clean actual) expected))))
ckey {:input ckey
:id ckey
:type :compressed-key
:ens-name nil}
link-ckey {:input link-ckey
:id ckey
:type :compressed-key
:ens-name nil}
link-ens {:input link-ens
:id ens
:type :ens-name
:ens-name ens-stateofus-eth}))
(deftest search-empty-string-test
(is (= (core/set-new-identity {:db {:contacts/new-identity :foo}} "")
{:db {}})))
(deftest search-uncompressed-key-test
(is (= (core/set-new-identity {:db {}} ukey)
{:db {:contacts/new-identity
{:input ukey
:public-key ukey
:state :error
:error :uncompressed-key}}})))
+1 -1
View File
@@ -172,7 +172,7 @@
;; used here.
(when (and community-id (not navigate-to-shell?))
{:dispatch-n [[:shell/add-switcher-card
:community {:community-id community-id}]]})))
:community-overview community-id]]})))
(delete-for-me/sync-all)
(delete-message/send-all)
(offload-messages chat-id))))
@@ -14,12 +14,12 @@
:overflow :hidden})
(defn image
[dimensions index portrait?]
[dimensions index portrait? images-count]
{:width (:width dimensions)
:height (:height dimensions)
:margin-left (when (or (and (not= index 0) (not= index 2) (not= count 3))
(= count 3)
(and portrait? (= index 2)))
:margin-left (when (or (and (not= index 0) (not= index 2) (not= images-count 3))
(and (not portrait?) (= images-count 3) (= index 2))
(and portrait? (= images-count 3) (> index 0)))
1)
:margin-bottom (when (< index 2) 1)
:align-self :flex-start})
@@ -5,8 +5,7 @@
[react-native.fast-image :as fast-image]
[status-im2.contexts.chat.messages.content.album.style :as style]
[status-im2.constants :as constants]
[utils.re-frame :as rf]
[status-im2.contexts.chat.messages.content.image.view :as image]))
[utils.re-frame :as rf]))
(def rectangular-style-count 3)
@@ -17,7 +16,7 @@
{:width (second size-arr) :height (first size-arr) :album-style album-style}))
(defn album-message
[{:keys [albumize?] :as message}]
[message]
(let [shared-element-id (rf/sub [:shared-element-id])
first-image (first (:album message))
album-style (if (> (:image-width first-image) (:image-height first-image))
@@ -26,43 +25,44 @@
images-count (count (:album message))
;; album images are always square, except when we have 3 images, then they must be rectangular
;; (portrait or landscape)
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))]
(if (and albumize? (> images-count 1))
[rn/view
{:style (style/album-container portrait?)}
(map-indexed
(fn [index item]
(let [images-size-key (if (< images-count constants/max-album-photos) images-count :default)
size (get-in constants/album-image-sizes [images-size-key index])
dimensions (if (not= images-count rectangular-style-count)
{:width size :height size}
(find-size size album-style))]
[rn/touchable-opacity
{:key (:message-id item)
:active-opacity 1
:on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox
{:messages (:album message) :index index}])
100))}
[fast-image/fast-image
{:style (style/image dimensions index portrait?)
:source {:uri (:image (:content item))}
:native-ID (when (and (= shared-element-id (:message-id item))
(< index constants/max-album-photos))
:shared-element)}]
(when (and (> images-count constants/max-album-photos)
(= index (- constants/max-album-photos 1)))
[rn/view
{:style style/overlay}
[quo/text
{:weight :bold
:size :heading-2
:style {:color colors/white}}
(str "+" (- images-count (dec constants/max-album-photos)))]])]))
(:album message))]
[:<>
(map-indexed
(fn [index item]
[image/image-message index item])
(:album message))])))
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))
text (:text (:content first-image))]
[:<>
;; This text comp is temporary. Should later use
;; `status-im2.contexts.chat.messages.content.text.view`
(when (not= text "placeholder") [quo/text {:style {:margin-bottom 10}} text])
[rn/view
{:style (style/album-container portrait?)}
(map-indexed
(fn [index item]
(let [images-size-key (if (< images-count constants/max-album-photos) images-count :default)
size (get-in constants/album-image-sizes [images-size-key index])
dimensions (if (not= images-count rectangular-style-count)
{:width size :height size}
(find-size size album-style))]
[rn/touchable-opacity
{:key (:message-id item)
:active-opacity 1
;; issue: https://github.com/status-im/status-mobile/issues/14995
:on-long-press #(js/alert "Action drawer for albums is not supported yet")
:on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox
{:messages (:album message) :index index}])
100))}
[fast-image/fast-image
{:style (style/image dimensions index portrait? images-count)
:source {:uri (:image (:content item))}
:native-ID (when (and (= shared-element-id (:message-id item))
(< index constants/max-album-photos))
:shared-element)}]
(when (and (> images-count constants/max-album-photos)
(= index (- constants/max-album-photos 1)))
[rn/view
{:style style/overlay}
[quo/text
{:weight :bold
:size :heading-2
:style {:color colors/white}}
(str "+" (- images-count (dec constants/max-album-photos)))]])]))
(:album message))]]))
@@ -1,12 +1,15 @@
(ns status-im2.contexts.chat.messages.content.image.view
(:require [react-native.core :as rn]
[react-native.fast-image :as fast-image]
[utils.re-frame :as rf]))
(:require
[quo2.core :as quo]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[status-im2.constants :as constants]
[utils.re-frame :as rf]))
(defn calculate-dimensions
[width height]
(let [max-width (if (> width height) 320 190)
max-height (if (> width height) 190 320)]
(let [max-width (if (> width height) (* 2 constants/image-size) (* 1.5 constants/image-size))
max-height (if (> width height) (* 1.5 constants/image-size) (* 2 constants/image-size))]
(if (> height width)
(let [calculated-height (* (min height max-height) (/ (max width max-width) width))
calculated-width (* (max width max-width) (/ (min height max-height) height))]
@@ -16,7 +19,7 @@
{:width calculated-width :height calculated-height}))))
(defn image-message
[index {:keys [content image-width image-height message-id] :as message}]
[_ {:keys [content image-width image-height message-id] :as message} context on-long-press]
(let [dimensions (calculate-dimensions (or image-width 1000) (or image-height 1000))
text (:text content)]
(fn []
@@ -24,7 +27,7 @@
[rn/touchable-opacity
{:active-opacity 1
:key message-id
:style {:margin-top (when (> index 0) 20)}
:on-long-press #(on-long-press message context)
:on-press (fn []
(rf/dispatch [:chat.ui/update-shared-element-id message-id])
(js/setTimeout #(rf/dispatch [:navigate-to :lightbox
@@ -32,7 +35,7 @@
100))}
;; This text comp is temporary. Should later use
;; `status-im2.contexts.chat.messages.content.text.view`
(when (and (not= text "placeholder") (= index 0)) [rn/text text])
(when (not= text "placeholder") [quo/text {:style {:margin-bottom 10}} text])
[fast-image/fast-image
{:source {:uri (:image content)}
:style (merge dimensions {:border-radius 12})
@@ -6,8 +6,10 @@
[status-im2.contexts.chat.messages.drawers.view :as drawers]))
(defn message-reactions-row
[chat-id message-id]
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])]
[chat-id message-id messages-ids]
(let [reactions (if messages-ids
(mapcat #(rf/sub [:chats/message-reactions % chat-id]) messages-ids)
(rf/sub [:chats/message-reactions message-id chat-id]))]
(when (seq reactions)
[rn/view {:margin-left 52 :margin-bottom 12 :flex-direction :row}
(for [{:keys [own emoji-id quantity emoji-reaction-id] :as emoji-reaction} reactions]
@@ -28,8 +30,12 @@
:accessibility-label (str "emoji-reaction-" emoji-id)}]])
[quo/add-reaction
{:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn [] [drawers/reactions
{:chat-id chat-id :message-id message-id}])}]))}]])))
;; issue: https://github.com/status-im/status-mobile/issues/14995
(if messages-ids
(js/alert "Reactions for albums is not yet supported")
(do
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn [] [drawers/reactions
{:chat-id chat-id :message-id message-id}])}]))))}]])))
@@ -0,0 +1,11 @@
(ns status-im2.contexts.chat.messages.content.status.style
(:require [quo2.foundations.colors :as colors]))
(def status-container
{:flex-direction :row
:align-items :center})
(defn message-status-text
[]
{:margin-left 4
:color (colors/theme-colors colors/neutral-40 colors/neutral-50)})
@@ -1,6 +1,24 @@
(ns status-im2.contexts.chat.messages.content.status.view
(:require [status-im.ui2.screens.chat.messages.message :as old-message]))
(:require [react-native.core :as rn]
[quo2.foundations.colors :as colors]
[utils.i18n :as i18n]
[status-im2.contexts.chat.messages.content.status.style :as style]
[quo2.core :as quo]))
(defn status
[message-data]
[old-message/message-status message-data])
[outgoing-status]
[rn/view
{:accessibility-label :message-status
:style style/status-container}
[quo/icon
(if (= outgoing-status :delivered)
:i/delivered
:i/sent)
{:size 12
:color (colors/theme-colors colors/neutral-40 colors/neutral-50)}]
[quo/text
{:size :label
:style (style/message-status-text)}
(if (= outgoing-status :delivered)
(i18n/label :t/delivered)
(i18n/label :t/sent))]])
@@ -1,43 +1,47 @@
(ns status-im2.contexts.chat.messages.content.view
(:require [quo2.core :as quo]
(:require [react-native.core :as rn]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im.ui2.screens.chat.messages.message :as old-message]
[status-im.utils.utils :as utils]
[status-im2.common.not-implemented :as not-implemented]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.album.view :as album]
[status-im2.contexts.chat.messages.content.image.view :as image]
[status-im2.contexts.chat.messages.content.style :as style]
[status-im2.contexts.chat.messages.content.pin.view :as pin]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.unknown.view :as content.unknown]
[status-im2.contexts.chat.messages.content.text.view :as content.text]
[status-im2.contexts.chat.messages.drawers.view :as drawers]
[status-im2.contexts.chat.messages.content.reactions.view :as reactions]
[status-im2.contexts.chat.messages.content.status.view :as status]
[status-im2.contexts.chat.messages.content.style :as style]
[status-im2.contexts.chat.messages.content.system.text.view :as system.text]
[status-im2.contexts.chat.messages.content.text.view :as content.text]
[status-im2.contexts.chat.messages.content.unknown.view :as content.unknown]
[status-im2.contexts.chat.messages.drawers.view :as drawers]
[status-im2.contexts.chat.messages.content.album.view :as album]
[status-im2.contexts.chat.messages.content.image.view :as image]
[quo2.core :as quo]
[utils.re-frame :as rf]
[status-im.ui2.screens.chat.messages.message :as old-message]
[status-im2.common.not-implemented :as not-implemented]
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
[reagent.core :as reagent]))
(def delivery-state-showing-time-ms 3000)
(defn avatar
[{:keys [content last-in-group? pinned quoted-message from]}]
[rn/touchable-without-feedback {:on-press #(rf/dispatch [:chat.ui/show-profile from])}
[rn/view {:padding-top 2 :width 32}
(when (or (and (seq (:response-to content))
quoted-message)
last-in-group?
pinned)
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
contact (rf/sub [:contacts/contact-by-address from])
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))
online? (rf/sub [:visibility-status-updates/online? from])]
(if (or (and (seq (:response-to content))
quoted-message)
last-in-group?
pinned)
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
contact (rf/sub [:contacts/contact-by-address from])
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))
online? (rf/sub [:visibility-status-updates/online? from])]
[rn/touchable-without-feedback {:on-press #(rf/dispatch [:chat.ui/show-profile from])}
[rn/view {:padding-top 2 :width 32}
[quo/user-avatar
{:full-name display-name
:profile-picture photo-path
:status-indicator? true
:online? online?
:size :small
:ring? false}]))]])
:ring? false}]]])
[rn/view {:padding-top 2 :width 32}]))
(defn author
[{:keys [response-to
@@ -79,51 +83,81 @@
(rf/dispatch [:bottom-sheet/show-sheet
{:content (drawers/reactions-and-actions message-data context)}]))
(defn on-long-press
[message-data context]
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:bottom-sheet/show-sheet
{:content (drawers/reactions-and-actions message-data
context)}]))
(defn user-message-content
[{:keys [content-type quoted-message content] :as message-data}
[{:keys [content-type quoted-message content outgoing outgoing-status] :as message-data}
{:keys [chat-id] :as context}]
(let [context (assoc context :on-long-press #(message-on-long-press message-data context))
response-to (:response-to content)]
[rn/touchable-highlight
{:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
:style {:border-radius 16}
:on-press #()
:on-long-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:bottom-sheet/show-sheet
{:content (drawers/reactions-and-actions message-data
context)}]))}
[rn/view {:padding-vertical 8}
(when (and (seq response-to) quoted-message chat-id)
[old-message/quoted-message {:message-id response-to :chat-id chat-id} quoted-message])
[rn/view {:padding-horizontal 12 :flex-direction :row}
[avatar message-data]
[rn/view {:margin-left 8 :flex 1}
[author message-data]
(case content-type
[:f>
(let [show-delivery-state? (reagent/atom false)]
(fn []
(let [first-image (first (:album message-data))
outgoing-status (if (= content-type constants/content-type-album)
(:outgoing-status first-image)
outgoing-status)
outgoing (if (= content-type constants/content-type-album)
(:outgoing first-image)
outgoing)
context (assoc context :on-long-press #(message-on-long-press message-data context))
response-to (:response-to content)]
[rn/touchable-highlight
{:accessibility-label (if (and outgoing (= outgoing-status :sending))
:message-sending
:message-sent)
:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
:style {:border-radius 16
:opacity (if (and outgoing (= outgoing-status :sending)) 0.5 1)}
:on-press (fn []
(when (and outgoing
(not (= outgoing-status :sending))
(not @show-delivery-state?))
(reset! show-delivery-state? true)
(js/setTimeout #(reset! show-delivery-state? false)
delivery-state-showing-time-ms)))
:on-long-press #(on-long-press message-data context)}
[rn/view {:style {:padding-vertical 8}}
(when (and (seq response-to) quoted-message)
[old-message/quoted-message {:message-id response-to :chat-id chat-id} quoted-message])
[rn/view
{:style {:padding-horizontal 12
:flex-direction :row}}
[avatar message-data]
[rn/view
{:style {:margin-left 8
:flex 1}}
[author message-data]
(case content-type
constants/content-type-text [not-implemented/not-implemented
[content.text/text-content message-data context]]
constants/content-type-text
[content.text/text-content message-data context]
constants/content-type-emoji [not-implemented/not-implemented
[old-message/emoji message-data]]
constants/content-type-emoji
[old-message/emoji message-data]
constants/content-type-sticker [not-implemented/not-implemented
[old-message/sticker message-data]]
constants/content-type-sticker
[old-message/sticker message-data]
constants/content-type-image [image/image-message 0 message-data context]
constants/content-type-audio
[old-message/audio message-data]
constants/content-type-audio [not-implemented/not-implemented
[old-message/audio message-data]]
constants/content-type-image
[image/image-message 0 message-data context on-long-press]
constants/content-type-album [album/album-message message-data context]
constants/content-type-album
[album/album-message message-data context on-long-press]
[not-implemented/not-implemented [content.unknown/unknown-content message-data]])
[status/status message-data]]]]]))
[content.unknown/unknown-content message-data])
(when @show-delivery-state?
[status/status outgoing-status])]]]])))])
(defn message-with-reactions
[{:keys [pinned pinned-by mentioned in-pinned-view? content-type
last-in-group? message-id]
last-in-group? message-id messages-ids]
:as message-data}
{:keys [chat-id] :as context}]
[rn/view
@@ -136,4 +170,4 @@
content-type)
[system-message-content message-data]
[user-message-content message-data context])
[reactions/message-reactions-row chat-id message-id]])
[reactions/message-reactions-row chat-id message-id messages-ids]])
@@ -19,7 +19,7 @@
(rf/dispatch [:pin-message/send-pin-message (assoc message-data :pinned (not pinned))]))))
(defn get-actions
[{:keys [outgoing content pinned] :as message-data}
[{:keys [outgoing content pinned outgoing-status] :as message-data}
{:keys [edit-enabled show-input? can-delete-message-for-everyone? community? message-pin-enabled]}]
(concat
(when (and outgoing edit-enabled)
@@ -28,7 +28,7 @@
:label (i18n/label :t/edit-message)
:icon :i/edit
:id :edit}])
(when show-input?
(when (and show-input? (not= outgoing-status :sending))
[{:type :main
:on-press #(rf/dispatch [:chat.ui/reply-to-message message-data])
:label (i18n/label :t/message-reply)
@@ -117,7 +117,7 @@
icon]])))]))
(defn reactions-and-actions
[{:keys [message-id] :as message-data} {:keys [chat-id] :as context}]
[{:keys [message-id outgoing-status] :as message-data} {:keys [chat-id] :as context}]
(fn []
(let [actions (get-actions message-data context)
main-actions (filter #(= (:type %) :main) actions)
@@ -125,7 +125,8 @@
admin-actions (filter #(= (:type %) :admin) actions)]
[:<>
;; REACTIONS
[reactions {:chat-id chat-id :message-id message-id}]
(when (not= outgoing-status :sending)
[reactions {:chat-id chat-id :message-id message-id}])
;; MAIN ACTIONS
[rn/view {:style {:padding-horizontal 8}}
@@ -1,23 +1,22 @@
(ns status-im2.contexts.chat.messages.pin.list.view
(:require [quo2.core :as quo]
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im2.contexts.chat.messages.content.view :as message]
[utils.datetime :as datetime]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.datetime :as datetime]))
(def list-key-fn #(or (:message-id %) (:value %)))
(defn message-render-fn
[{:keys [whisper-timestamp chat-id] :as message}
[{:keys [whisper-timestamp] :as message}
_
{:keys [group-chat public? community? current-public-key show-input? edit-enabled]}]
;; TODO (flexsurfer) probably we don't want reactions here
[message/message-with-reactions
message
{:group-chat group-chat
:chat-id chat-id
:public? public?
:community? community?
:current-public-key current-public-key
@@ -29,7 +29,8 @@
:position :absolute
:right 20})
(def camera-button-container
(defn close-button-container
[]
{:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
:width 32
:height 32
@@ -130,7 +130,7 @@
[rn/touchable-opacity
{:active-opacity 1
:on-press #(rf/dispatch [:navigate-back])
:style style/camera-button-container}
:style (style/close-button-container)}
[quo/icon :i/close
{:size 20 :color (colors/theme-colors colors/black colors/white)}]])
[album-title true selected-album selected temporary-selected]
@@ -0,0 +1,55 @@
(ns status-im2.contexts.communities.discover.style
(:require [react-native.platform :as platform]))
(def screen-title-container
{:height 56
:padding-vertical 12
:justify-content :center})
(def featured-communities-header
{:flex-direction :row
:height 30
:padding-top 8
:margin-bottom 8
:padding-right 20
:justify-content :space-between})
(def featured-communities-title-container
{:flex-direction :row
:align-items :center})
(def featured-list-container
{:flex-direction :row
:overflow :hidden
:margin-bottom 24})
(defn discover-communities-segments
[fixed?]
(merge
{:padding-vertical 12
:height 56
:background-color :transparent}
(when-not fixed?
{:margin-top 12
:margin-bottom 4})))
(defn discover-screen-container
[background-color]
{:background-color background-color
:position :absolute
:top (if platform/ios? 0 44)
:bottom 0
:left 0
:right 0})
(defn blur-tabs-header
[]
{:padding-horizontal 20
:position :absolute
:top (if platform/ios? 56 60)
:height 56
:right 0
:left 0
:justify-content :center
:flex 1
:background-color :transparent})
@@ -4,10 +4,14 @@
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im.react-native.resources :as resources]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im.ui.screens.communities.community :as community]
[status-im.ui.components.react :as react]
[react-native.platform :as platform]
[status-im2.common.scroll-page.view :as scroll-page]
[status-im2.contexts.communities.discover.style :as style]
[utils.re-frame :as rf]))
(def mock-community-item-data ;; TODO: remove once communities are loaded with this data.
@@ -29,10 +33,9 @@
:resource (resources/get-image :podcasts)}]}})
(defn render-fn
[community-item _ _ {:keys [featured? width view-type]}]
[community-item _ _ {:keys [width view-type]}]
(let [item (merge community-item
(get mock-community-item-data :data)
{:featured featured?})]
(get mock-community-item-data :data))]
(if (= view-type :card-view)
[quo/community-card-view-item (assoc item :width width)
#(rf/dispatch [:navigate-to :community-overview (:id item)])]
@@ -49,8 +52,7 @@
(defn screen-title
[]
[rn/view
{:height 56
:padding-vertical 12}
{:style style/screen-title-container}
[quo/text
{:accessibility-label :communities-screen-title
:weight :semi-bold
@@ -60,13 +62,9 @@
(defn featured-communities-header
[communities-count]
[rn/view
{:flex-direction :row
:height 30
:margin-bottom 8
:justify-content :space-between}
{:style style/featured-communities-header}
[rn/view
{:flex-direction :row
:align-items :center}
{:style style/featured-communities-title-container}
[quo/text
{:accessibility-label :featured-communities-title
:weight :semi-bold
@@ -83,18 +81,34 @@
colors/neutral-50
colors/neutral-40)}]])
(defn discover-communities-segments
[selected-tab fixed]
[rn/view
{:style (style/discover-communities-segments fixed)}
[quo/tabs
{:size 32
:on-change #(reset! selected-tab %)
:default-active :all
:data [{:id :all
:label (i18n/label :t/all)
:accessibility-label :all-communities-tab}
{:id :open
:label (i18n/label :t/open)
:accessibility-label :open-communities-tab}
{:id :gated
:label (i18n/label :t/gated)
:accessibility-label :gated-communities-tab}]}]])
(defn featured-list
[communities view-type]
(let [view-size (reagent/atom 0)]
(fn []
[rn/view
{:style {:flex-direction :row
:overflow :hidden
:width "100%"
:margin-bottom 24}
{:style style/featured-list-container
:on-layout #(swap! view-size
(fn []
(oops/oget % "nativeEvent.layout.width")))}
(- (oops/oget % "nativeEvent.layout.width") 20)))}
(when-not (= @view-size 0)
[rn/flat-list
{:key-fn :id
@@ -104,47 +118,134 @@
:separator [rn/view {:width 12}]
:data communities
:render-fn render-fn
:render-data {:featured? true
:width @view-size
:render-data {:width @view-size
:view-type view-type}}])])))
(defn discover-communities-header
[{:keys [featured-communities-count
featured-communities
view-type
selected-tab]}]
[react/animated-view
[screen-title]
[featured-communities-header featured-communities-count]
[featured-list featured-communities view-type]
[quo/separator]
[discover-communities-segments selected-tab false]])
(defn other-communities-list
[communities view-type]
[rn/flat-list
{:key-fn :id
:keyboard-should-persist-taps :always
:shows-horizontal-scroll-indicator false
:separator [rn/view {:margin-bottom 16}]
:data communities
:render-fn render-fn
:render-data {:featured? false
:width "100%"
:view-type view-type}}])
[{:keys [communities communities-ids view-type]}]
[rn/view {:flex 1}
(map-indexed
(fn [inner-index item]
(let [community-id (when communities-ids item)
community (if communities
item
[rf/sub [:communities/home-item community-id]])]
[rn/view
{:key (str inner-index (:id community))
:margin-bottom 16}
(if (= view-type :card-view)
[quo/community-card-view-item
(merge community
(get mock-community-item-data :data))
#(rf/dispatch [:navigate-to :community-overview (:id community)])]
[quo/communities-list-view-item
{:on-press (fn []
(rf/dispatch [:communities/load-category-states (:id community)])
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:navigate-to :community (:id community)]))
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn []
;; TODO implement with quo2
[community/community-actions community])}])}
(merge community
(get mock-community-item-data :data))])]))
(if communities communities communities-ids))])
(defn communities-lists
[selected-tab view-type]
(let [ids-by-user-involvement (rf/sub [:communities/community-ids-by-user-involvement])
all-communities (rf/sub [:communities/sorted-communities])
tab @selected-tab]
[rn/view {:style {:flex 1}}
(case tab
:all
(other-communities-list {:communities all-communities
:view-type view-type})
:open
(other-communities-list {:communities-ids (:open ids-by-user-involvement)
:view-type view-type})
:gated
(other-communities-list {:communities-ids (:gated ids-by-user-involvement)
:view-type view-type})
[quo/information-box
{:type :error
:icon :i/info}
(i18n/label :t/error)])]))
(defn render-communities
[selected-tab
featured-communities-count
featured-communities
view-type]
(fn []
[rn/view {:padding-horizontal 20}
[discover-communities-header
{:selected-tab selected-tab
:view-type view-type
:featured-communities-count featured-communities-count
:featured-communities featured-communities}]
[communities-lists selected-tab view-type]]))
(defn render-sticky-header
[{:keys [selected-tab scroll-height]}]
(fn []
(when (> @scroll-height 360)
[rn/view
{:style (style/blur-tabs-header)}
[discover-communities-segments selected-tab true]])))
(defn discover-screen-content
[featured-communities]
(let [view-type (reagent/atom :card-view)
selected-tab (reagent/atom :all)
scroll-height (reagent/atom 0)
featured-communities-count (count featured-communities)]
(fn []
[scroll-page/scroll-page
{:name (i18n/label :t/discover-communities)
:on-scroll #(reset! scroll-height %)
:background-color (colors/theme-colors
colors/white
colors/neutral-95)
:navigate-back? :true
:height (if platform/ios?
(if (> @scroll-height 360)
156
100)
(if (> @scroll-height 360)
162
106))}
[render-sticky-header
{:selected-tab selected-tab
:scroll-height scroll-height}]
[render-communities
selected-tab
featured-communities-count
featured-communities
@view-type]])))
(defn discover
[]
(let [view-type (reagent/atom :card-view)]
(fn []
(let [communities (rf/sub [:communities/sorted-communities])
featured-communities (rf/sub [:communities/featured-communities])
featured-communities-count (count featured-communities)]
[safe-area/consumer
(fn []
[rn/view
{:style {:margin-left 20
:margin-right 20
:flex 1
:background-color (colors/theme-colors
colors/white
colors/neutral-90)}}
[quo/button
{:icon true
:type :grey
:size 32
:style {:margin-vertical 12}
:on-press #(rf/dispatch [:navigate-back])}
:i/close]
[screen-title]
[featured-communities-header featured-communities-count]
[featured-list featured-communities @view-type]
[other-communities-list communities @view-type]])]))))
(let [featured-communities (rf/sub [:communities/featured-communities])]
[rn/view
{:style (style/discover-screen-container (colors/theme-colors
colors/white
colors/neutral-95))}
[discover-screen-content featured-communities]]))
@@ -0,0 +1,29 @@
(ns status-im2.contexts.communities.home.style
(:require [react-native.platform :as platform]))
(defn community-segments
[padding-top]
{:padding-bottom 12
:padding-top padding-top
:padding-horizontal 20
:background-color :transparent})
(defn home-communities-container
[background-color]
{:flex 1
:background-color background-color
:position :absolute
:top (if platform/ios? -44 0)
:bottom 0
:left 0
:right 0})
(def blur-tabs-header
{:flex 1
:position :absolute
:top 112
:height 52
:left 0
:right 0
:justify-content :center
:background-color :transparent})
@@ -1,37 +1,19 @@
(ns status-im2.contexts.communities.home.view
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[react-native.core :as rn]
[quo2.foundations.colors :as colors]
[reagent.core :as reagent]
[react-native.core :as rn]
[status-im2.common.home.view :as common.home]
[status-im2.common.scroll-page.view :as scroll-page]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im2.contexts.communities.home.style :as style]
[utils.re-frame :as rf]))
(defn render-fn
[id]
(let [community-item (rf/sub [:communities/home-item id])]
[quo/communities-membership-list-item
{:on-press #(rf/dispatch [:navigate-to :community-overview id])
:on-long-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn []
[options/community-options-bottom-sheet id])
:selected-item (fn []
[quo/communities-membership-list-item {} community-item])}])}
community-item]))
(defn get-item-layout-js
[_ index]
#js {:length 64 :offset (* 64 index) :index index})
(defn home-community-segments
[selected-tab]
(defn community-segments
[selected-tab padding-top]
[rn/view
{:style {:padding-bottom 12
:padding-top 16
:margin-top 8
:height 60
:padding-horizontal 20}}
{:style (style/community-segments padding-top)}
[quo/tabs
{:size 32
:on-change #(reset! selected-tab %)
@@ -41,22 +23,31 @@
{:id :opened :label (i18n/label :t/opened) :accessibility-label :opened-tab}]}]])
(defn communities-list
[community-ids]
[rn/flat-list
{:key-fn identity
:get-item-layout get-item-layout-js
:keyboard-should-persist-taps :always
:shows-horizontal-scroll-indicator false
:data community-ids
:render-fn render-fn
:content-container-style {:padding-bottom 30}}])
[communities-ids]
[rn/view
(map-indexed
(fn [index id]
(let [community (rf/sub [:communities/home-item id])]
^{:key index}
[quo/communities-membership-list-item
{:on-press #(rf/dispatch [:navigate-to-nav2 :community-overview id])
:on-long-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn []
[options/community-options-bottom-sheet id])
:selected-item (fn []
[quo/communities-membership-list-item {} community])}])}
community]))
communities-ids)])
(defn segments-community-lists
(defn render-communities-segments
[selected-tab]
(let [ids-by-user-involvement (rf/sub [:communities/community-ids-by-user-involvement])
tab @selected-tab]
[rn/view
{:style {:padding-horizontal 20
{:style {:flex 1
:padding-horizontal 20
:padding-vertical 12}}
(case tab
:joined
@@ -73,20 +64,70 @@
:icon :i/info}
(i18n/label :t/error)])]))
(defn communities-header
[selected-tab padding-top]
[:<>
[rn/view {:style {:padding-vertical 8}}
[quo/discover-card
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
:title (i18n/label :t/discover)
:description (i18n/label :t/whats-trending)
:accessibility-label :communities-home-discover-card}]]
[community-segments selected-tab padding-top]])
(defn home-page-comunity-lists
[{:keys [selected-tab padding-top]}]
(fn []
[rn/view {:style {:flex 1}}
[communities-header selected-tab padding-top]
[render-communities-segments selected-tab]]))
(defn home-sticky-header
[{:keys [selected-tab scroll-height padding-top]}]
(fn []
(when (> @scroll-height 80)
[rn/view
{:style style/blur-tabs-header}
[community-segments selected-tab padding-top]])))
(defn communities-screen-content
[]
(let [scroll-height (reagent/atom 0)
selected-tab (reagent/atom :joined)]
(fn []
[scroll-page/scroll-page
{:name (i18n/label :t/communities)
:on-scroll #(reset! scroll-height %)
:top-nav (fn []
[common.home/top-nav
{:type :default
:hide-search true
:style {:background-color :transparent}}])
:title-colum (fn []
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet :add-new {}])
:accessibility-label :new-chat-button}])
:background-color (colors/theme-colors
colors/white
colors/neutral-95)
:navigate-back? :false
:height (if (> @scroll-height 80)
208
156)}
[home-sticky-header
{:selected-tab selected-tab
:scroll-height scroll-height
:padding-top 8}]
[home-page-comunity-lists
{:selected-tab selected-tab
:padding-top 16
:height 60}]])))
(defn home
[]
(let [selected-tab (reagent/atom :joined)]
(fn []
[:<>
[common.home/top-nav {:type :default :hide-search true}]
[common.home/title-column
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:bottom-sheet/show-sheet :add-new {}])
:accessibility-label :new-chat-button}]
[quo/discover-card
{:on-press #(rf/dispatch [:navigate-to :discover-communities])
:title (i18n/label :t/discover)
:description (i18n/label :t/whats-trending)
:accessibility-label :communities-home-discover-card}]
[home-community-segments selected-tab]
[segments-community-lists selected-tab]])))
[rn/view
{:style (style/home-communities-container (colors/theme-colors
colors/white
colors/neutral-95))}
[communities-screen-content]])
@@ -36,8 +36,7 @@
:margin-bottom 20})
(def title-container
{:flex 1
:flex-direction :row
{:flex-direction :row
:align-items :center
:justify-content :space-between})
@@ -56,10 +55,10 @@
{:flex 1
:margin-right 12})
(def request-button
{:margin-top 32
:margin-bottom 16
:flex 1
(defn bottom-container
[safe-area-insets]
{:padding-top 32
:padding-bottom (:bottom safe-area-insets)
:flex-direction :row
:align-items :center
:justify-content :space-evenly})
@@ -1,9 +1,10 @@
(ns status-im2.contexts.communities.menus.request-to-join.view
(:require [quo.react-native :as rn]
[quo2.core :as quo]
(:require [react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[utils.i18n :as i18n]
[status-im2.contexts.communities.menus.request-to-join.style :as style]
[quo2.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.requests :as requests]))
@@ -73,60 +74,72 @@
:render-fn community-rule-item}])
(defn request-to-join
[{:keys [permissions name id images
can-join? can-request-access?
[{:keys [permissions
name
id
images
can-join?
can-request-access?
requested-to-join-at]}]
(let [agreed-to-rules? (reagent/atom false)
is-open? (not= 3 (:access permissions))]
(fn []
[rn/scroll-view {:style style/page-container}
[rn/view
{:style style/title-container}
(let [agreed-to-rules? (reagent/atom false)]
[safe-area/consumer
(fn [insets]
[:f>
(fn []
(let [{window-height :height} (rn/use-window-dimensions)
is-open? (not= 3 (:access permissions))]
[rn/scroll-view {:style {:max-height (- window-height (:top insets))}}
[rn/view style/page-container
[rn/view
{:style style/title-container}
[quo/text
{:accessibility-label :communities-join-community
:weight :semi-bold
:size :heading-1}
(request-to-join-text is-open?)]
[rn/view
{:style style/request-icon}
[quo/icon :i/info]]]
[quo/context-tag
{:style
{:margin-right :auto
:margin-top 8}}
(:thumbnail images) name]
[quo/text
{:style {:margin-top 24}
:accessibility-label :communities-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)]
[community-rules-list community-rules]
[quo/text
{:accessibility-label :communities-join-community
:weight :semi-bold
:size :heading-1}
(request-to-join-text is-open?)]
[rn/view
{:style style/request-icon}
[quo/icon :i/info]]]
[quo/context-tag
{:style
{:margin-right :auto
:margin-top 8}}
(:thumbnail images) name]
[quo/text
{:style {:margin-top 24}
:accessibility-label :communities-rules-title
:weight :semi-bold
:size :paragraph-1}
(i18n/label :t/community-rules)]
[quo/disclaimer
{:accessibility-label :rules-disclaimer-checkbox
:container-style {:margin-top 20}
:on-change #(swap! agreed-to-rules? not)}
(i18n/label :t/accept-community-rules)]
[rn/view
{:style style/request-button}
[quo/button
{:accessibility-label :cancel
:on-press #(rf/dispatch [:bottom-sheet/hide])
:type :grey
:style style/cancel-button} (i18n/label :t/cancel)]
[quo/button
{:accessibility-label :join-community-button
:on-press (fn []
(if can-join?
(do
(rf/dispatch [:communities/join id])
(rf/dispatch [:bottom-sheet/hide]))
(do (and can-request-access?
(not (pos? requested-to-join-at))
(requests/can-request-access-again? requested-to-join-at))
(rf/dispatch [:communities/request-to-join id])
(rf/dispatch [:bottom-sheet/hide]))))
:disabled (not @agreed-to-rules?)
:style {:flex 1}} (request-to-join-text is-open?)]]])))
[community-rules-list community-rules]
[quo/disclaimer
{:accessibility-label :rules-disclaimer-checkbox
:container-style {:margin-top 20}
:on-change #(swap! agreed-to-rules? not)}
(i18n/label :t/accept-community-rules)]
[rn/view {:style (style/bottom-container insets)}
[quo/button
{:accessibility-label :cancel
:on-press #(rf/dispatch [:bottom-sheet/hide])
:type :grey
:style style/cancel-button} (i18n/label :t/cancel)]
[quo/button
{:accessibility-label :join-community-button
:on-press (fn []
(if can-join?
(do
(rf/dispatch [:communities/join id])
(rf/dispatch [:bottom-sheet/hide]))
(do (and can-request-access?
(not (pos? requested-to-join-at))
(requests/can-request-access-again?
requested-to-join-at))
(rf/dispatch [:communities/request-to-join id])
(rf/dispatch [:bottom-sheet/hide]))))
:disabled (not @agreed-to-rules?)
:style {:flex 1}} (request-to-join-text is-open?)]]]]))])]))
@@ -8,11 +8,13 @@
:margin-top 20})
(def blur-channel-header
{:position :absolute
:top (if platform/ios? 56 60)
:height 34
:width "100%"
:flex 1})
{:position :absolute
:top (if platform/ios? 56 60)
:height 34
:right 0
:left 0
:flex 1
:background-color :transparent})
(def join-button
{:width "100%"
@@ -4,7 +4,6 @@
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.blur :as blur]
[react-native.platform :as platform]
[reagent.core :as reagent]
[status-im2.constants :as constants]
@@ -12,6 +11,7 @@
[status-im2.contexts.communities.overview.style :as style]
[status-im2.contexts.communities.menus.community-options.view :as options]
[status-im2.contexts.communities.menus.request-to-join.view :as join-menu]
[quo2.components.navigation.floating-shell-button :as floating-shell-button]
[status-im2.contexts.communities.overview.utils :as utils]
[utils.re-frame :as rf]))
@@ -119,9 +119,10 @@
[quo/button
{:on-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content (fn [] [join-menu/request-to-join
community])
:content-height 300}])
{:content (fn [] [join-menu/request-to-join
community])
:bottom-safe-area-spacing? false
:content-height 300}])
:accessibility-label :show-request-to-join-screen-button
:override-background-color community-color
:style style/join-button
@@ -262,11 +263,8 @@
[_]
(fn [{:keys [:enabled :label]}]
(when enabled
[blur/view
{:blur-amount 32
:blur-type :xlight
:overlay-color (if platform/ios? colors/white-opa-70 :transparent)
:style style/blur-channel-header}
[rn/view
{:style style/blur-channel-header}
[quo/divider-label
{:label (:label label)
:chevron-position :left}]])))
@@ -293,7 +291,18 @@
{:cover-image cover
:page-nav-right-section-buttons (page-nav-right-section-buttons id)
:name name
:on-scroll #(reset! scroll-height %)}
:on-scroll #(reset! scroll-height %)
:navigate-back? true
:background-color (colors/theme-colors
colors/white
colors/neutral-90)
:height (if platform/ios?
(if (> @scroll-height @first-channel-height)
134
100)
(if (> @scroll-height @first-channel-height)
140
106))}
[sticky-category-header
{:enabled (> @scroll-height @first-channel-height)
@@ -311,5 +320,9 @@
community (rf/sub [:communities/community id])]
[rn/view
{:style style/community-overview-container}
[community-card-page-view community]]))
[community-card-page-view community]
[floating-shell-button/floating-shell-button
{:jump-to {:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:label (i18n/label :t/jump-to)}}
{:position :absolute
:bottom 41}]]))
+4 -4
View File
@@ -72,13 +72,13 @@
nil))
:community
:community-overview
{:navigate-from :communities-stack
:card-id (:community-id id)
:card-id id
:switcher-card {:type shell.constants/community-card
:card-id (:community-id id)
:card-id id
:clock now
:screen-id (:community-id id)}}
:screen-id id}}
nil))
(rf/defn add-switcher-card
+15 -2
View File
@@ -25,7 +25,10 @@
(defn dismiss-all-modals
[]
(log/debug "dissmiss-all-modals")
(log/debug "dissmiss-all-modals"
{:curr-modal @state/curr-modal
:modals @state/modals
:dissmissing @state/dissmissing})
(when @state/curr-modal
(reset! state/curr-modal false)
(reset! state/dissmissing true)
@@ -75,7 +78,11 @@
(defn open-modal
[comp]
(log/debug "open-modal" comp)
(log/debug "open-modal"
{:comp comp
:dissmissing @state/dissmissing
:curr-modal @state/curr-modal
:modals @state/modals})
(let [{:keys [options]} (get views/screens comp)]
(if @state/dissmissing
(reset! state/dissmissing comp)
@@ -122,6 +129,10 @@
(defn modal-dismissed-listener
[]
(log/debug "modal-dismissed"
{:modals @state/modals
:curr-modal @state/curr-modal
:dissmissing @state/dissmissing})
(if (> (count @state/modals) 1)
(let [new-modals (butlast @state/modals)]
(reset! state/modals (vec new-modals))
@@ -180,6 +191,7 @@
:init-root-fx
(fn [new-root-id]
(log/debug :init-root-fx new-root-id)
(dismiss-all-modals)
(reset! state/root-comp-id new-root-id)
(reset! state/root-id @state/root-comp-id)
(navigation/set-root (get (roots/roots) new-root-id))))
@@ -188,6 +200,7 @@
:init-root-with-component-fx
(fn [[new-root-id new-root-comp-id]]
(log/debug :init-root-with-component-fx new-root-id new-root-comp-id)
(dismiss-all-modals)
(reset! state/root-comp-id new-root-comp-id)
(reset! state/root-id @state/root-comp-id)
(navigation/set-root (get (roots/roots) new-root-id))))
+33 -16
View File
@@ -111,22 +111,39 @@
(defn albumize-messages
[messages]
(get
(reduce (fn [{:keys [messages albums]} message]
(let [album-id (:album-id message)
albums (cond-> albums album-id (update album-id conj message))
messages (if album-id
(conj (filterv #(not= album-id (:album-id %)) messages)
{:album (get albums album-id)
:album-id album-id
:albumize? (:albumize? message)
:message-id album-id
:content-type constants/content-type-album})
(conj messages message))]
{:messages messages
:albums albums}))
{:messages []
:albums {}}
messages)
(reduce
(fn [{:keys [messages albums]} message]
(let [album-id (:album-id message)
;; check if this image is the first image in an album (which is not albumized yet)
add-text? (when (and album-id (not (:albumize? message)) (> (count (get albums album-id)) 0))
(not (some #(= false %)
(mapv #(< (:timestamp message) (:timestamp %))
(get albums album-id)))))
albums (cond-> albums album-id (update album-id conj message))
;; keep text of the first album image only
message (if (or add-text? (<= (count (get albums album-id)) 1))
message
(assoc-in message [:content :text] nil))
messages (if (and (> (count (get albums album-id)) 1) (:albumize? message))
(conj (filterv #(not= album-id (:album-id %)) messages)
{:album (get albums album-id)
:album-id album-id
:albumize? (:albumize? message)
:messages-ids (mapv :message-id (get albums album-id))
:message-id album-id
:content-type constants/content-type-album})
;; remove text of other images in an album
(if add-text?
(conj (mapv #(when (= (:album-id %) album-id)
(assoc-in % [:content :text] nil))
messages)
message)
(conj messages message)))]
{:messages messages
:albums albums}))
{:messages []
:albums {}}
messages)
:messages))
(re-frame/reg-sub
+7 -2
View File
@@ -10,7 +10,9 @@
[{:message-id "0x111" :album-id "abc" :albumize? true}
{:message-id "0x222" :album-id "abc" :albumize? true}
{:message-id "0x333" :album-id "abc" :albumize? true}
{:message-id "0x444" :album-id "abc" :albumize? true}])
{:message-id "0x444" :album-id "abc" :albumize? true}
{:message-id "0x555" :album-id "edf" :timestamp 10 :content {:text "Wassup!"}}
{:message-id "0x666" :album-id "edf" :timestamp 20 :content {:text "Wassup!"}}])
(def messages-albumized-state
[{:album [{:message-id "0x444" :album-id "abc" :albumize? true}
@@ -20,7 +22,10 @@
:album-id "abc"
:albumize? true
:message-id "abc"
:content-type constants/content-type-album}])
:messages-ids ["0x444" "0x333" "0x222" "0x111"]
:content-type constants/content-type-album}
{:message-id "0x555" :album-id "edf" :timestamp 10 :content {:text "Wassup!"}}
{:message-id "0x666" :album-id "edf" :timestamp 20 :content {:text nil}}])
(deftest albumize-messages
(testing "Finding albums in the messages list"
+7 -4
View File
@@ -224,16 +224,19 @@
(fn [[{:keys [joined categories chats]} full-chats-data] [_ community-id]]
(reduce
(fn [acc [_ {:keys [name categoryID id emoji can-post?]}]]
(let [category (keyword (get-in categories
[categoryID :name]
(i18n/label :t/none)))
{:keys [unviewed-messages-count]} (get full-chats-data (str community-id id))]
(let [category (keyword
(get-in categories
[categoryID :name]
(i18n/label :t/none)))
{:keys [unviewed-messages-count unviewed-mentions-count]} (get full-chats-data
(str community-id id))]
(update acc
category
#(vec (conj %1 %2))
{:name name
:emoji emoji
:unread-messages? (pos? unviewed-messages-count)
:mentions-count (or unviewed-mentions-count 0)
:locked? (or (not joined) (not can-post?))
:id id})))
{}
+21 -14
View File
@@ -150,10 +150,13 @@
:categories {1 {:id 1 :name "category1"}
2 {:id 2 :name "category2"}}
:joined true}})
(is (= {:category1 [{:name "chat1" :emoji nil :locked? false :id "0x1" :unread-messages? false}
{:name "chat2" :emoji nil :locked? true :id "0x2" :unread-messages? false}]
:category2 [{:name "chat3" :emoji nil :locked? false :id "0x3" :unread-messages? false}]}
(rf/sub [sub-name "0x1"]))))
(is
(= {:category1
[{:name "chat1" :emoji nil :locked? false :id "0x1" :unread-messages? false :mentions-count 0}
{:name "chat2" :emoji nil :locked? true :id "0x2" :unread-messages? false :mentions-count 0}]
:category2
[{:name "chat3" :emoji nil :locked? false :id "0x3" :unread-messages? false :mentions-count 0}]}
(rf/sub [sub-name "0x1"]))))
(testing "Channels without categories"
(swap! rf-db/app-db assoc
:communities/enabled? true
@@ -165,11 +168,13 @@
:categories {1 {:id 1 :name "category1"}
2 {:id 2 :name "category2"}}
:joined true}})
(is (= {:category1 [{:name "chat1" :emoji nil :locked? false :id "0x1" :unread-messages? false}
{:name "chat2" :emoji nil :locked? true :id "0x2" :unread-messages? false}]
(keyword (i18n/label :t/none))
[{:name "chat3" :emoji nil :locked? false :id "0x3" :unread-messages? false}]}
(rf/sub [sub-name "0x1"]))))
(is
(= {:category1
[{:name "chat1" :emoji nil :locked? false :id "0x1" :unread-messages? false :mentions-count 0}
{:name "chat2" :emoji nil :locked? true :id "0x2" :unread-messages? false :mentions-count 0}]
(keyword (i18n/label :t/none))
[{:name "chat3" :emoji nil :locked? false :id "0x3" :unread-messages? false :mentions-count 0}]}
(rf/sub [sub-name "0x1"]))))
(testing "Unread messages"
(swap! rf-db/app-db assoc
:communities/enabled? true
@@ -180,8 +185,10 @@
:categories {1 {:id 1 :name "category1"}}
:joined true}}
:chats
{"0x10x1" {:unviewed-messages-count 1}
"0x10x2" {:unviewed-messages-count 0}})
(is (= {:category1 [{:name "chat1" :emoji nil :locked? false :id "0x1" :unread-messages? true}
{:name "chat2" :emoji nil :locked? true :id "0x2" :unread-messages? false}]}
(rf/sub [sub-name "0x1"])))))
{"0x10x1" {:unviewed-messages-count 1 :unviewed-mentions-count 2}
"0x10x2" {:unviewed-messages-count 0 :unviewed-mentions-count 0}})
(is
(= {:category1
[{:name "chat1" :emoji nil :locked? false :id "0x1" :unread-messages? true :mentions-count 2}
{:name "chat2" :emoji nil :locked? true :id "0x2" :unread-messages? false :mentions-count 0}]}
(rf/sub [sub-name "0x1"])))))
+4 -10
View File
@@ -76,16 +76,10 @@
:contacts/active-sections
:<- [:contacts/active]
(fn [contacts]
(-> (reduce
(fn [acc contact]
(let [first-char (first (:alias contact))]
(if (get acc first-char)
(update-in acc [first-char :data] #(conj % contact))
(assoc acc first-char {:title first-char :data [contact]}))))
{}
contacts)
sort
vals)))
(->> contacts
(group-by #(string/upper-case (ffirst (:two-names %))))
sort
(mapv (fn [[title items]] {:title title :data items})))))
(re-frame/reg-sub
:contacts/grouped-by-first-letter
+6 -3
View File
@@ -95,7 +95,8 @@
:names {:nickname nil
:display-name ""
:three-words-name "Fake Slim Shady"
:ens-name "@slim.shady"}
:ens-name "slim.shady"}
:two-names ["slim.shady" "Fake Slim Shady"]
:has-added-us true
:contact-request-state 1}]}
{:title "I"
@@ -124,7 +125,8 @@
:names {:nickname nil
:display-name ""
:three-words-name "Instant noodles"
:ens-name "@slim.shady"}
:ens-name "slim.shady"}
:two-names ["slim.shady" "Instant noodles"]
:has-added-us true
:contact-request-state 1}]}
{:title "R"
@@ -153,7 +155,8 @@
:names {:nickname nil
:display-name ""
:three-words-name "Real Slim Shady"
:ens-name "@slim.shady"}
:ens-name "slim.shady"}
:two-names ["slim.shady" "Real Slim Shady"]
:has-added-us true
:contact-request-state 1}]}])
+2 -3
View File
@@ -90,8 +90,7 @@
{:name (:name community)})
:customization-color (or (:customization-color community) :primary)
:on-close #(re-frame/dispatch [:shell/close-switcher-card id])
:on-press #(re-frame/dispatch [:navigate-to-nav2 :community
{:community-id id} true])
:on-press #(re-frame/dispatch [:navigate-to-nav2 :community-overview id true])
:content {:community-info {:type :permission}}}))
(defn community-channel-card
@@ -101,7 +100,7 @@
{:content {:community-channel {:emoji (:emoji channel)
:channel-name (str "# " (:name channel))}}
:on-press (fn []
(re-frame/dispatch [:navigate-to-nav2 :community {:community-id community-id}])
(re-frame/dispatch [:navigate-to-nav2 :community-overview community-id true])
(js/setTimeout
#(re-frame/dispatch [:chat/navigate-to-chat channel-id true])
100))}))
+80
View File
@@ -0,0 +1,80 @@
(ns status-im2.subs.shell-test
(:require [utils.re-frame :as rf]
[re-frame.db :as rf-db]
[test-helpers.unit :as h]
[cljs.test :refer [is testing]]
[status-im2.constants :as constants]))
(def public-profile-timeline-chats
{"0xpublic-chat" {:chat-type constants/public-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 6}
"0xprofile-chat" {:chat-type constants/profile-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 6}
"0xtimeline-chat" {:chat-type constants/timeline-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 6}})
(def expected-notification-data-for-public-profile-timeline-chats
{:communities-stack {:new-notifications? false
:notification-indicator :unread-dot
:counter-label 0}
:chats-stack {:new-notifications? false
:notification-indicator :unread-dot
:counter-label 0}})
(def one-to-one-group-community-chats1
{"0xone-to-one-chat1" {:chat-type constants/one-to-one-chat-type
:unviewed-messages-count 5
:unviewed-mentions-count 0}
"0xgroup-chat1" {:chat-type constants/private-group-chat-type
:unviewed-messages-count 2
:unviewed-mentions-count 0}
"0xcommunity-chat1" {:chat-type constants/community-chat-type
:unviewed-messages-count 3
:unviewed-mentions-count 0}})
(def expected-notification-data-for-one-to-one-group-community-chats1
{:communities-stack {:new-notifications? true
:notification-indicator :unread-dot
:counter-label 0}
:chats-stack {:new-notifications? true
:notification-indicator :unread-dot
:counter-label 0}})
(def one-to-one-group-community-chats2
(merge
one-to-one-group-community-chats1
{"0xone-to-one-chat2" {:chat-type constants/one-to-one-chat-type
:unviewed-messages-count 8
:unviewed-mentions-count 6}
"0xgroup-chat2" {:chat-type constants/private-group-chat-type
:unviewed-messages-count 4
:unviewed-mentions-count 3}
"0xcommunity-chat2" {:chat-type constants/community-chat-type
:unviewed-messages-count 9
:unviewed-mentions-count 7}}))
(def expected-notification-data-for-one-to-one-group-community-chats2
{:communities-stack {:new-notifications? true
:notification-indicator :counter
:counter-label 7}
:chats-stack {:new-notifications? true
:notification-indicator :counter
:counter-label 9}})
(h/deftest-sub :shell/bottom-tabs-notifications-data
[sub-name]
(testing "public, profile and timeline chats should not affect shell bottom tab indicator"
(swap! rf-db/app-db assoc :chats public-profile-timeline-chats)
(is (= (rf/sub [sub-name]) expected-notification-data-for-public-profile-timeline-chats)))
(testing "chats with only unviewed-messages, without unviewed-mentions count should use unread-dot"
(swap! rf-db/app-db assoc :chats one-to-one-group-community-chats1)
(is (= (rf/sub [sub-name]) expected-notification-data-for-one-to-one-group-community-chats1)))
(testing
"chats with both unviewed-messages and unviewed-mentions count should use counter with mentions count"
(swap! rf-db/app-db assoc :chats one-to-one-group-community-chats2)
(is (= (rf/sub [sub-name]) expected-notification-data-for-one-to-one-group-community-chats2))))
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.128.2",
"commit-sha1": "550de3bff2ff1500347bafca78aefa4cd6a9c526",
"src-sha256": "17j1x5dsyvdj8i6s5fiqh0dbwsqmv9sqx1x60axak8nywfl6b62x"
"version": "v0.131.7+hotfix.1",
"commit-sha1": "47263752fca6d2efab08430aa71d33296374b805",
"src-sha256": "1fsv1nlqw0rln01alzr5bqlh9mkh2jjwxg1binfiwq34fk91r4sq"
}
+7 -11
View File
@@ -4,11 +4,11 @@ from datetime import datetime
from http.client import RemoteDisconnected
from os import environ
from time import sleep
from io import BytesIO
import os
import urllib.request
import pytest
from _pytest.runner import runtestprotocol
import requests
import tests
from support.device_stats_db import DeviceStatsDB
@@ -203,18 +203,14 @@ def pytest_configure(config):
if config.getoption('env') == 'sauce':
if not is_uploaded():
if 'http' in config.getoption('apk'):
response = requests.get(config.getoption('apk'), stream=True)
response.raise_for_status()
apk_name = config.getoption('apk').split("/")[-1]
file = BytesIO(response.content)
del response
# it works with just a file_name, but I've added full path because not sure how it'll behave on the remote run (Jenkins)
file_path = os.path.join(os.path.dirname(__file__), apk_name)
for _ in range(3):
try:
requests.post('https://' + apibase + '/rest/v1/storage/'
+ sauce_username + '/' + apk_name + '?overwrite=true',
auth=(sauce_username, sauce_access_key),
data=file,
headers={'Content-Type': 'application/octet-stream'})
urllib.request.urlretrieve(config.getoption('apk'), filename=file_path) # if url is not valid it raises an error
sauce.storage.upload(file_path)
os.remove(file_path)
break
except ConnectionError:
sleep(10)
+3 -2
View File
@@ -1875,7 +1875,7 @@
"identity-verification-request": "Identity verification",
"identity-verification-request-sent": "asks",
"type-something": "Type something",
"type-some-chat-key": "0x123abc",
"type-some-chat-key": "zQ3abc...123",
"your-answer": "Your answer",
"membership": "Membership",
"jump-to": "Jump to",
@@ -1959,5 +1959,6 @@
"you-have-no-contacts": "You have no contacts",
"my-albums": "My albums",
"images": "images",
"only-6-images": "You can only add 6 images to your message"
"only-6-images": "You can only add 6 images to your message",
"delivered": "Delivered"
}