Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca569a7bd8 | ||
|
|
de7cfe9242 | ||
|
|
1e224217f7 | ||
|
|
9b15705f4a | ||
|
|
5ad6f6a256 | ||
|
|
70bd57a1d1 | ||
|
|
9c1cd317ab | ||
|
|
31371ac9e5 | ||
|
|
087a02c8a0 | ||
|
|
c825fa6634 | ||
|
|
b6c55097c3 | ||
|
|
57a81fbca0 | ||
|
|
d3f6cbf687 | ||
|
|
5e84446f9d | ||
|
|
3a299e2c7f | ||
|
|
cbaf5db674 | ||
|
|
59d122d6e3 | ||
|
|
4d99227036 | ||
|
|
574e69acae | ||
|
|
feae148ec8 | ||
|
|
8ebad39c25 | ||
|
|
8cfc6ecb4f | ||
|
|
cc348fda99 | ||
|
|
5f119c4b3a | ||
|
|
bf932e6825 | ||
|
|
0c59ed5ceb | ||
|
|
875f9f1acc | ||
|
|
98b219191f | ||
|
|
f8b5b35063 | ||
|
|
7315dc8914 | ||
|
|
e61bd769a8 | ||
|
|
b9ac26edd7 | ||
|
|
739d10a9ef | ||
|
|
361ddb338e | ||
|
|
91d0e106f2 | ||
|
|
89039cd79a | ||
|
|
0202af8070 | ||
|
|
0472140f02 |
+3
-11
@@ -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()
|
||||
}
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label params.AGENT_LABEL }
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label 'macos' }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
|
||||
+45
-6
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]])]))))
|
||||
|
||||
@@ -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}))))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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))))))))))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
[]
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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}]))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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])]])))
|
||||
|
||||
@@ -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}}})))
|
||||
|
||||
|
||||
@@ -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}]]))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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})))
|
||||
{}
|
||||
|
||||
@@ -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"])))))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}]}])
|
||||
|
||||
|
||||
@@ -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))}))
|
||||
|
||||
@@ -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,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"
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user