Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
866ba63ab7 | ||
|
|
ee5dcb3683 | ||
|
|
995d120d94 | ||
|
|
cbad7f4c87 | ||
|
|
488db615c0 | ||
|
|
5cea66647e | ||
|
|
ab750c1829 | ||
|
|
bbb07ff595 | ||
|
|
1753ea0de0 | ||
|
|
8ff7a1630c | ||
|
|
5e87d7eefd | ||
|
|
cdada3fa23 | ||
|
|
4020b4fdef | ||
|
|
ba89ac3fcf | ||
|
|
a5571eae92 | ||
|
|
c12cab27f4 | ||
|
|
d1514ec52d | ||
|
|
c4264462b1 | ||
|
|
b1d4368154 |
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.5'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.3'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
agent { label 'linux' }
|
||||
@@ -8,6 +8,8 @@ pipeline {
|
||||
disableConcurrentBuilds()
|
||||
/* Prevent Jenkins jobs from running forever */
|
||||
timeout(time: 40, unit: 'MINUTES')
|
||||
/* Allow copying of artifacts from this job. */
|
||||
copyArtifactPermission('/status-mobile/e2e/*')
|
||||
/* Limit builds retained */
|
||||
buildDiscarder(logRotator(
|
||||
numToKeepStr: '10',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.5'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
/* Options section can't access functions in objects. */
|
||||
def isPRBuild = utils.isPRBuild()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
|
||||
agent { label 'linux' }
|
||||
@@ -18,13 +20,17 @@ pipeline {
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
stage('Fetch') {
|
||||
when { expression { !params.APK_URL } }
|
||||
steps { script {
|
||||
if (params.PR_ID == null) {
|
||||
error("PR_ID parameter not set!")
|
||||
}
|
||||
copyArtifacts(
|
||||
projectName: "status-mobile/nightly",
|
||||
filter: '*-x86.apk',
|
||||
/* WARNING: This copies the latest available artifact. */
|
||||
selector: lastWithArtifacts(),
|
||||
)
|
||||
apk_path = "${env.WORKSPACE}/${utils.findFile('*-x86.apk')}"
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -73,7 +79,7 @@ pipeline {
|
||||
-m testrail_id \
|
||||
-m \"new_ui_critical or new_ui_medium\" \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
--apk=${params.APK_NAME}
|
||||
--apk=${params.APK_URL ?: apk_path}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library 'status-jenkins-lib@v1.6.5'
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
|
||||
@@ -14,6 +14,10 @@ pipeline {
|
||||
name: 'PR_ID',
|
||||
description: 'ID of the Pull Request triggering this build.',
|
||||
)
|
||||
string(
|
||||
name: 'APK_URL',
|
||||
description: 'Optional, set if job require APK to be downloaded from URL.',
|
||||
)
|
||||
string(
|
||||
name: 'KEYWORD_EXPRESSION',
|
||||
description: 'This will run tests which contain names that match the given string expression (Optional)',
|
||||
@@ -54,9 +58,11 @@ pipeline {
|
||||
}
|
||||
|
||||
stage('Fetch') {
|
||||
steps { script { /* WARNING: This copies the latest available artifact. */
|
||||
when { expression { !params.APK_URL } }
|
||||
steps { script {
|
||||
copyArtifacts(
|
||||
projectName: "status-mobile/prs/android-e2e/PR-${params.PR_ID}",
|
||||
/* WARNING: This copies the latest available artifact. */
|
||||
selector: lastWithArtifacts(),
|
||||
)
|
||||
apk_path = "${env.WORKSPACE}/${utils.findFile('result/*.apk')}"
|
||||
@@ -119,7 +125,7 @@ pipeline {
|
||||
--rerun_count=2 \
|
||||
--testrail_report=True \
|
||||
-k \"${params.KEYWORD_EXPRESSION}\" \
|
||||
--apk=${apk_path} \
|
||||
--apk=${params.APK_URL ?: apk_path} \
|
||||
--build=PR-${params.PR_ID}-${utils.timestamp()} \
|
||||
--pr_number=${params.PR_ID} \
|
||||
${extraPytestOpts}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
library 'status-jenkins-lib@v1.6.6'
|
||||
|
||||
pipeline {
|
||||
|
||||
agent { label 'linux' }
|
||||
|
||||
@@ -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' }
|
||||
|
||||
@@ -27,12 +27,10 @@ The most important thing is that
|
||||
|
||||
status-mobile code that makes it to the `develop` branch, should always point to a tagged version of status-go in the `develop` branch of status-go.
|
||||
|
||||
In practice this means:
|
||||
|
||||
|
||||
1) Create a PR in status-go, get it reviewed by status-go devs
|
||||
2) Create a PR in status-mobile, get it reviewed by devs, then go through manual testing (if necessary)
|
||||
3) Once ready to merge, merge status-go PR first, make sure you bump the `VERSION` file in status-go
|
||||
In practice, this means that sometimes they need to be merged in lockstep.
|
||||
1) Create a PR in status-go and status-mobile. Update the status-go version to the PR revision `scripts/update-status-go.sh $git_revision`.
|
||||
2) Get both PRs reviewed and approved. Once status-mobile PR has been approved, go through manual QA testing if necessary. Don't merge status-mobile PR just yet.
|
||||
3) Now that you know the integration between client & server is working, bump the `VERSION` in status-go and merge it.
|
||||
4) Once merged, tag the version with the new version and push the tag:
|
||||
```
|
||||
git checkout develop
|
||||
@@ -41,4 +39,7 @@ In practice this means:
|
||||
git push origin vx.y.z
|
||||
```
|
||||
5) Update status-mobile with the new status-go version, using the new tag `scripts/update-status-go.sh "vx.y.z"`
|
||||
6) Push, make sure it's rebased and go through the merge process as above.
|
||||
6) In status-mobile, push, rebase against `develop` and merge it 🚀
|
||||
|
||||
|
||||
important note : make sure your status-go PRs get a tested-ok by QA before merging them in.
|
||||
|
||||
+17
-3
@@ -1,4 +1,4 @@
|
||||
# Guidelines
|
||||
# Code Style Guidelines
|
||||
|
||||
>The goal of this document is to help all contributors (core and external) to
|
||||
>write code in _unison_ and help establish good practices that serve the Status
|
||||
@@ -77,7 +77,21 @@ Joshua Comeau.
|
||||
[rn/view {:style {:padding-horizontal 20}}]
|
||||
```
|
||||
|
||||
#### Styles def vs defn
|
||||
### Don't prepend booleans with is-
|
||||
|
||||
It is a common practice in JavaScript and other languages to prepend boolean variable names with `is-*`.
|
||||
In ClojureScript it is common practice to suffix boolean variable names with a `?`.
|
||||
There is no need for both of these and so it is preferable to stick with the latter.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(let [is-open? true] ...)
|
||||
|
||||
;; good
|
||||
(let [open? true] ...)
|
||||
```
|
||||
|
||||
### Styles def vs defn
|
||||
|
||||
Always use `def` over `defn`, unless the style relies on dynamic values, such as
|
||||
deref'ed atoms.
|
||||
@@ -170,7 +184,7 @@ Use the simple `defn` to declare components. Don't use `utils.views/defview` and
|
||||
(do-something window-width)))
|
||||
```
|
||||
|
||||
#### Use `[]` instead of `()` in Reagent components
|
||||
### 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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
+5
@@ -1139,6 +1139,11 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
|
||||
executeRunnableStatusGoMethod(() -> Statusgo.generateAlias(seed), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void emojiHash(final String publicKey, final Callback callback) throws JSONException {
|
||||
executeRunnableStatusGoMethod(() -> Statusgo.emojiHash(publicKey), callback);
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public String identicon(final String seed) {
|
||||
return Statusgo.identicon(seed);
|
||||
|
||||
@@ -865,6 +865,12 @@ RCT_EXPORT_METHOD(generateAliasAsync:(NSString *)publicKey
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(emojiHash:(NSString *)publicKey
|
||||
callback:(RCTResponseSenderBlock)callback) {
|
||||
NSString *result = StatusgoEmojiHash(publicKey);
|
||||
callback(@[result]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(identicon:(NSString *)publicKey) {
|
||||
return StatusgoIdenticon(publicKey);
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 539 KiB |
@@ -0,0 +1,70 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.component-spec
|
||||
(:require [quo2.components.drawers.drawer-buttons.view :as drawer-buttons]
|
||||
[react-native.core :as rn]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "drawer-buttons"
|
||||
(h/test "the top heading and subheading render"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(-> (js/expect (h/get-by-text "top-heading"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (h/get-by-text "top-sub-heading"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "the bottom heading and subheading render"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(-> (js/expect (h/get-by-text "bottom-heading"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (h/get-by-text "bottom-sub-heading"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
|
||||
(h/test "it clicks the top card"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:on-press event
|
||||
:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(h/fire-event :press (h/get-by-text "top-heading"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled))))
|
||||
|
||||
(h/test "it clicks the bottom card"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:on-press event
|
||||
:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(h/fire-event :press (h/get-by-text "bottom-heading"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled))))
|
||||
|
||||
(h/test "the top card child renders with a render prop"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
[rn/text :top-render-fn]
|
||||
:bottom-sub-heading])
|
||||
(-> (js/expect (h/get-by-text "top-render-fn"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "the bottom card child renders with a render prop"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
[rn/text :bottom-render-fn]])
|
||||
(-> (js/expect (h/get-by-text "bottom-render-fn"))
|
||||
(.toBeTruthy))))
|
||||
@@ -0,0 +1,48 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def outer-container {:height 216})
|
||||
|
||||
(def top-card
|
||||
{:flex 1
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-radius 20
|
||||
:background-color colors/neutral-80})
|
||||
|
||||
(def bottom-card
|
||||
{:position :absolute
|
||||
:top 80
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-radius 20
|
||||
:background-color (colors/alpha colors/white 0.05)})
|
||||
|
||||
(def bottom-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(def bottom-icon
|
||||
{:border-radius 40
|
||||
:border-width 1
|
||||
:margin-left 24
|
||||
:height 28
|
||||
:width 28
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:border-color (colors/alpha colors/white 0.05)})
|
||||
|
||||
(def bottom-text
|
||||
{:flex 1
|
||||
:color (colors/alpha colors/white 0.7)})
|
||||
|
||||
(def top-text
|
||||
{:color (colors/alpha colors/white 0.7)})
|
||||
|
||||
(defn heading-text
|
||||
[gap]
|
||||
{:color colors/white
|
||||
:margin-bottom gap})
|
||||
@@ -0,0 +1,80 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.view
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.drawers.drawer-buttons.style :as style]))
|
||||
|
||||
(defn render-bottom
|
||||
[children]
|
||||
[rn/view {:style style/bottom-container}
|
||||
children
|
||||
[rn/view
|
||||
{:style style/bottom-icon}
|
||||
[icon/icon :arrow-right
|
||||
{:color colors/white
|
||||
:size 20}]]])
|
||||
|
||||
(defn label? [el] (or (string? el) (keyword? el)))
|
||||
|
||||
(defn render-children-bottom
|
||||
[children]
|
||||
(if (label? children)
|
||||
[render-bottom
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style style/bottom-text
|
||||
:weight :semi-bold}
|
||||
children]]
|
||||
[render-bottom children]))
|
||||
|
||||
(defn render-children-top
|
||||
[children]
|
||||
(if (label? children)
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style style/top-text
|
||||
:weight :semi-bold}
|
||||
children]
|
||||
children))
|
||||
|
||||
(defn card
|
||||
[{:keys [on-press style heading gap top?]} children]
|
||||
[rn/touchable-highlight
|
||||
{:on-press on-press
|
||||
:border-radius 20
|
||||
:style style
|
||||
:underlay-color (:background-color style)}
|
||||
[rn/view {}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:style (style/heading-text gap)
|
||||
:weight :semi-bold}
|
||||
heading]
|
||||
(if top?
|
||||
[render-children-top children]
|
||||
[render-children-bottom children])]])
|
||||
|
||||
(defn view
|
||||
"[view opts]
|
||||
opts
|
||||
{:container-style style-object
|
||||
:top-card { :on-press event
|
||||
:heading string}
|
||||
:bottom-card { :on-press event
|
||||
:heading string}}
|
||||
child-1 string, keyword or hiccup
|
||||
child-2 string, keyword or hiccup
|
||||
"
|
||||
[{:keys [container-style top-card bottom-card]} child-1 child-2]
|
||||
[rn/view
|
||||
{:style (merge container-style style/outer-container)}
|
||||
[card
|
||||
(merge {:gap 4
|
||||
:top? true
|
||||
:style style/top-card}
|
||||
top-card) child-1]
|
||||
[card
|
||||
(merge {:style style/bottom-card
|
||||
:gap 20}
|
||||
bottom-card) child-2]])
|
||||
@@ -173,7 +173,7 @@
|
||||
(utils/truncate-str (:info content) 24)])]]]])
|
||||
|
||||
(defn system-message
|
||||
[{:keys [type style non-pressable? animate-landing? labels] :as message}]
|
||||
[{:keys [type style non-pressable? animate-landing? labels on-long-press] :as message}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [sv-color (reanimated/use-shared-value
|
||||
@@ -186,16 +186,17 @@
|
||||
:linear
|
||||
1000))
|
||||
[reanimated/touchable-opacity
|
||||
{:on-press #(when-not non-pressable?
|
||||
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:background-color sv-color}
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:padding-vertical 9
|
||||
:padding-horizontal 11
|
||||
:background-color sv-color}
|
||||
style))}
|
||||
{:on-press #(when-not non-pressable?
|
||||
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
|
||||
:on-long-press on-long-press
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:background-color sv-color}
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:padding-vertical 9
|
||||
:padding-horizontal 11
|
||||
:background-color sv-color}
|
||||
style))}
|
||||
[sm-render message labels]]))])
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
(ns quo2.components.onboarding.small-option-card.component-spec
|
||||
(:require [quo2.components.onboarding.small-option-card.view :as small-option-card]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defn- testing-small-option-card
|
||||
[variant
|
||||
{:keys [title subtitle image on-press]
|
||||
:or {title "title" subtitle "subtitle"}}]
|
||||
[small-option-card/small-option-card
|
||||
{:variant variant
|
||||
:title title
|
||||
:subtitle subtitle
|
||||
:image image
|
||||
:on-press on-press}])
|
||||
|
||||
(h/describe "small-option-card"
|
||||
(h/describe "Title & subtitle are rendered"
|
||||
(let [title "A title"
|
||||
subtitle "A subtitle"
|
||||
component-props {:title title :subtitle subtitle}]
|
||||
(h/test "`:main` variant"
|
||||
(h/render (testing-small-option-card :main component-props))
|
||||
(-> (h/get-by-text title) h/expect .toBeTruthy)
|
||||
(-> (h/get-by-text subtitle) h/expect .toBeTruthy))
|
||||
|
||||
(h/test "`:icon` variant"
|
||||
(h/render (testing-small-option-card :icon component-props))
|
||||
(-> (h/get-by-text title) h/expect .toBeTruthy)
|
||||
(-> (h/get-by-text subtitle) h/expect .toBeTruthy))))
|
||||
|
||||
(h/describe "Card pressed"
|
||||
(let [on-press-fn (h/mock-fn)
|
||||
component-props {:on-press on-press-fn}]
|
||||
(h/test "`:main` variant"
|
||||
(h/render (testing-small-option-card :main component-props))
|
||||
(h/fire-event :press (h/get-by-label-text :small-option-card))
|
||||
(-> on-press-fn js/expect .toHaveBeenCalled))
|
||||
|
||||
(h/test "`:icon` variant"
|
||||
(h/render (testing-small-option-card :icon component-props))
|
||||
(h/fire-event :press (h/get-by-label-text :small-option-card))
|
||||
(-> on-press-fn js/expect .toHaveBeenCalled))))
|
||||
|
||||
(h/describe "Image rendered"
|
||||
(let [image (resources/get-mock-image :small-opt-card-main)
|
||||
component-props {:image image}]
|
||||
(h/test "`:main` variant"
|
||||
(h/render (testing-small-option-card :main component-props))
|
||||
(-> (h/get-by-label-text :small-option-card-main-image) h/expect .-not .toBeNull))
|
||||
|
||||
(h/test "`:icon` variant"
|
||||
(h/render (testing-small-option-card :icon component-props))
|
||||
(-> (h/get-by-label-text :small-option-card-icon-image) h/expect .-not .toBeNull)))))
|
||||
@@ -0,0 +1,52 @@
|
||||
(ns quo2.components.onboarding.small-option-card.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def text-container {:flex 1})
|
||||
|
||||
(def title
|
||||
{:color colors/white
|
||||
:height 22})
|
||||
|
||||
(def subtitle
|
||||
{:color colors/white-opa-70
|
||||
:height 18})
|
||||
|
||||
(def icon-variant
|
||||
{:flex-direction :row
|
||||
:padding-vertical 8
|
||||
:padding-horizontal 12})
|
||||
|
||||
(def icon-variant-image-container
|
||||
{:width 32
|
||||
:height 40
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:padding-vertical 4
|
||||
:margin-right 8})
|
||||
|
||||
(def icon-variant-image
|
||||
{:flex 1
|
||||
:width 32
|
||||
:height 32})
|
||||
|
||||
(def main-variant
|
||||
{:flex 1
|
||||
:margin-bottom -8})
|
||||
|
||||
(def main-variant-text-container
|
||||
{:height 62
|
||||
:padding-top 10
|
||||
:padding-bottom 12
|
||||
:padding-horizontal 12})
|
||||
|
||||
(def touchable-overlay {:border-radius 16})
|
||||
|
||||
(defn card-container
|
||||
[main-variant?]
|
||||
(when main-variant? {:height 343}))
|
||||
|
||||
(defn card
|
||||
[main-variant?]
|
||||
{:background-color colors/white-opa-5
|
||||
:border-radius 16
|
||||
:height (if main-variant? 335 56)})
|
||||
@@ -0,0 +1,66 @@
|
||||
(ns quo2.components.onboarding.small-option-card.view
|
||||
(:require [quo2.components.markdown.text :as text]
|
||||
[quo2.components.onboarding.small-option-card.style :as style]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]))
|
||||
|
||||
(defn- texts
|
||||
[{:keys [title subtitle]}]
|
||||
[rn/view {:style style/text-container}
|
||||
[text/text
|
||||
{:style style/title
|
||||
:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:number-of-lines 1}
|
||||
title]
|
||||
[text/text
|
||||
{:style style/subtitle
|
||||
:size :paragraph-2
|
||||
:weight :regular
|
||||
:number-of-lines 1}
|
||||
subtitle]])
|
||||
|
||||
(defn- icon-variant
|
||||
[{:keys [title subtitle image]}]
|
||||
[rn/view {:style style/icon-variant}
|
||||
[rn/view {:style style/icon-variant-image-container}
|
||||
[fast-image/fast-image
|
||||
{:accessibility-label :small-option-card-icon-image
|
||||
:style style/icon-variant-image
|
||||
:resize-mode :contain
|
||||
:source image}]]
|
||||
[texts
|
||||
{:title title
|
||||
:subtitle subtitle}]])
|
||||
|
||||
(defn- main-variant
|
||||
[{:keys [title subtitle image]}]
|
||||
[rn/view {:style style/main-variant}
|
||||
[rn/view {:style style/main-variant-text-container}
|
||||
[texts
|
||||
{:title title
|
||||
:subtitle subtitle}]]
|
||||
[fast-image/fast-image
|
||||
{:accessibility-label :small-option-card-main-image
|
||||
:style {:flex 1}
|
||||
:resize-mode :contain
|
||||
:source image}]])
|
||||
|
||||
(defn small-option-card
|
||||
[{:keys [variant title subtitle image on-press]
|
||||
:or {variant :main}}]
|
||||
(let [main-variant? (= variant :main)
|
||||
card-component (if main-variant? main-variant icon-variant)]
|
||||
[rn/touchable-highlight
|
||||
{:accessibility-label :small-option-card
|
||||
:style style/touchable-overlay
|
||||
:active-opacity 1
|
||||
:underlay-color colors/white-opa-5
|
||||
:on-press on-press}
|
||||
[rn/view {:style (style/card-container main-variant?)}
|
||||
[rn/view {:style (style/card main-variant?)}
|
||||
[card-component
|
||||
{:title title
|
||||
:subtitle subtitle
|
||||
:image image}]]]]))
|
||||
@@ -21,6 +21,7 @@
|
||||
quo2.components.dividers.divider-label
|
||||
quo2.components.dividers.new-messages
|
||||
quo2.components.drawers.action-drawers.view
|
||||
quo2.components.drawers.drawer-buttons.view
|
||||
quo2.components.drawers.permission-context.view
|
||||
quo2.components.dropdowns.dropdown
|
||||
quo2.components.header
|
||||
@@ -50,6 +51,7 @@
|
||||
quo2.components.separator
|
||||
quo2.components.settings.accounts.view
|
||||
quo2.components.settings.privacy-option
|
||||
quo2.components.onboarding.small-option-card.view
|
||||
quo2.components.tabs.account-selector
|
||||
quo2.components.tabs.tabs
|
||||
quo2.components.tags.context-tags
|
||||
@@ -101,6 +103,9 @@
|
||||
;;;; BANNER
|
||||
(def banner quo2.components.banners.banner.view/banner)
|
||||
|
||||
;;;; CARDS
|
||||
(def small-option-card quo2.components.onboarding.small-option-card.view/small-option-card)
|
||||
|
||||
;;;; COMMUNITY
|
||||
(def community-card-view-item quo2.components.community.community-card-view/community-card-view-item)
|
||||
(def communities-list-view-item quo2.components.community.community-list-view/communities-list-view-item)
|
||||
@@ -122,6 +127,7 @@
|
||||
|
||||
;;;; DRAWERS
|
||||
(def action-drawer quo2.components.drawers.action-drawers.view/action-drawer)
|
||||
(def drawer-buttons quo2.components.drawers.drawer-buttons.view/view)
|
||||
(def permission-context quo2.components.drawers.permission-context.view/view)
|
||||
|
||||
;;;; LIST ITEMS
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
[quo2.components.counter.--tests--.counter-component-spec]
|
||||
[quo2.components.dividers.--tests--.divider-label-component-spec]
|
||||
[quo2.components.drawers.action-drawers.component-spec]
|
||||
[quo2.components.drawers.drawer-buttons.component-spec]
|
||||
[quo2.components.drawers.permission-context.component-spec]
|
||||
[quo2.components.markdown.--tests--.text-component-spec]
|
||||
[quo2.components.selectors.--tests--.selectors-component-spec]
|
||||
[quo2.components.selectors.filter.component-spec]
|
||||
[quo2.components.onboarding.small-option-card.component-spec]
|
||||
[quo2.components.record-audio.record-audio.--tests--.record-audio-component-spec]
|
||||
[quo2.components.record-audio.soundtrack.--tests--.soundtrack-component-spec]))
|
||||
[quo2.components.record-audio.soundtrack.--tests--.soundtrack-component-spec]
|
||||
[quo2.components.selectors.--tests--.selectors-component-spec]
|
||||
[quo2.components.selectors.filter.component-spec]))
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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,29 @@
|
||||
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]}]
|
||||
"Use preferred name, display-name, name or alias in that order"
|
||||
[{:keys [name display-name preferred-name alias public-key ens-verified]}]
|
||||
(let [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))))
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[status-im2.common.log :as logging]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.security.core :as security]))
|
||||
[utils.security.core :as security]
|
||||
[status-im2.contexts.emoji-hash.events :as emoji-hash]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::initialize-communities-enabled
|
||||
@@ -473,6 +474,7 @@
|
||||
(get-group-chat-invitations)
|
||||
(multiaccounts/get-profile-picture)
|
||||
(multiaccounts/switch-preview-privacy-mode-flag)
|
||||
(emoji-hash/fetch-for-current-public-key)
|
||||
(link-preview/request-link-preview-whitelist)
|
||||
(visibility-status-updates-store/fetch-visibility-status-updates-rpc)
|
||||
(switcher-cards-store/fetch-switcher-cards-rpc))))
|
||||
|
||||
@@ -481,6 +481,12 @@
|
||||
(when (validators/valid-public-key? public-key)
|
||||
(.generateAliasAsync ^js (status) public-key callback)))
|
||||
|
||||
(defn public-key->emoji-hash
|
||||
"Generate an emoji hash from the multiaccount public key"
|
||||
[public-key callback]
|
||||
(when (validators/valid-public-key? public-key)
|
||||
(.emojiHash ^js (status) public-key callback)))
|
||||
|
||||
(defn identicon
|
||||
"Generate a icon based on a string, synchronously"
|
||||
[seed]
|
||||
|
||||
@@ -67,7 +67,9 @@
|
||||
:user-picture-female2 (js/require "../resources/images/mock/user_picture_female2.png")
|
||||
:user-picture-male4 (js/require "../resources/images/mock/user_picture_male4.png")
|
||||
:user-picture-male5 (js/require "../resources/images/mock/user_picture_male5.png")
|
||||
:coinbase (js/require "../resources/images/mock/coinbase.png")})
|
||||
:coinbase (js/require "../resources/images/mock/coinbase.png")
|
||||
:small-opt-card-icon (js/require "../resources/images/mock/small_opt_card_icon.png")
|
||||
:small-opt-card-main (js/require "../resources/images/mock/small_opt_card_main.png")})
|
||||
|
||||
(defn get-theme-image
|
||||
[k]
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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,14 +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.components.safe-area :as safe-area]
|
||||
[status-im.react-native.resources :as resources]))
|
||||
|
||||
(defn- hide-sheet-and-dispatch
|
||||
@@ -33,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
|
||||
@@ -74,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
|
||||
@@ -85,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
|
||||
@@ -99,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
|
||||
@@ -110,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))])]))])
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
[from username current-public-key]
|
||||
(or (and (= from current-public-key)
|
||||
(i18n/label :t/You))
|
||||
(format-author username)))
|
||||
(when username (format-author username))))
|
||||
|
||||
(defn reply-deleted-message
|
||||
[]
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.components.fast-image :as fast-image]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.chat.image.preview.views :as preview]
|
||||
[status-im.ui.screens.chat.message.audio :as message.audio]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||
@@ -21,14 +19,14 @@
|
||||
[status-im.ui.screens.chat.utils :as chat.utils]
|
||||
[status-im.ui.screens.communities.icon :as communities.icon]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
|
||||
[status-im2.config :as config]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]
|
||||
[status-im2.contexts.chat.messages.delete-message-for-me.events]
|
||||
[status-im2.contexts.chat.messages.delete-message.events]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.core :as quo])
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defn system-text?
|
||||
@@ -40,7 +38,7 @@
|
||||
(rf/sub [:contacts/contact-name-by-identity from]))
|
||||
|
||||
(defn render-inline
|
||||
[_message-text content-type acc {:keys [type literal destination]} use-status-tag?]
|
||||
[_message-text content-type acc {:keys [type literal destination]}]
|
||||
(case type
|
||||
""
|
||||
(conj acc literal)
|
||||
@@ -82,10 +80,9 @@
|
||||
"status-tag"
|
||||
(conj acc
|
||||
[rn/text
|
||||
(when use-status-tag?
|
||||
{:style {:color :blue
|
||||
:text-decoration-line :underline}
|
||||
:on-press #(rf/dispatch [:chat.ui/start-public-chat literal])})
|
||||
{:style {:color :blue
|
||||
:text-decoration-line :underline}
|
||||
:on-press #(rf/dispatch [:chat.ui/start-public-chat literal])}
|
||||
"#"
|
||||
literal])
|
||||
|
||||
@@ -97,15 +94,13 @@
|
||||
;; TEXT
|
||||
(defn render-block
|
||||
[{:keys [content content-type edited-at in-popover?]} acc
|
||||
{:keys [type ^js literal children]}
|
||||
use-status-tag?]
|
||||
|
||||
{:keys [type ^js literal children]}]
|
||||
(case type
|
||||
|
||||
"paragraph"
|
||||
(conj acc
|
||||
(reduce
|
||||
(fn [acc e] (render-inline (:text content) content-type acc e use-status-tag?))
|
||||
(fn [acc e] (render-inline (:text content) content-type acc e))
|
||||
[rn/text (style/text-style content-type in-popover?)]
|
||||
(conj
|
||||
children
|
||||
@@ -126,13 +121,11 @@
|
||||
acc))
|
||||
|
||||
(defn render-parsed-text
|
||||
[{:keys [content chat-id] :as message-data}]
|
||||
(let [{:keys [chat-type]} (rf/sub [:chats/chat chat-id])
|
||||
use-status-tag? (= constants/community-chat-type chat-type)]
|
||||
(reduce (fn [acc e]
|
||||
(render-block message-data acc e use-status-tag?))
|
||||
[:<>]
|
||||
(:parsed-text content))))
|
||||
[{:keys [content] :as message-data}]
|
||||
(reduce (fn [acc e]
|
||||
(render-block message-data acc e))
|
||||
[:<>]
|
||||
(:parsed-text content)))
|
||||
|
||||
(defn quoted-message
|
||||
[{:keys [message-id chat-id]} reply pin?]
|
||||
@@ -235,65 +228,13 @@
|
||||
(re-frame/dispatch [:pin-message/show-pin-limit-modal chat-id]))
|
||||
(re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned (not pinned))]))))
|
||||
|
||||
(defn on-long-press-fn
|
||||
[on-long-press
|
||||
{:keys [pinned message-pin-enabled outgoing edit-enabled show-input? community?
|
||||
can-delete-message-for-everyone?]
|
||||
:as message} content]
|
||||
(on-long-press
|
||||
(concat
|
||||
(when (and outgoing edit-enabled)
|
||||
[{:type :main
|
||||
:on-press #(re-frame/dispatch [:chat.ui/edit-message message])
|
||||
:label (i18n/label :t/edit-message)
|
||||
:icon :i/edit
|
||||
:id :edit}])
|
||||
(when show-input?
|
||||
[{:type :main
|
||||
:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||
:label (i18n/label :t/message-reply)
|
||||
:icon :i/reply
|
||||
:id :reply}])
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
:id :copy}]
|
||||
(when message-pin-enabled
|
||||
[{:type :main
|
||||
:on-press #(pin-message message)
|
||||
:label (i18n/label (if pinned
|
||||
(if community? :t/unpin-from-channel :t/unpin-from-chat)
|
||||
(if community? :t/pin-to-channel :t/pin-to-chat)))
|
||||
:icon :i/pin
|
||||
:id (if pinned :unpin :pin)}])
|
||||
(when-not pinned
|
||||
[{:type :danger
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch
|
||||
[:chat.ui/delete-message-for-me message
|
||||
config/delete-message-for-me-undo-time-limit-ms]))
|
||||
:label (i18n/label :t/delete-for-me)
|
||||
:icon :i/delete
|
||||
:id :delete-for-me}])
|
||||
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
|
||||
[{:type :danger
|
||||
:on-press #(re-frame/dispatch [:chat.ui/delete-message
|
||||
message
|
||||
config/delete-message-undo-time-limit-ms])
|
||||
:label (i18n/label :t/delete-for-everyone)
|
||||
:icon :i/delete
|
||||
:id :delete-for-all}]))))
|
||||
|
||||
;; STATUS ? whats that ?
|
||||
(defmethod ->message constants/content-type-status
|
||||
[{:keys [content content-type]}]
|
||||
[rn/view style/status-container
|
||||
[rn/text {:style (style/status-text)}
|
||||
(reduce
|
||||
(fn [acc e] (render-inline (:text content) content-type acc e false))
|
||||
(fn [acc e] (render-inline (:text content) content-type acc e))
|
||||
[rn/text {:style (style/status-text)}]
|
||||
(-> content :parsed-text peek :children))]])
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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}]))
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
:style {:line-height 21}}
|
||||
name]])
|
||||
(if top-nav
|
||||
[top-nav]
|
||||
top-nav
|
||||
[quo/page-nav
|
||||
(merge {:horizontal-description? true
|
||||
:one-icon-align-left? true
|
||||
@@ -89,7 +89,7 @@
|
||||
:icon-background-color (icon-color)
|
||||
:on-press #(rf/dispatch [:navigate-back])}}))])
|
||||
(when title-colum
|
||||
[title-colum])
|
||||
title-colum)
|
||||
sticky-header]]))
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
(def communities-enabled? (enabled? (get-config :COMMUNITIES_ENABLED "0")))
|
||||
(def database-management-enabled? (enabled? (get-config :DATABASE_MANAGEMENT_ENABLED "0")))
|
||||
(def debug-webview? (enabled? (get-config :DEBUG_WEBVIEW "0")))
|
||||
(def delete-message-enabled? (enabled? (get-config :DELETE_MESSAGE_ENABLED "0")))
|
||||
(def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1")))
|
||||
(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0")))
|
||||
(def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0")))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -36,13 +36,11 @@
|
||||
parsed-text-children))))
|
||||
|
||||
(defn view
|
||||
[{:keys [author chat-name chat-id message read timestamp]}]
|
||||
(let [chat (rf/sub [:chats/chat chat-id])
|
||||
community-id (:community-id chat)
|
||||
is-chat-from-community? (not (nil? community-id))
|
||||
community (rf/sub [:communities/community community-id])
|
||||
community-name (:name community)
|
||||
community-image (get-in community [:images :thumbnail :uri])]
|
||||
[{:keys [author chat-name community-id chat-id message read timestamp]}]
|
||||
(let [community-chat? (not (string/blank? community-id))
|
||||
community (rf/sub [:communities/community community-id])
|
||||
community-name (:name community)
|
||||
community-image (get-in community [:images :thumbnail :uri])]
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:hide-popover])
|
||||
@@ -54,7 +52,7 @@
|
||||
:unread? (not read)
|
||||
:context [[common/user-avatar-tag author]
|
||||
[quo/text {:style style/tag-text} (string/lower-case (i18n/label :t/on))]
|
||||
(if is-chat-from-community?
|
||||
(if community-chat?
|
||||
[quo/context-tag tag-params {:uri community-image} community-name chat-name]
|
||||
[quo/group-avatar-tag chat-name tag-params])]
|
||||
:message {:body (message-body message)}}]]))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im2.contexts.activity-center.notification.reply.view
|
||||
(:require [quo2.core :as quo]
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[status-im.ui2.screens.chat.messages.message :as old-message]
|
||||
@@ -37,13 +38,11 @@
|
||||
nil))
|
||||
|
||||
(defn view
|
||||
[{:keys [author chat-name chat-id message read timestamp]}]
|
||||
(let [chat (rf/sub [:chats/chat chat-id])
|
||||
community-id (:community-id chat)
|
||||
is-chat-from-community? (not (nil? community-id))
|
||||
community (rf/sub [:communities/community community-id])
|
||||
community-name (:name community)
|
||||
community-image (get-in community [:images :thumbnail :uri])]
|
||||
[{:keys [author chat-name community-id chat-id message read timestamp]}]
|
||||
(let [community-chat? (not (string/blank? community-id))
|
||||
community (rf/sub [:communities/community community-id])
|
||||
community-name (:name community)
|
||||
community-image (get-in community [:images :thumbnail :uri])]
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:hide-popover])
|
||||
@@ -55,7 +54,7 @@
|
||||
:unread? (not read)
|
||||
:context [[common/user-avatar-tag author]
|
||||
[quo/text {:style style/lowercase-text} (i18n/label :t/on)]
|
||||
(if is-chat-from-community?
|
||||
(if community-chat?
|
||||
[quo/context-tag tag-params {:uri community-image} community-name chat-name]
|
||||
[quo/group-avatar-tag chat-name tag-params])]
|
||||
:message {:body-number-of-lines 1
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[status-im.ethereum.ens :as ens]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im2.navigation.events :as navigation]
|
||||
[status-im2.utils.validators :as validators]
|
||||
[status-im.utils.utils :as utils]))
|
||||
|
||||
@@ -109,3 +110,10 @@
|
||||
{:events [:contacts/clear-new-identity :contacts/new-chat-focus]}
|
||||
[{:keys [db]}]
|
||||
{:db (dissoc db :contacts/new-identity)})
|
||||
|
||||
(rf/defn qr-code-scanned
|
||||
{:events [:contacts/qr-code-scanned]}
|
||||
[{:keys [db] :as cofx} input]
|
||||
(rf/merge cofx
|
||||
(set-new-identity input)
|
||||
(navigation/navigate-back)))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.qr-scanner.core :as qr-scanner]
|
||||
[status-im2.contexts.add-new-contact.style :as style]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -42,7 +43,8 @@
|
||||
600)})]
|
||||
[quo/button
|
||||
(merge style/button-qr
|
||||
{:on-press #(js/alert "TODO: to be implemented")})
|
||||
{:on-press #(rf/dispatch [::qr-scanner/scan-code
|
||||
{:handler :contacts/qr-code-scanned}])})
|
||||
:i/scan]]
|
||||
(when error?
|
||||
[rn/view style/container-error
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.chat.messages.content.deleted.view
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.chat.messages.drawers.view :as drawers]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -20,8 +21,20 @@
|
||||
[quo/text {:style {:margin-left 4} :size :paragraph-2}
|
||||
(i18n/label :t/deleted-this-message)]])
|
||||
|
||||
(defn- compute-on-long-press-fn
|
||||
[{:keys [deleted? pinned] :as message}
|
||||
{:keys [message-pin-enabled] :as context}]
|
||||
;; only show drawer for user who has the permission to unpin messages
|
||||
(when (and pinned deleted? message-pin-enabled)
|
||||
(fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (drawers/reactions-and-actions message
|
||||
context)}]))))
|
||||
|
||||
(defn deleted-by-message
|
||||
[{:keys [deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]}]
|
||||
[{:keys [deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]}
|
||||
on-long-press-fn]
|
||||
(let [;; deleted message with nil deleted-by is deleted by (:from message)
|
||||
display-name (first (rf/sub [:contacts/contact-two-names-by-identity (or deleted-by from)]))
|
||||
contact (rf/sub [:contacts/contact-by-address (or deleted-by from)])
|
||||
@@ -32,21 +45,25 @@
|
||||
:timestamp-str timestamp-str
|
||||
:child [user-xxx-deleted-this-message
|
||||
{:display-name display-name :profile-picture photo-path}]
|
||||
:non-pressable? true
|
||||
:on-long-press on-long-press-fn
|
||||
:non-pressable? (if on-long-press-fn false true)
|
||||
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}]))
|
||||
|
||||
(defn deleted-message
|
||||
[{:keys [deleted? deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]
|
||||
:as message}]
|
||||
(let [pub-key (rf/sub [:multiaccount/public-key])
|
||||
deleted-by-me? (= (or deleted-by from) pub-key)]
|
||||
(if (not deleted-by-me?)
|
||||
[deleted-by-message message]
|
||||
:as message}
|
||||
context]
|
||||
(let [pub-key (rf/sub [:multiaccount/public-key])
|
||||
deleted-by-me? (= (or deleted-by from) pub-key)
|
||||
on-long-press-fn (compute-on-long-press-fn message context)]
|
||||
(if-not deleted-by-me?
|
||||
[deleted-by-message message on-long-press-fn]
|
||||
[quo/system-message
|
||||
{:type :deleted
|
||||
:label (if deleted? :message-deleted :message-deleted-for-you)
|
||||
:labels {:message-deleted (i18n/label :t/message-deleted-for-everyone)
|
||||
:message-deleted-for-you (i18n/label :t/message-deleted-for-you)}
|
||||
:on-long-press on-long-press-fn
|
||||
:timestamp-str timestamp-str
|
||||
:non-pressable? true
|
||||
:non-pressable? (if on-long-press-fn false true)
|
||||
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}])))
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn message-container
|
||||
[in-pinned-view? pinned mentioned last-in-group?]
|
||||
(merge (when (and (not in-pinned-view?) (or mentioned pinned))
|
||||
[in-pinned-view? pinned-by mentioned last-in-group?]
|
||||
(merge (when (and (not in-pinned-view?) (or mentioned pinned-by))
|
||||
{:background-color colors/primary-50-opa-5
|
||||
:margin-bottom 4})
|
||||
(when (or mentioned pinned last-in-group?)
|
||||
(when (or mentioned pinned-by last-in-group?)
|
||||
{:margin-top 8})
|
||||
{:border-radius 16}))
|
||||
|
||||
@@ -156,14 +156,14 @@
|
||||
[status/status outgoing-status])]]]])))])
|
||||
|
||||
(defn message-with-reactions
|
||||
[{:keys [pinned pinned-by mentioned in-pinned-view? content-type
|
||||
[{:keys [pinned-by mentioned in-pinned-view? content-type
|
||||
last-in-group? message-id messages-ids]
|
||||
:as message-data}
|
||||
{:keys [chat-id] :as context}]
|
||||
[rn/view
|
||||
{:style (style/message-container in-pinned-view? pinned mentioned last-in-group?)
|
||||
{:style (style/message-container in-pinned-view? pinned-by mentioned last-in-group?)
|
||||
:accessibility-label :chat-item}
|
||||
(when pinned
|
||||
(when pinned-by
|
||||
[pin/pinned-by-view pinned-by])
|
||||
(if (#{constants/content-type-system-text constants/content-type-community
|
||||
constants/content-type-contact-request}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns status-im2.contexts.chat.messages.delete-message.events
|
||||
(:require
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- update-db-clear-undo-timer
|
||||
@@ -47,6 +47,26 @@
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
(update-in db [:messages chat-id message-id] assoc :deleted? true :deleted-by deleted-by)))
|
||||
|
||||
(defn- should-and-able-to-unpin-to-be-deleted-message
|
||||
"check
|
||||
1. if the to-be deleted message is pinned
|
||||
2. if user has the permission to unpin message in current chat"
|
||||
[db {:keys [chat-id message-id]}]
|
||||
(let [{:keys [group-chat chat-id public? community-id admins]} (get-in db [:chats chat-id])
|
||||
community (get-in db [:communities community-id])
|
||||
community-admin? (get community :admin false)
|
||||
pub-key (get-in db [:multiaccount :public-key])
|
||||
group-admin? (get admins pub-key)
|
||||
message-pin-enabled (and (not public?)
|
||||
(or (not group-chat)
|
||||
(and group-chat
|
||||
(or group-admin?
|
||||
community-admin?))))
|
||||
pinned (get-in db
|
||||
[:pin-messages chat-id
|
||||
message-id])]
|
||||
(and pinned message-pin-enabled)))
|
||||
|
||||
(rf/defn delete
|
||||
"Delete message now locally and broadcast after undo time limit timeout"
|
||||
{:events [:chat.ui/delete-message]}
|
||||
@@ -56,14 +76,22 @@
|
||||
;; new delete operation will reset prev pending deletes' undo timelimit
|
||||
;; undo will undo all pending deletes
|
||||
;; all pending deletes are stored in toast
|
||||
(let [pub-key (get-in db [:multiaccount :public-key])
|
||||
(let [unpin? (should-and-able-to-unpin-to-be-deleted-message
|
||||
db
|
||||
{:chat-id chat-id :message-id message-id})
|
||||
|
||||
pub-key (get-in db [:multiaccount :public-key])
|
||||
|
||||
;; compute deleted by
|
||||
message-from (get message :from)
|
||||
deleted-by (when (not= pub-key message-from) pub-key)
|
||||
|
||||
existing-undo-toast (get-in db [:toasts :toasts :delete-message-for-everyone])
|
||||
toast-count (inc (get existing-undo-toast :message-deleted-for-everyone-count 0))
|
||||
existing-undos (-> existing-undo-toast
|
||||
(get :message-deleted-for-everyone-undos [])
|
||||
(conj {:message-id message-id :chat-id chat-id}))]
|
||||
existing-undos
|
||||
(-> existing-undo-toast
|
||||
(get :message-deleted-for-everyone-undos [])
|
||||
(conj {:message-id message-id :chat-id chat-id :should-pin-back? unpin?}))]
|
||||
(assoc
|
||||
(message-list/rebuild-message-list
|
||||
{:db (reduce
|
||||
@@ -89,7 +117,10 @@
|
||||
:undo-duration (/ undo-time-limit-ms 1000)
|
||||
:undo-on-press #(do (rf/dispatch [:chat.ui/undo-all-delete-message])
|
||||
(rf/dispatch [:toasts/close
|
||||
:delete-message-for-everyone]))}]]
|
||||
:delete-message-for-everyone]))}]
|
||||
(when unpin?
|
||||
[:pin-message/send-pin-message-locally
|
||||
{:chat-id chat-id :message-id message-id :pinned false}])]
|
||||
:utils/dispatch-later (mapv (fn [{:keys [chat-id message-id]}]
|
||||
{:dispatch [:chat.ui/delete-message-and-send
|
||||
{:chat-id chat-id :message-id message-id}]
|
||||
@@ -98,11 +129,16 @@
|
||||
|
||||
(rf/defn undo
|
||||
{:events [:chat.ui/undo-delete-message]}
|
||||
[{:keys [db]} {:keys [chat-id message-id]}]
|
||||
[{:keys [db]} {:keys [chat-id message-id should-pin-back?]}]
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
(message-list/rebuild-message-list
|
||||
{:db (update-db-undo-locally db chat-id message-id)}
|
||||
chat-id)))
|
||||
(let [effects (message-list/rebuild-message-list
|
||||
{:db (update-db-undo-locally db chat-id message-id)}
|
||||
chat-id)
|
||||
message (get-in effects [:db :messages chat-id message-id])]
|
||||
(cond-> effects
|
||||
should-pin-back?
|
||||
(assoc :dispatch
|
||||
[:pin-message/send-pin-message-locally (assoc message :pinned true)])))))
|
||||
|
||||
(rf/defn undo-all
|
||||
{:events [:chat.ui/undo-all-delete-message]}
|
||||
@@ -126,19 +162,32 @@
|
||||
[{:keys [db]} {:keys [message-id chat-id]} force?]
|
||||
(when-let [message (get-in db [:messages chat-id message-id])]
|
||||
(when (or force? (check-before-delete-and-send db chat-id message-id))
|
||||
(cond-> {:db (update-db-clear-undo-timer db chat-id message-id)
|
||||
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
|
||||
:params [message-id]
|
||||
:js-response true
|
||||
:on-error #(log/error "failed to delete message "
|
||||
{:message-id message-id :error %})
|
||||
:on-success #(rf/dispatch
|
||||
[:sanitize-messages-and-process-response
|
||||
%])}]}
|
||||
(get-in db [:pin-messages chat-id message-id])
|
||||
(assoc :dispatch
|
||||
[:pin-message/send-pin-message
|
||||
{:chat-id chat-id :message-id message-id :pinned false}])))))
|
||||
(let [unpin-locally?
|
||||
;; this only check against local client data
|
||||
;; generally msg is already unpinned at delete locally phase when user
|
||||
;; has unpin permission
|
||||
;;
|
||||
;; will be true only if
|
||||
;; 1. admin delete an unpinned msg
|
||||
;; 2. another admin pin the msg within the undo time limit
|
||||
;; 3. msg finally deleted
|
||||
(should-and-able-to-unpin-to-be-deleted-message db
|
||||
{:chat-id chat-id
|
||||
:message-id message-id})]
|
||||
{:db (update-db-clear-undo-timer db chat-id message-id)
|
||||
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
|
||||
:params [message-id]
|
||||
:js-response true
|
||||
:on-error #(log/error "failed to delete message "
|
||||
{:message-id message-id :error %})
|
||||
:on-success #(rf/dispatch
|
||||
[:sanitize-messages-and-process-response
|
||||
%])}]
|
||||
:dispatch [:pin-message/send-pin-message
|
||||
{:chat-id chat-id
|
||||
:message-id message-id
|
||||
:pinned false
|
||||
:remote-only? (not unpin-locally?)}]}))))
|
||||
|
||||
(defn- filter-pending-send-messages
|
||||
"traverse all messages find not yet synced deleted? messages"
|
||||
|
||||
@@ -1,46 +1,49 @@
|
||||
(ns status-im2.contexts.chat.messages.drawers.view
|
||||
(:require [react-native.core :as rn]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im2.config :as config]
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
|
||||
[status-im2.common.not-implemented :as not-implemented]))
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn pin-message
|
||||
[{:keys [chat-id pinned] :as message-data}]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned chat-id])]
|
||||
(if (and (not pinned) (> (count pinned-messages) 2))
|
||||
[{:keys [chat-id pinned pinned-by] :as message-data}]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned chat-id])
|
||||
message-not-pinned? (and (empty? pinned-by) (not pinned))]
|
||||
(if (and message-not-pinned? (> (count pinned-messages) 2))
|
||||
(do
|
||||
(js/setTimeout (fn [] (rf/dispatch [:dismiss-keyboard])) 500)
|
||||
(rf/dispatch [:pin-message/show-pin-limit-modal chat-id]))
|
||||
(rf/dispatch [:pin-message/send-pin-message (assoc message-data :pinned (not pinned))]))))
|
||||
(rf/dispatch [:pin-message/send-pin-message
|
||||
(assoc message-data :pinned message-not-pinned?)]))))
|
||||
|
||||
(defn get-actions
|
||||
[{:keys [outgoing content pinned outgoing-status] :as message-data}
|
||||
{:keys [edit-enabled show-input? can-delete-message-for-everyone? community? message-pin-enabled]}]
|
||||
[{:keys [outgoing content pinned outgoing-status deleted? deleted-for-me?] :as message-data}
|
||||
{:keys [edit-enabled show-input? community? can-delete-message-for-everyone?
|
||||
message-pin-enabled group-chat group-admin?]}]
|
||||
(concat
|
||||
(when (and outgoing edit-enabled)
|
||||
(when (and outgoing edit-enabled (not (or deleted? deleted-for-me?)))
|
||||
[{:type :main
|
||||
:on-press #(rf/dispatch [:chat.ui/edit-message message-data])
|
||||
:label (i18n/label :t/edit-message)
|
||||
:icon :i/edit
|
||||
:id :edit}])
|
||||
(when (and show-input? (not= outgoing-status :sending))
|
||||
(when (and show-input? (not= outgoing-status :sending) (not (or deleted? deleted-for-me?)))
|
||||
[{:type :main
|
||||
:on-press #(rf/dispatch [:chat.ui/reply-to-message message-data])
|
||||
:label (i18n/label :t/message-reply)
|
||||
:icon :i/reply
|
||||
:id :reply}])
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
:id :copy}]
|
||||
(when-not (or deleted? deleted-for-me?)
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
:id :copy}])
|
||||
(when message-pin-enabled
|
||||
[{:type :main
|
||||
:on-press #(pin-message message-data)
|
||||
@@ -49,7 +52,7 @@
|
||||
(if community? :t/pin-to-channel :t/pin-to-chat)))
|
||||
:icon :i/pin
|
||||
:id (if pinned :unpin :pin)}])
|
||||
(when-not pinned
|
||||
(when-not (or pinned deleted? deleted-for-me?)
|
||||
[{:type :danger
|
||||
:on-press (fn []
|
||||
(rf/dispatch
|
||||
@@ -60,7 +63,13 @@
|
||||
:label (i18n/label :t/delete-for-me)
|
||||
:icon :i/delete
|
||||
:id :delete-for-me}])
|
||||
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
|
||||
(when (cond
|
||||
deleted? false
|
||||
deleted-for-me? false
|
||||
outgoing true
|
||||
community? can-delete-message-for-everyone?
|
||||
group-chat group-admin?
|
||||
:else false)
|
||||
[{:type :danger
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
@@ -117,7 +126,8 @@
|
||||
icon]])))]))
|
||||
|
||||
(defn reactions-and-actions
|
||||
[{:keys [message-id outgoing-status] :as message-data} {:keys [chat-id] :as context}]
|
||||
[{:keys [message-id outgoing-status deleted? deleted-for-me?] :as message-data}
|
||||
{:keys [chat-id] :as context}]
|
||||
(fn []
|
||||
(let [actions (get-actions message-data context)
|
||||
main-actions (filter #(= (:type %) :main) actions)
|
||||
@@ -125,7 +135,7 @@
|
||||
admin-actions (filter #(= (:type %) :admin) actions)]
|
||||
[:<>
|
||||
;; REACTIONS
|
||||
(when (not= outgoing-status :sending)
|
||||
(when (and (not= outgoing-status :sending) (not (or deleted? deleted-for-me?)))
|
||||
[reactions {:chat-id chat-id :message-id message-id}])
|
||||
|
||||
;; MAIN ACTIONS
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
(ns status-im2.contexts.chat.messages.list.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[oops.core :as oops]
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[status-im.ui.screens.chat.group :as chat.group]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im.ui.screens.chat.group :as chat.group]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[status-im2.contexts.chat.messages.list.state :as state]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]))
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defonce messages-list-ref (atom nil))
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
(if platform/low-device? 700 200))))
|
||||
|
||||
(defn get-render-data
|
||||
"compute data used to render message list, including pinned message list and message list in chats"
|
||||
[{:keys [group-chat chat-id public? community-id admins space-keeper show-input? edit-enabled
|
||||
in-pinned-view?]}]
|
||||
(let [current-public-key (rf/sub [:multiaccount/public-key])
|
||||
@@ -82,6 +83,7 @@
|
||||
(or group-admin?
|
||||
community-admin?))))]
|
||||
{:group-chat group-chat
|
||||
:group-admin? group-admin?
|
||||
:public? public?
|
||||
:community? (not (nil? community-id))
|
||||
:current-public-key current-public-key
|
||||
@@ -123,7 +125,7 @@
|
||||
[message.gap/gap message-data]]
|
||||
[rn/view {:padding-horizontal 8}
|
||||
(if (or deleted? deleted-for-me?)
|
||||
[content.deleted/deleted-message message-data]
|
||||
[content.deleted/deleted-message message-data context]
|
||||
[message/message-with-reactions message-data context])]))])
|
||||
|
||||
(defn messages-list
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.banner.view
|
||||
(:require [quo2.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn banner
|
||||
[chat-id]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list chat-id])
|
||||
latest-pin-text (->> pinned-messages
|
||||
last
|
||||
:content
|
||||
:text)
|
||||
pins-count (count pinned-messages)]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list
|
||||
chat-id])
|
||||
latest-pinned-message (last pinned-messages)
|
||||
latest-pin-text (get-in latest-pinned-message [:content :text])
|
||||
{:keys [deleted? deleted-for-me?]} latest-pinned-message
|
||||
pins-count (count pinned-messages)
|
||||
|
||||
latest-pin-text
|
||||
(cond deleted? (i18n/label :t/message-deleted-for-everyone)
|
||||
deleted-for-me? (i18n/label :t/message-deleted-for-you)
|
||||
:else latest-pin-text)]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||
[status-im2.common.toasts.events :as toasts]
|
||||
[status-im2.constants :as constants]
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.data-store.pin-messages :as data-store.pin-messages]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[utils.re-frame :as rf]
|
||||
[taoensso.timbre :as log]))
|
||||
[status-im2.common.toasts.events :as toasts]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn handle-failed-loading-pin-messages
|
||||
{:events [:pin-message/failed-loading-pin-messages]}
|
||||
@@ -59,23 +59,34 @@
|
||||
(assoc-in [:pin-message-lists chat-id]
|
||||
(message-list/add-many nil (vals all-messages))))}))))
|
||||
|
||||
(rf/defn send-pin-message
|
||||
"Pin message, rebuild pinned messages list"
|
||||
{:events [:pin-message/send-pin-message]}
|
||||
|
||||
(rf/defn send-pin-message-locally
|
||||
"Pin message, rebuild pinned messages list locally"
|
||||
{:events [:pin-message/send-pin-message-locally]}
|
||||
[{:keys [db] :as cofx} {:keys [chat-id message-id pinned] :as pin-message}]
|
||||
(let [current-public-key (get-in db [:multiaccount :public-key])
|
||||
message (merge pin-message {:pinned-by current-public-key})
|
||||
preferred-name (get-in db [:multiaccount :preferred-name])]
|
||||
(let [current-public-key (get-in db [:multiaccount :public-key])
|
||||
message (merge pin-message {:pinned-by current-public-key})
|
||||
pin-message-lists-exist? (some? (get-in db [:pin-message-lists chat-id]))]
|
||||
(rf/merge cofx
|
||||
{:db (cond-> db
|
||||
pinned
|
||||
(->
|
||||
(update-in [:pin-message-lists chat-id] message-list/add message)
|
||||
(assoc-in [:pin-messages chat-id message-id] message))
|
||||
(not pinned)
|
||||
(and (not pinned) pin-message-lists-exist?)
|
||||
(->
|
||||
(update-in [:pin-message-lists chat-id] message-list/remove-message pin-message)
|
||||
(update-in [:pin-messages chat-id] dissoc message-id)))}
|
||||
(update-in [:pin-messages chat-id] dissoc message-id)))})))
|
||||
|
||||
(rf/defn send-pin-message
|
||||
"Pin message, rebuild pinned messages list"
|
||||
{:events [:pin-message/send-pin-message]}
|
||||
[{:keys [db] :as cofx} {:keys [chat-id message-id pinned remote-only?] :as pin-message}]
|
||||
(let [current-public-key (get-in db [:multiaccount :public-key])
|
||||
message (merge pin-message {:pinned-by current-public-key})
|
||||
preferred-name (get-in db [:multiaccount :preferred-name])]
|
||||
(rf/merge cofx
|
||||
(when-not remote-only? (send-pin-message-locally pin-message))
|
||||
(data-store.pin-messages/send-pin-message {:chat-id (pin-message :chat-id)
|
||||
:message_id (pin-message :message-id)
|
||||
:pinned (pin-message :pinned)})
|
||||
|
||||
@@ -1,37 +1,33 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.list.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.datetime :as datetime]))
|
||||
[status-im2.contexts.chat.messages.list.view :as list.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def list-key-fn #(or (:message-id %) (:value %)))
|
||||
|
||||
(defn message-render-fn
|
||||
[{:keys [whisper-timestamp] :as message}
|
||||
_
|
||||
{:keys [group-chat public? community? current-public-key show-input? edit-enabled]}]
|
||||
[{:keys [deleted? deleted-for-me?] :as message} _ _ context]
|
||||
;; TODO (flexsurfer) probably we don't want reactions here
|
||||
[message/message-with-reactions
|
||||
message
|
||||
{:group-chat group-chat
|
||||
:public? public?
|
||||
:community? community?
|
||||
:current-public-key current-public-key
|
||||
:show-input? show-input?
|
||||
:message-pin-enabled true
|
||||
:in-pinned-view? true
|
||||
:pinned true
|
||||
:timestamp-str (datetime/timestamp->time whisper-timestamp)
|
||||
:edit-enabled edit-enabled}])
|
||||
(if (or deleted? deleted-for-me?)
|
||||
[content.deleted/deleted-message message context]
|
||||
[message/message-with-reactions message context]))
|
||||
|
||||
(defn pinned-messages-list
|
||||
[chat-id]
|
||||
(let [pinned-messages (vec (vals (rf/sub [:chats/pinned chat-id])))
|
||||
current-chat (rf/sub [:chat-by-id chat-id])
|
||||
community (rf/sub [:communities/community (:community-id current-chat)])]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list
|
||||
chat-id])
|
||||
current-chat (rf/sub [:chat-by-id chat-id])
|
||||
|
||||
{:keys [group-chat chat-id public? community-id admins]}
|
||||
current-chat
|
||||
|
||||
community (rf/sub [:communities/community
|
||||
community-id])]
|
||||
[rn/view {:accessibility-label :pinned-messages-list}
|
||||
;; TODO (flexsurfer) this should be a component in quo2
|
||||
;; https://github.com/status-im/status-mobile/issues/14529
|
||||
@@ -62,10 +58,18 @@
|
||||
(str "# " (:chat-name current-chat))]])]
|
||||
(if (> (count pinned-messages) 0)
|
||||
[rn/flat-list
|
||||
{:data pinned-messages
|
||||
:render-fn message-render-fn
|
||||
:key-fn list-key-fn
|
||||
:separator quo/separator}]
|
||||
{:data pinned-messages
|
||||
:render-data (list.view/get-render-data {:group-chat group-chat
|
||||
:chat-id chat-id
|
||||
:public? public?
|
||||
:community-id community-id
|
||||
:show-input? false
|
||||
:admins admins
|
||||
:edit-enabled true
|
||||
:in-pinned-view? true})
|
||||
:render-fn message-render-fn
|
||||
:key-fn list-key-fn
|
||||
:separator quo/separator}]
|
||||
[rn/view
|
||||
{:style {:justify-content :center
|
||||
:align-items :center
|
||||
|
||||
@@ -77,18 +77,30 @@
|
||||
|
||||
(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]]))
|
||||
[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]])))
|
||||
(when (> @scroll-height 80)
|
||||
[rn/view
|
||||
{:style style/blur-tabs-header}
|
||||
[community-segments selected-tab padding-top]]))
|
||||
|
||||
(defn home-nav
|
||||
[]
|
||||
[common.home/top-nav
|
||||
{:type :default
|
||||
:hide-search true
|
||||
:style {:background-color :transparent}}])
|
||||
|
||||
(defn title-column
|
||||
[]
|
||||
[common.home/title-column
|
||||
{:label (i18n/label :t/communities)
|
||||
:handler #(rf/dispatch [:bottom-sheet/show-sheet :add-new {}])
|
||||
:accessibility-label :new-chat-button}])
|
||||
|
||||
(defn communities-screen-content
|
||||
[]
|
||||
@@ -98,16 +110,8 @@
|
||||
[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}])
|
||||
:top-nav [home-nav]
|
||||
:title-colum [title-column]
|
||||
:background-color (colors/theme-colors
|
||||
colors/white
|
||||
colors/neutral-95)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(ns status-im2.contexts.emoji-hash.events
|
||||
(:require [utils.re-frame :as rf]
|
||||
[status-im.native-module.core :as native-module]
|
||||
[utils.transforms :as transform]))
|
||||
|
||||
(defn fetch-for-current-public-key
|
||||
[]
|
||||
(let [public-key (rf/sub [:multiaccount/public-key])]
|
||||
(native-module/public-key->emoji-hash
|
||||
public-key
|
||||
(fn [response]
|
||||
(let [response-clj (transform/json->clj response)
|
||||
emoji-hash (get response-clj :result)]
|
||||
(rf/dispatch [:emoji-hash/add-to-multiaccount emoji-hash]))))))
|
||||
|
||||
(rf/defn add-emoji-hash-to-multiaccount
|
||||
{:events [:emoji-hash/add-to-multiaccount]}
|
||||
[{:keys [db]} emoji-hash]
|
||||
{:db (assoc db :multiaccount/emoji-hash emoji-hash)})
|
||||
@@ -0,0 +1,74 @@
|
||||
(ns status-im2.contexts.quo-preview.drawers.drawer-buttons
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Top Heading"
|
||||
:key :top-heading
|
||||
:type :text}
|
||||
{:label "Top Sub heading"
|
||||
:key :top-sub-heading
|
||||
:type :text}
|
||||
{:label "Bottom heading"
|
||||
:key :bottom-heading
|
||||
:type :text}])
|
||||
|
||||
(defn text-with-link
|
||||
[]
|
||||
[quo/text
|
||||
{:style {:flex 1
|
||||
:flex-wrap :wrap}}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:flex 1
|
||||
:color (colors/alpha colors/white 0.7)}
|
||||
:weight :semi-bold}
|
||||
"By continuing you accept our "]
|
||||
[quo/text
|
||||
{:on-press #(js/alert "Terms of use clicked")
|
||||
:size :paragraph-2
|
||||
:style {:flex 1
|
||||
:color colors/white}
|
||||
:weight :semi-bold}
|
||||
"Terms of Use"]])
|
||||
|
||||
(defn render-drawer-buttons
|
||||
[state]
|
||||
[rn/view
|
||||
{:height 300
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95)}
|
||||
[quo/drawer-buttons
|
||||
{:container-style {:margin-left 40
|
||||
:margin-right 24}
|
||||
:top-card {:on-press #(js/alert "top card clicked")
|
||||
:heading (:top-heading @state)}
|
||||
:bottom-card {:on-press #(js/alert "bottom card clicked")
|
||||
:heading (:bottom-heading @state)}}
|
||||
(:top-sub-heading @state) [text-with-link]]])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:top-heading "Sign in "
|
||||
:top-sub-heading "You already use Status"
|
||||
:bottom-heading "I'm new to status"})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 400}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:padding-vertical 60}
|
||||
[render-drawer-buttons state]]]])))
|
||||
|
||||
(defn preview-drawer-buttons
|
||||
[]
|
||||
[rn/view
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-95)
|
||||
:flex 1}
|
||||
[rn/flat-list
|
||||
{:flex 1
|
||||
:nestedScrollEnabled true
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:key-fn :id}]])
|
||||
@@ -8,6 +8,7 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im2.contexts.quo-preview.animated-header-list.animated-header-list :as animated-header-list]
|
||||
[status-im2.contexts.quo-preview.avatars.account-avatar :as account-avatar]
|
||||
[status-im2.contexts.quo-preview.avatars.channel-avatar :as channel-avatar]
|
||||
[status-im2.contexts.quo-preview.avatars.group-avatar :as group-avatar]
|
||||
@@ -28,7 +29,8 @@
|
||||
[status-im2.contexts.quo-preview.dividers.date :as divider-date]
|
||||
[status-im2.contexts.quo-preview.dividers.divider-label :as divider-label]
|
||||
[status-im2.contexts.quo-preview.dividers.new-messages :as new-messages]
|
||||
[status-im2.contexts.quo-preview.drawers.action-drawers :as drawers]
|
||||
[status-im2.contexts.quo-preview.drawers.action-drawers :as action-drawers]
|
||||
[status-im2.contexts.quo-preview.drawers.drawer-buttons :as drawer-buttons]
|
||||
[status-im2.contexts.quo-preview.drawers.permission-drawers :as permission-drawers]
|
||||
[status-im2.contexts.quo-preview.dropdowns.dropdown :as dropdown]
|
||||
[status-im2.contexts.quo-preview.foundations.shadows :as shadows]
|
||||
@@ -46,6 +48,7 @@
|
||||
[status-im2.contexts.quo-preview.navigation.top-nav :as top-nav]
|
||||
[status-im2.contexts.quo-preview.notifications.activity-logs :as activity-logs]
|
||||
[status-im2.contexts.quo-preview.notifications.toast :as toast]
|
||||
[status-im2.contexts.quo-preview.onboarding.small-option-card :as small-option-card]
|
||||
[status-im2.contexts.quo-preview.posts-and-attachments.messages-skeleton :as messages-skeleton]
|
||||
[status-im2.contexts.quo-preview.profile.collectible :as collectible]
|
||||
[status-im2.contexts.quo-preview.profile.profile-card :as profile-card]
|
||||
@@ -68,8 +71,7 @@
|
||||
[status-im2.contexts.quo-preview.wallet.lowest-price :as lowest-price]
|
||||
[status-im2.contexts.quo-preview.wallet.network-amount :as network-amount]
|
||||
[status-im2.contexts.quo-preview.wallet.network-breakdown :as network-breakdown]
|
||||
[status-im2.contexts.quo-preview.wallet.token-overview :as token-overview]
|
||||
[status-im2.contexts.quo-preview.animated-header-list.animated-header-list :as animated-header-list]))
|
||||
[status-im2.contexts.quo-preview.wallet.token-overview :as token-overview]))
|
||||
|
||||
(def screens-categories
|
||||
{:foundations [{:name :shadows
|
||||
@@ -137,7 +139,10 @@
|
||||
:component divider-date/preview-divider-date}]
|
||||
:drawers [{:name :action-drawers
|
||||
:insets {:top false}
|
||||
:component drawers/preview-action-drawers}
|
||||
:component action-drawers/preview-action-drawers}
|
||||
{:name :drawer-buttons
|
||||
:insets {:top false}
|
||||
:component drawer-buttons/preview-drawer-buttons}
|
||||
{:name :permission-drawers
|
||||
:insets {:top false}
|
||||
:component permission-drawers/preview-permission-drawers}]
|
||||
@@ -186,6 +191,9 @@
|
||||
{:name :toast
|
||||
:insets {:top false}
|
||||
:component toast/preview-toasts}]
|
||||
:onboarding [{:name :small-option-card
|
||||
:insets {:top false}
|
||||
:component small-option-card/preview-small-option-card}]
|
||||
:posts-and-attachments [{:name :messages-skeleton
|
||||
:insets {:top false}
|
||||
:component messages-skeleton/preview-messages-skeleton}]
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
(ns status-im2.contexts.quo-preview.onboarding.small-option-card
|
||||
(:require
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.onboarding.small-option-card.view :as quo2]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Variant"
|
||||
:key :variant
|
||||
:type :select
|
||||
:options [{:key :main
|
||||
:value "Main"}
|
||||
{:key :icon
|
||||
:value "Icon"}]}
|
||||
{:label "Image"
|
||||
:key :image
|
||||
:type :select
|
||||
:options [{:key (resources/get-mock-image :small-opt-card-main)
|
||||
:value "Image 1"}
|
||||
{:key (resources/get-mock-image :small-opt-card-icon)
|
||||
:value "Image 2"}]}
|
||||
{:label "Title"
|
||||
:key :title
|
||||
:type :text}
|
||||
{:label "Subtitle"
|
||||
:key :subtitle
|
||||
:type :text}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:variant :main
|
||||
:image (-> descriptor second :options first :key)
|
||||
:title "Generate keys "
|
||||
:subtitle "Your new self-sovereign identity in Status"
|
||||
:on-press #(js/alert "Small option card pressed!")})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:style {:padding-bottom 150}}
|
||||
[rn/view {:style {:flex 1}}
|
||||
[preview/customizer state descriptor]]
|
||||
[rn/view
|
||||
{:style {:background-color colors/neutral-80
|
||||
:padding 20}}
|
||||
[quo2/small-option-card @state]]]])))
|
||||
|
||||
(defn preview-small-option-card
|
||||
[]
|
||||
[rn/view
|
||||
{:style {:background-color (colors/theme-colors colors/white colors/neutral-90)
|
||||
:flex 1}}
|
||||
[rn/flat-list
|
||||
{:flex 1
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:key-fn str}]])
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns status-im2.subs.chat.messages
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im2.contexts.chat.messages.list.events :as models.message-list]
|
||||
[status-im.chat.models.reactions :as models.reactions]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im2.constants :as constants]))
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.list.events :as models.message-list]
|
||||
[utils.datetime :as datetime]))
|
||||
|
||||
(defn intersperse-datemark
|
||||
"Reduce step which expects the input list of messages to be sorted by clock value.
|
||||
@@ -24,7 +24,7 @@
|
||||
:acc (conj acc msg)}
|
||||
|
||||
(and (not= last-datemark datemark) ; not the same day
|
||||
(< whisper-timestamp last-timestamp)) ; not out-of-order
|
||||
(< whisper-timestamp last-timestamp)) ; not out-of-order
|
||||
{:last-timestamp whisper-timestamp
|
||||
:last-datemark datemark
|
||||
:acc (conj acc
|
||||
@@ -32,7 +32,7 @@
|
||||
:type :datemark}
|
||||
msg)}
|
||||
:else
|
||||
{:last-timestamp (min whisper-timestamp last-timestamp) ; use last datemark
|
||||
{:last-timestamp (min whisper-timestamp last-timestamp) ; use last datemark
|
||||
:last-datemark last-datemark
|
||||
:acc (conj acc (assoc msg :datemark last-datemark))}))
|
||||
|
||||
@@ -158,14 +158,18 @@
|
||||
[(re-frame/subscribe [:messages/pin-messages])
|
||||
(re-frame/subscribe [:chats/chat-messages chat-id])])
|
||||
(fn [[pin-messages messages] [_ chat-id]]
|
||||
(let [pin-messages (get pin-messages chat-id {})]
|
||||
(reduce-kv (fn [acc message-id message]
|
||||
(let [{:keys [deleted? deleted-for-me?]} (get messages message-id)]
|
||||
(if (or deleted? deleted-for-me?)
|
||||
acc
|
||||
(assoc acc message-id message))))
|
||||
{}
|
||||
pin-messages))))
|
||||
(let [pinned-messages (get pin-messages chat-id {})]
|
||||
(reduce-kv
|
||||
(fn [pinned-messages pinned-message-id pinned-message]
|
||||
(let [{:keys [deleted? deleted-for-me? deleted-by]} (get messages pinned-message-id)
|
||||
pinned-message (assoc pinned-message
|
||||
:deleted? deleted?
|
||||
:deleted-for-me? deleted-for-me?
|
||||
:deleted-by deleted-by
|
||||
:pinned true)]
|
||||
(assoc pinned-messages pinned-message-id pinned-message)))
|
||||
pinned-messages
|
||||
pinned-messages))))
|
||||
|
||||
;; local messages will not have a :pinned-at key until user navigates away and to
|
||||
;; chat screen. For this reason we want to retain order of local messages with :pinned-at nil
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns status-im2.subs.chat.messages-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.subs.chat.messages :as messages]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.db :as rf-db]
|
||||
[status-im2.constants :as constants]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def messages-state
|
||||
[{:message-id "0x111" :album-id "abc" :albumize? true}
|
||||
@@ -109,51 +109,91 @@
|
||||
[sub-name]
|
||||
(testing "It sorts three messages with pinned-at property"
|
||||
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state)
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 1000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user}]
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 1000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}]
|
||||
(rf/sub [sub-name :0xChat]))))
|
||||
(testing "It sorts messages from backend with pinned-at property and 1 new local pinned message"
|
||||
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-1-new-local-message)
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user}]
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}]
|
||||
(rf/sub [sub-name :0xChat]))))
|
||||
(testing "It sorts messages from backend with pinned-at property and 2 new local pinned messages"
|
||||
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-2-new-local-messages)
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x4
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user}]
|
||||
(rf/sub [sub-name :0xChat])))))
|
||||
|
||||
(is
|
||||
(= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x4
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}]
|
||||
(rf/sub [sub-name :0xChat])))))
|
||||
|
||||
@@ -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}]}])
|
||||
|
||||
|
||||
@@ -45,3 +45,5 @@
|
||||
(defn advance-timers-by-time
|
||||
[time-ms]
|
||||
(js/jest.advanceTimersByTime time-ms))
|
||||
|
||||
(def mock-fn js/jest.fn)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.130.0",
|
||||
"commit-sha1": "dea21f440a9f630c4b8324fcde0b016d6c3fc02b",
|
||||
"src-sha256": "1w9iyigj0rkqfnyb8m9w802r1lx1cydg41p8qb7hnsry2bgrfk97"
|
||||
"version": "v0.131.7",
|
||||
"commit-sha1": "97579ee36393955705e51f364fce3ab40d1d6921",
|
||||
"src-sha256": "0b15kv6f1f1935lljl4bmvmndsr5smb9kxazx0fxz6xfsyjd1x5i"
|
||||
}
|
||||
|
||||
@@ -108,9 +108,9 @@ class BaseTestReport:
|
||||
return url
|
||||
|
||||
@staticmethod
|
||||
def get_jenkins_link_to_rerun_e2e(branch_name="develop", pr_id="", apk_name="", tr_case_ids=""):
|
||||
def get_jenkins_link_to_rerun_e2e(branch_name="develop", pr_id="", tr_case_ids=""):
|
||||
return 'https://ci.status.im/job/status-mobile/job/e2e/job/status-app-prs-rerun/parambuild/' \
|
||||
'?BRANCH_NAME=%s&APK_NAME=%s&PR_ID=%s&TR_CASE_IDS=%s' % (branch_name, apk_name, pr_id, tr_case_ids)
|
||||
'?BRANCH_NAME=%s&PR_ID=%s&TR_CASE_IDS=%s' % (branch_name, pr_id, tr_case_ids)
|
||||
|
||||
def get_sauce_final_screenshot_url(self, job_id):
|
||||
return 'https://media.giphy.com/media/9M5jK4GXmD5o1irGrF/giphy.gif'
|
||||
|
||||
@@ -71,13 +71,11 @@ class GithubHtmlReport(BaseTestReport):
|
||||
if not_executed_tests:
|
||||
html += "<li><a href=\"%s\">Rerun not executed tests</a></li>" % self.get_jenkins_link_to_rerun_e2e(
|
||||
pr_id=pr_id,
|
||||
apk_name=apk_name,
|
||||
tr_case_ids=','.join([str(i) for i in tests]))
|
||||
|
||||
if failed_tests:
|
||||
html += "<li><a href=\"%s\">Rerun failed tests</a></li>" % self.get_jenkins_link_to_rerun_e2e(
|
||||
pr_id=pr_id,
|
||||
apk_name=apk_name,
|
||||
tr_case_ids=','.join([str(test.testrail_case_id) for test in tests]))
|
||||
|
||||
if not not_executed_tests:
|
||||
|
||||
@@ -12,7 +12,7 @@ module.exports = {
|
||||
},
|
||||
"testTimeout": 60000,
|
||||
"transformIgnorePatterns": [
|
||||
"/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions)/).*/"
|
||||
"/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions|@react-native-community/blur)/).*/"
|
||||
],
|
||||
"globals": {
|
||||
"__TEST__": true
|
||||
|
||||
Reference in New Issue
Block a user