Compare commits

..
Author SHA1 Message Date
Volodymyr Kozieiev 6239ab7b9d Added component desciription 2023-08-29 16:04:32 +01:00
Volodymyr Kozieiev b84cc6c54e Wallet activity component 2023-08-25 13:40:43 +01:00
Ulises M bc168cb94e Add issue for wroing text style 2023-08-14 16:49:54 -06:00
Ulises M 294913c05b Add issue for multinetwork variant 2023-08-14 16:30:18 -06:00
Ulises M 1b42c9d58e Update use of group-avatar api 2023-08-14 13:52:33 -06:00
Ulises M 3c6e6e19c7 Fix code style 2023-08-14 12:49:30 -06:00
Ulises M e7b8f188e1 add map style argument to style/container 2023-08-14 12:47:27 -06:00
Ulises M b8d51a404e Remove unused require 2023-08-14 12:45:04 -06:00
Ulises M 027f35906b Lint fix 2023-08-14 12:44:06 -06:00
Ulises M d513690290 Remove theme/provider alias 2023-08-14 12:44:06 -06:00
Ulises M 7101be0dac Rename alias 2023-08-14 12:44:05 -06:00
Ulises M 7d12f75977 remove nil nil params 2023-08-14 12:44:05 -06:00
Ulises M 35b2cc582d Updates context-tag previous uses 2023-08-14 12:44:04 -06:00
Ulises M ca648e7153 Add missing context-tags variants and fix the API to match figma 2023-08-14 12:36:15 -06:00
Ulises M e12a0d1596 Add size 20 for preview-list 2023-08-14 12:36:15 -06:00
Ulises M 7a8c0ab724 Add icon-name to group avatar 2023-08-14 12:35:54 -06:00
Ulises M 8f9d78d359 Add size 28 for user-avatar 2023-08-14 12:32:55 -06:00
170 changed files with 3105 additions and 3287 deletions
+5 -5
View File
@@ -95,11 +95,11 @@ status-im.hardwallet.simulated-keycard/sign-typed-data
status-im.utils.core/safe-read-message-content
status-im.ui.components.react/native-modules
status-im.ui.components.react/progress-bar
react-native.fs/move-file
react-native.fs/read-dir
react-native.fs/mkdir
react-native.fs/unlink
react-native.fs/file-exists?
status-im.utils.fs/move-file
status-im.utils.fs/read-dir
status-im.utils.fs/mkdir
status-im.utils.fs/unlink
status-im.utils.fs/file-exists?
quo.animated/code
quo.animated/eq
quo.animated/neq
+5 -3
View File
@@ -16,7 +16,7 @@ The responsibilities of the team are to implement the new wallet UI, with the su
## Decision
The team members for the initial wallet team are:
Some team members have already expressed interest and some have been asked and accepted to join the wallet team, these team members are:
- @rasom
- @OmarBasem
@@ -25,5 +25,7 @@ The team members for the initial wallet team are:
- @briansztamfater
- @smohamedjavid
- @ulisesmac
- @erikseppanen
- @mmilad75
# Follow-up Actions
- We still need 3/4 team members to join the wallet team
+1 -1
View File
@@ -33,7 +33,7 @@ The people identified for each sections are as follow:
- Messaging @flexsurfer, followed by @alwx
- Syncing & Onboarding @siddarthkay
- Communities @ilmotta, followed by @ajayesivan
- Communities @ilmotta
- Activity Center & Shell @J-Son89, followed by @Parveshdhull
- Wallet (once the vertical team is created) @J-Son89, followed by @briansztamfater
+16 -27
View File
@@ -30,7 +30,7 @@ Ready for testing PR should meet the following criteria:
3. Wait for the review.
4. Make sure that after review and before requesting manual QA your PR is rebased to current develop.
5. Once the PR has been approved by reviewer(s) - label `request-manual-qa` should be applied to the PR
6. Move PR to the E2E column when it is ready for testing (**mandatory for all PRs**). That will also trigger e2e tests run. QAs are monitoring PRs from E2E column and take it into test.
6. Move PR to the E2E column when it is ready for testing. That will also trigger e2e tests run. QAs are monitoring PRs from E2E column and take it into test.
After that - PR will be taken into manual testing by the QA team.
@@ -41,37 +41,27 @@ After that - PR will be taken into manual testing by the QA team.
- QA engineer picks up one of PRs with the ```request-manual-qa``` label, drags the item to the ```IN TESTING``` column and assigns it to themselves.
- During testing, QA will add comments describing the issues found, and also review automation tests results.
Usually found issues are numbered as "Issue 1, Issue 2", etc.
When the first round of testing is completed and all issues for this stage are found, the QA can add the ```Tested - Issues``` label and drag the card to the ```CONTRIBUTOR``` column. These two actions are optional.
- When manual testing of the PR is fully completed and all the issues are fixed, the QA adds the ```Tested - OK``` label and drags the card to the ```Design review``` column (the cases when design review is necessary are described below).
- If design review is not required, the QA drags the PR to the ```MERGE``` column. After that the developer merges PR into develop.
- If design review has been done, the designer (```@Francesca-G```) drags the PR to the ```MERGE``` column.
After that the developer merges PR into develop.
- If manual testing/design review was not carried out, the developer drags PR to the ```MERGE``` column themselves.
### Design review
_**How do I know if a design review is needed?**_
There are three cases here depending on the changes in the PR:
1. **Functional PRs with UI changes:** after the ```Tested - OK``` label is added, the QA moves the PR to the ```Design review``` column + mentions ```@Francesca-G``` in comments.
2. **Component PRs:** can be moved directly to the ```Design review``` column by the developer when get a review from devs (manual testing step can be skipped) + the developer mentions ```@Francesca-G``` in comments.
3. **Functional PRs changes in which are not related to UI (e.g. a crash fix):** skip the ```Design review``` step (the PR should only be manually tested by QA).
There are three possible scenarios when the design review is completed:
1. **Approved by design** > the PR is moved to the ```MERGE``` column by Francesca
2. **Some changes requested, but can be fixed as followups** > need to be negotiated with Francesca > Francesca moves PR to the ```MERGE``` column and adds the ```Follow-up required``` label > follow-ups should be added **by the dev** right after the PR is merged
3. **Some changes requested, they should be fixed before merge** > Francesca reviews the PR again after the fixes and moves PR to the ```MERGE``` column from ```Design review```
---
**Notes:**
- If your PR has a long story and started from `develop` branch several days ago, please rebase it to current develop before adding label
- if PR can be tested by developer (in case of small changes) and/or developer is sure that the changes made cannot introduce a regression, then PR can be merged without manual testing. Also, currently, PRs are not manually tested if the changes relate only the design (creation of components, etc.) and do not affect the functionality.
---
When the first round of testing is completed and all issues for this stage are found, tester can add the ```Tested - Issues``` label and drag the card to the ```CONTRIBUTOR``` column. These two actions are optional.
- When manual testing of PR is fully completed and all issues are fixed, QA adds the ```Tested - OK``` label and drags the card to the ```MERGE``` column, after which developer merges PR into develop.
If manual testing was not carried out, developer drags PR to the ```MERGE``` column themselves.
**Notes:**
- If your PR has a long story and started from `develop` branch several days ago, please rebase it to current develop before adding label
- if PR can be tested by developer (in case of small changes) and/or developer is sure that the changes made cannot introduce a regression, then PR can be merged without manual testing. Also, currently, PRs are not manually tested if the changes relate only the design (creation of components, etc.) and do not affect the functionality.
#### Why my PR is in `Contributor` column?
PR can be moved to this column by the ```status-github-bot``` or by QA engineer with label `Tested-issues`.
In the first case most often this happens due to conflicting files in PR.
In the second case - after fixing of all found issues, the developer should ping the QA in the PR comments for retesting.
#### Why is my PR in `To Rebase` column?
PR is moved to the "To Rebase" column in two cases:
- automatically by github bot if PR branch has conflicts that should be resolved
- manually (by QAs) if PR branch is out-of-date with the base branch and requires rebasing to the latest develop
If PR appeared in the "To Rebase" column dev who is working on the PR should resolve conflicts/rebase branch to the latest develop. After resolving conflicts/rebasing PR should be moved by developer to the right column depending on PR work progress.
## Merging a PR
**Merge conditions:**
1. Required number of reviews received
@@ -83,7 +73,6 @@ In the second case - after fixing of all found issues, the developer should ping
6. In case of manual testing - the label ```Tested - OK``` from QA
7. In case of design review - the approval from the designer
You can merge your PR into develop - some useful clues you can find [here](https://notes.status.im/setup-e2e#3-Merging-PR)
+2 -2
View File
@@ -66,13 +66,13 @@
"react-native-randombytes": "^3.6.1",
"react-native-reanimated": "2.11.0",
"react-native-redash": "^16.0.11",
"react-native-svg": "13.10.0",
"react-native-shake": "^3.3.1",
"react-native-share": "^8.2.2",
"react-native-static-safe-area-insets": "^2.2.0",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39",
"react-native-svg": "13.10.0",
"react-native-touch-id": "^4.4.1",
"react-native-transparent-video": "git+https://github.com/status-im/react-native-transparent-video.git#refs/tags/0.1.1",
"react-native-transparent-video": "git+https://github.com/status-im/react-native-transparent-video.git#refs/tags/0.0.9",
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",
"react-syntax-highlighter": "^15.5.0",
"rn-emoji-keyboard": "0.7.0",
Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

+18 -21
View File
@@ -10,14 +10,14 @@
;; (-> reanimated/slide-out-up-animation (.damping 20) .springify (.stiffness 300))
(js/eval
"
var globalThis
if (typeof window === \"undefined\") {
globalThis = global
} else {
globalThis = window
}
globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return () => globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__}})
")
var globalThis
if (typeof window === \"undefined\") {
globalThis = global
} else {
globalThis = window
}
globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return () => globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__}})
")
(def action-button #js {:default #js {:Item #js {}}})
(def config #js {:default #js {}})
@@ -90,8 +90,7 @@
:configureNext (fn [])}
:requireNativeComponent (fn [] {:propTypes ""})
:Appearance {:getColorScheme (fn [])
:addChangeListener (fn [])}
:PixelRatio {:get (fn [])}}))
:addChangeListener (fn [])}}))
(set! js/ReactNative react-native)
@@ -139,17 +138,15 @@
(def react-native-share #js {:default {}})
(def react-native-svg
#js
{:ClipPath #js {:render identity}
:Circle #js {:render identity}
:Defs #js {:render identity}
:G #js {:render identity}
:Path #js {:render identity}
:Rect #js {:render identity}
:SvgUri #js {:render identity}
:SvgXml #js {:render identity}
:LinearGradient #js {:render identity}
:Stop #js {:render identity}
:default #js {:render identity}})
{:ClipPath #js {:render identity}
:Circle #js {:render identity}
:Defs #js {:render identity}
:G #js {:render identity}
:Path #js {:render identity}
:Rect #js {:render identity}
:SvgUri #js {:render identity}
:SvgXml #js {:render identity}
:default #js {:render identity}})
(def react-native-webview #js {:default {}})
(def react-native-audio-toolkit
#js
@@ -3,12 +3,12 @@
(defn container
[{:keys [container-size customization-color theme]}]
{:width container-size
:height container-size
:align-items :center
:justify-content :center
:border-radius (/ container-size 2)
:overflow :hidden
:background-color (colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)})
{:width container-size
:height container-size
:align-items :center
:justify-content :center
:border-radius (/ container-size 2)
:background-color
(colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)})
@@ -1,30 +1,32 @@
(ns quo2.components.avatars.group-avatar.view
(:require [quo2.components.icon :as icon]
[quo2.theme :as theme]
[quo2.theme :as quo.theme]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
[quo2.components.avatars.group-avatar.style :as style]))
(def sizes
{:size/s-20 {:icon 12
:container 20}
:size/s-28 {:icon 16
:container 28}
:size/s-32 {:icon 16
:container 32}
:size/s-48 {:icon 20
:container 48}
:size/s-80 {:icon 32
:container 80}})
{:icon {:x-small 12
:small 16
:medium 16
:large 20
:x-large 32}
:container {:x-small 20
:small 28
:medium 32
:large 48
:x-large 80}})
(defn- view-internal
[_]
(fn [{:keys [size theme customization-color picture]
:or {size :size/s-20
customization-color :blue}}]
(let [container-size (get-in sizes [size :container])
icon-size (get-in sizes [size :icon])]
(fn [{:keys [size theme customization-color picture icon-name]
:or {size :x-small
customization-color :blue
picture nil
icon-name :i/group}}]
(let [container-size (get-in sizes [:container size])
icon-size (get-in sizes [:icon size])]
[rn/view
{:style (style/container {:container-size container-size
:customization-color customization-color
@@ -34,8 +36,8 @@
{:source picture
:style {:width container-size
:height container-size}}]
[icon/icon :i/members
[icon/icon icon-name
{:size icon-size
:color colors/white-opa-70}])])))
(def view (theme/with-theme view-internal))
(def view (quo.theme/with-theme view-internal))
+2 -7
View File
@@ -1,7 +1,6 @@
(ns quo2.components.avatars.icon-avatar
(:require [quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]))
(def sizes
@@ -9,8 +8,8 @@
:medium 32
:small 20})
(defn icon-avatar-internal
[{:keys [size icon color opacity border? theme]
(defn icon-avatar
[{:keys [size icon color opacity]
:or {opacity 20}}]
(let [component-size (size sizes)
circle-color (colors/custom-color color 50 opacity)
@@ -23,13 +22,9 @@
{:style {:width component-size
:height component-size
:border-radius component-size
:border-width (when border? 1)
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:background-color circle-color
:justify-content :center
:align-items :center}}
[icons/icon icon
{:size icon-size
:color icon-color}]]))
(def icon-avatar (quo.theme/with-theme icon-avatar-internal))
@@ -2,9 +2,14 @@
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[test-helpers.component :as h]))
(defonce mock-picture {:uri (js/require "../resources/images/mock2/user_picture_male4.png")})
(defonce mock-picture (js/require "../resources/images/mock2/user_picture_male4.png"))
(h/describe "user avatar"
(h/test "Default render"
(h/render [user-avatar/user-avatar])
(h/is-truthy (h/get-by-label-text :user-avatar))
(h/is-truthy (h/get-by-text "EN")))
(h/describe "Profile picture"
(h/test "Renders"
(h/render
@@ -13,5 +18,124 @@
(h/test "Renders even if `:full-name` is passed"
(h/render
[user-avatar/user-avatar {:profile-picture mock-picture}])
(h/is-truthy (h/get-by-label-text :profile-picture)))))
[user-avatar/user-avatar
{:profile-picture mock-picture
:full-name "New User1"}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-null (h/query-by-label-text :initials-avatar)))
(h/describe "Status indicator"
(h/test "Render"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:status-indicator? true}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-truthy (h/get-by-label-text :status-indicator)))
(h/test "Do not render"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:status-indicator? false}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-null (h/query-by-label-text :status-indicator)))))
(h/describe "Initials Avatar"
(h/describe "Render initials"
(letfn [(user-avatar-component [size]
[user-avatar/user-avatar
{:full-name "New User"
:size size}])]
(h/describe "Two letters"
(h/test "Size :big"
(h/render (user-avatar-component :big))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Two letters with excess whitespace"
(h/render [user-avatar/user-avatar
{:full-name "New User"
:size :big}])
(h/is-truthy (h/get-by-text "NU")))
(h/test "Two letters with leading whitespace"
(h/render [user-avatar/user-avatar
{:full-name " New User"
:size :big}])
(h/is-truthy (h/get-by-text "NU"))))
(h/describe "One letter"
(h/test "Size :xs"
(h/render (user-avatar-component :xs))
(h/is-truthy (h/get-by-text "N")))
(h/test "Size :xxs"
(h/render (user-avatar-component :xxs))
(h/is-truthy (h/get-by-text "N")))
(h/test "Size :xxxs"
(h/render (user-avatar-component :xxxs))
(h/is-truthy (h/get-by-text "N"))))))
(h/describe "Render ring"
(letfn [(user-avatar-component [size]
[user-avatar/user-avatar
{:full-name "New User"
:ring-background mock-picture
:size size}])]
(h/describe "Passed and drawn"
(h/test "Size :big"
(h/render (user-avatar-component :big))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-truthy (h/get-by-label-text :ring-background)))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-truthy (h/get-by-label-text :ring-background)))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-truthy (h/get-by-label-text :ring-background))))
(h/describe "Passed and not drawn (because of invalid size for ring)"
(h/test "Size :xs"
(h/render (user-avatar-component :xs))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-null (h/query-by-label-text :ring-background)))
(h/test "Size :xxs"
(h/render (user-avatar-component :xxs))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-null (h/query-by-label-text :ring-background)))
(h/test "Size :xxxs"
(h/render (user-avatar-component :xxxs))
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-null (h/query-by-label-text :ring-background))))))
(h/describe "Status indicator"
(h/test "Render"
(h/render
[user-avatar/user-avatar
{:full-name "Test User"
:status-indicator? true}])
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-truthy (h/get-by-label-text :status-indicator)))
(h/test "Do not render"
(h/render
[user-avatar/user-avatar
{:full-name "Test User"
:status-indicator? false}])
(h/is-truthy (h/get-by-label-text :initials-avatar))
(h/is-null (h/query-by-label-text :status-indicator))))))
@@ -2,61 +2,97 @@
(:require [quo2.foundations.colors :as colors]))
(def sizes
{:big {:dimensions 80
{:big {:outer 80
:inner 72
:status-indicator 20
:status-indicator-border 4
:font-size :heading-1}
:medium {:dimensions 48
:medium {:outer 48
:inner 44
:status-indicator 12
:status-indicator-border 2
:font-size :heading-2}
:small {:dimensions 32
:small {:outer 32
:inner 28
:status-indicator 12
:status-indicator-border 2
:font-size :paragraph-2}
:xs {:dimensions 24
28 {:outer 28
:inner 28
:status-indicator 0
:status-indicator-border 0
:font-size :paragraph-2}
:xxs {:dimensions 20
:xs {:outer 24
:inner 24
:status-indicator 0
:status-indicator-border 0
:font-size :paragraph-2}
:xxs {:outer 20
:inner 20
:status-indicator 0
:status-indicator-border 0
:font-size :label}
:xxxs {:dimensions 16
:xxxs {:outer 16
:inner 16
:status-indicator 0
:status-indicator-border 0
:font-size :label}})
(defn outer
[size]
(let [dimensions (get-in sizes [size :outer])]
{:width dimensions
:height dimensions
:border-radius dimensions}))
(defn initials-avatar
[size customization-color theme]
(let [dimensions (get-in sizes [size :dimensions])]
[size draw-ring? customization-color theme]
(let [outer-dimensions (get-in sizes [size :outer])
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
{:position :absolute
:top 0
:left 0
:width dimensions
:height dimensions
:border-radius dimensions
:top (/ (- outer-dimensions inner-dimensions) 2)
:left (/ (- outer-dimensions inner-dimensions) 2)
:width inner-dimensions
:height inner-dimensions
:border-radius inner-dimensions
:justify-content :center
:align-items :center
:background-color (colors/custom-color-by-theme customization-color 50 60 nil nil theme)}))
(def indicator-color
{:online colors/success-50
:offline colors/neutral-40})
(defn outer
[size static-profile-picture?]
(let [dimensions (get-in sizes [size :dimensions])
outer-style {:width dimensions
:height dimensions}
outer-style-with-border-radius (assoc outer-style :border-radius dimensions)]
(if static-profile-picture?
outer-style-with-border-radius
outer-style)))
(defn customization-color
[color-id theme]
(colors/custom-color-by-theme color-id 50 60 nil nil theme))
(def initials-avatar-text
{:color colors/white-opa-70})
(defn inner-dot
[size online?]
(let [background (if online? colors/success-50 colors/neutral-40)
dimensions (get-in sizes [size :status-indicator])]
{:width (- dimensions 4)
:height (- dimensions 4)
:border-radius (- dimensions 4)
:background-color background}))
(defn dot
[size ring? theme]
(let [dimensions (get-in sizes [size :status-indicator])
border-width (get-in sizes [size :status-indicator-border])
right (case size
:big 2
:medium 0
:small -2
0)
bottom (case size
:big (if ring? -1 2)
:medium (if ring? 0 -2)
:small -2
0)]
{:position :absolute
:justify-content :center
:align-items :center
:bottom bottom
:right right
:width dimensions
:height dimensions
:border-width border-width
:border-radius dimensions
:background-color (colors/theme-colors colors/white colors/neutral-100 theme)
:border-color (colors/theme-colors colors/white colors/neutral-100 theme)}))
@@ -1,104 +1,64 @@
(ns quo2.components.avatars.user-avatar.view
(:require
[quo2.components.avatars.user-avatar.style :as style]
[quo2.components.common.no-flicker-image :as no-flicker-image]
[quo2.components.markdown.text :as text]
[quo2.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
utils.string))
(:require [quo2.components.avatars.user-avatar.style :as style]
[quo2.components.markdown.text :as text]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[react-native.fast-image :as fast-image]
utils.string))
(defn initials-avatar
[{:keys [full-name size customization-color theme]}]
[{:keys [full-name size draw-ring? customization-color theme]}]
(let [font-size (get-in style/sizes [size :font-size])
amount-initials (if (#{:xs :xxs :xxxs} size) 1 2)]
[rn/view
{:accessibility-label :initials-avatar
:style (style/initials-avatar size customization-color theme)}
:style (style/initials-avatar size draw-ring? customization-color theme)}
[text/text
{:style style/initials-avatar-text
:size font-size
:weight :semi-bold}
(utils.string/get-initials full-name amount-initials)]]))
(defn user-avatar-internal
"Render user avatar with `profile-picture`
`profile-picture` should be one of {:uri profile-picture-uri} or {:fn profile-picture-fn}
(def valid-ring-sizes #{:big :medium :small})
`profile-picture-fn` should return an image URI, there's helper fn to generate
it in `utils.image-server`
params for `profile-picture-fn`
{:length initials' length
:full-name used to generate initials
:font-size initials font size
:indicator-size status indicator outer radius, set to nil or 0 when no indicator
:indicator-border `indicator-size`-`indicator-border` is the inner radius
:indicator-color color for status indicator
:override-theme override theme for ring
:background-color intials avatar background color
:color intials avatar text color
:size intials avatar radius
:ring? render ident ring around avatar?}
supported color formats:
#RRGGBB
#RRGGBBAA
rgb(255,255,255)
rgba(255,255,255,0.1) note alpha is 0-1
the reason we use the `profile-picture-fn` here is to separate
logic (pubkey, key-uid... in subs) and style (color, size... in this component)"
[{:keys [full-name size profile-picture customization-color static?
status-indicator? online? ring? theme]
:or {size :big
status-indicator? true
(defn- user-avatar-internal
"If no `profile-picture` is given, draws the initials based on the `full-name` and
uses `ring-background` to display the ring behind the initials when given. Otherwise,
shows the `profile-picture` which already comes with the ring drawn."
[{:keys [full-name status-indicator? online? size profile-picture ring-background
customization-color static? muted? theme ring?]
:or {status-indicator? true
online? true
ring? true
customization-color :turquoise}
:as props}]
(let [full-name (or full-name "Your Name")
;; image generated with profile-picture-fn is round cropped
;; no need to add border-radius for them
outer-styles (style/outer size (not (:fn profile-picture)))
;; Once image is loaded, fast image re-renders view with the help of reagent atom,
size :big
customization-color :turquoise}}]
(let [full-name (or full-name "empty name")
draw-ring? (and ring? (when-not muted? (and ring-background (valid-ring-sizes size))))
outer-styles (style/outer size)
;; Once image is loaded, fast image rerenders view with the help of reagent atom,
;; But dynamic updates don't work when user-avatar is used inside hole-view
;; https://github.com/status-im/status-mobile/issues/15553
image-view (if static? no-flicker-image/image fast-image/fast-image)
font-size (get-in style/sizes [size :font-size])
amount-initials (if (#{:xs :xxs :xxxs} size) 1 2)
sizes (get style/sizes size)
indicator-color (get style/indicator-color (if online? :online :offline))
profile-picture-fn (:fn profile-picture)]
image-view (if static? rn/image fast-image/fast-image)]
[rn/view {:style outer-styles :accessibility-label :user-avatar}
(if (and full-name (not (or profile-picture-fn profile-picture)))
;; this is for things that's not user-avatar
;; but are currently using user-avatar to render the initials
;; e.g. community avatar
[initials-avatar props]
;; The `profile-picture` already has the ring in it
(when-let [image (or profile-picture ring-background)]
[image-view
{:accessibility-label :profile-picture
:style outer-styles
:source
(cond profile-picture-fn
{:uri (profile-picture-fn
{:length amount-initials
:full-name full-name
:font-size (:font-size (text/text-style {:size
font-size}))
:indicator-size (when status-indicator?
(:status-indicator sizes))
:indicator-border (when status-indicator?
(:status-indicator-border sizes))
:indicator-color indicator-color
:override-theme theme
:background-color (style/customization-color customization-color theme)
:color (:color style/initials-avatar-text)
:size (:width outer-styles)
:ring? ring?})}
(:uri profile-picture)
profile-picture
:else {:uri profile-picture})}])]))
{:accessibility-label (if draw-ring? :ring-background :profile-picture)
:style outer-styles
:source image}])
(when-not profile-picture
[initials-avatar
{:full-name full-name
:size size
:draw-ring? draw-ring?
:customization-color customization-color
:theme theme}])
(when status-indicator?
[rn/view
{:accessibility-label :status-indicator
:style (style/dot size draw-ring? theme)}
[rn/view
{:accessibility-label :inner-status-indicator-dot
:style (style/inner-dot size online?)}]])]))
(def user-avatar (quo2.theme/with-theme user-avatar-internal))
(def user-avatar (quo.theme/with-theme user-avatar-internal))
@@ -61,7 +61,6 @@
:active-opacity 1
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}
:pointer-events :auto
:style {:height 24}
:accessibility-label type}
[rn/view
{:style (merge
@@ -1,39 +0,0 @@
(ns quo2.components.buttons.wallet-button.component-spec
(:require [quo2.components.buttons.wallet-button.view :as wallet-button]
[test-helpers.component :as h]))
(h/describe "button tests"
(h/test "default render of wallet button component"
(h/render [wallet-button/view
{:icon :i/placeholder
:accessibility-label "test-button"}])
(h/is-truthy (h/get-by-label-text "test-button")))
(h/test "button on-press works"
(let [event (h/mock-fn)]
(h/render [wallet-button/view
{:icon :i/placeholder
:on-press event
:accessibility-label "test-button"}])
(h/fire-event :press (h/get-by-label-text "test-button"))
(h/was-called event)))
(h/test "button on-press disabled when disabled"
(let [event (h/mock-fn)]
(h/render [wallet-button/view
{:icon :i/placeholder
:on-press event
:accessibility-label "test-button"
:disabled? true}])
(h/fire-event :press (h/get-by-label-text "test-button"))
(h/was-not-called event)))
(h/test "button on-long-press works"
(let [event (h/mock-fn)]
(h/render [wallet-button/view
{:icon :i/placeholder
:on-long-press event
:accessibility-label "test-button"}])
(h/fire-event :long-press (h/get-by-label-text "test-button"))
(h/was-called event))))
@@ -1,20 +0,0 @@
(ns quo2.components.buttons.wallet-button.style
(:require [quo2.foundations.colors :as colors]))
(defn get-border-color
[{:keys [pressed? theme]}]
(if (= pressed? true)
(colors/theme-colors colors/neutral-40 colors/neutral-60 theme)
(colors/theme-colors colors/neutral-30 colors/neutral-70 theme)))
(defn main
[{:keys [pressed? theme disabled?]}]
{:border-color (get-border-color {:pressed? pressed?
:theme theme})
:border-width 1
:border-radius 10
:width 32
:height 32
:justify-content :center
:align-items :center
:opacity (when disabled? 0.3)})
@@ -1,29 +0,0 @@
(ns quo2.components.buttons.wallet-button.view
(:require
[quo2.components.buttons.wallet-button.style :as style]
[quo2.components.icon :as quo2.icons]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn- view-internal
[]
(let [pressed? (reagent/atom false)]
(fn
[{:keys [on-press on-long-press disabled? icon accessibility-label container-style theme]}]
[rn/pressable
{:accessibility-label (or accessibility-label :wallet-button)
:on-press on-press
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? nil)
:on-long-press on-long-press
:disabled disabled?
:style (merge (style/main {:pressed? @pressed?
:theme theme
:disabled? disabled?})
container-style)}
[quo2.icons/icon icon
{:color (colors/theme-colors colors/neutral-100 colors/white theme)}]])))
(def view (theme/with-theme view-internal))
@@ -1,11 +0,0 @@
(ns quo2.components.buttons.wallet-ctas.component-spec
(:require [test-helpers.component :as h]
[quo2.components.buttons.wallet-ctas.view :as wallet-ctas]))
(h/describe "Wallet CTAs test"
(h/test "Buttons render"
(h/render [wallet-ctas/view])
(h/is-truthy (h/get-by-label-text :buy))
(h/is-truthy (h/get-by-label-text :send))
(h/is-truthy (h/get-by-label-text :receive))
(h/is-truthy (h/get-by-label-text :bridge))))
@@ -1,13 +0,0 @@
(ns quo2.components.buttons.wallet-ctas.style)
(def container
{:padding-top 24
:padding-bottom 12
:padding-horizontal 20
:flex-direction :row})
(def button-container
{:padding-vertical 8
:width 77.75
:justify-content :center
:align-items :center})
@@ -1,55 +0,0 @@
(ns quo2.components.buttons.wallet-ctas.view
(:require
[quo2.components.buttons.wallet-button.view :as wallet-button]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[utils.i18n :as i18n]
[quo2.components.buttons.wallet-ctas.style :as style]))
(defn action-button
[{:keys [icon text on-press theme accessibility-label]}]
[rn/view
{:style style/button-container
:accessibility-label accessibility-label}
[wallet-button/view
{:icon icon
:on-press on-press
:on-long-press #(js/alert "long pressed")}]
[text/text
{:weight :medium
:size :paragraph-2
:style {:margin-top 4
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}} text]])
(defn view-internal
[{:keys [theme buy-action send-action receive-action bridge-action]}]
[rn/view {:style style/container}
[action-button
{:icon :i/add
:text (i18n/label :t/buy)
:on-press buy-action
:theme theme
:accessibility-label :buy}]
[action-button
{:icon :i/send
:text (i18n/label :t/send)
:on-press send-action
:theme theme
:accessibility-label :send}]
[action-button
{:icon :i/receive
:text (i18n/label :t/receive)
:on-press receive-action
:theme theme
:accessibility-label :receive}]
[action-button
{:icon :i/bridge
:text (i18n/label :t/bridge)
:on-press bridge-action
:theme theme
:accessibility-label :bridge}]])
(def view (quo.theme/with-theme view-internal))
@@ -1,49 +0,0 @@
(ns quo2.components.common.no-flicker-image
(:require
[oops.core :as oops]
[react-native.core :as rn]
[react-native.platform :as platform]
[reagent.core :as reagent]))
(def cached-sources (js/Set. (js/Array.)))
(defn- caching-image
[_ on-source-loaded]
(let [this (reagent/current-component)]
(reagent/create-class
{:component-did-update
(fn []
(let [source (-> this reagent/props :source)]
(when (oops/ocall cached-sources "has" source)
(on-source-loaded source))))
:reagent-render
(fn [{:keys [source] :as props}]
[rn/image
(assoc props
;; hide the cache image under the real one
;; have to render it for the on-load event
:style {:width 1
:height 1
:left "50%"
:top "50%"
:position :absolute}
:on-load
(fn [_]
(when-not (oops/ocall cached-sources "has" source)
(oops/ocall cached-sources "add" source)
(on-source-loaded source)))
:on-error js/console.error)])})))
(defn image
"Same as rn/image but cache the image source in a js/Set, so the image won't
flicker when re-render on android"
[]
(let [loaded-source (reagent/atom nil)
on-source-loaded #(reset! loaded-source %)]
(fn [props]
(if platform/ios?
[rn/image props]
[:<>
[rn/image (assoc props :source @loaded-source)]
[caching-image props on-source-loaded]]))))
@@ -3,6 +3,23 @@
[test-helpers.component :as h]))
(h/describe "Profile Input"
(h/test "renders user avatar with placeholder name if no value is specified"
(h/render [profile-input/profile-input
{:placeholder "Your Name"
:image-picker-props {:full-name "Your Name"}}])
(-> (js/expect (h/get-by-text "YN"))
(.toBeTruthy)))
(h/test "renders user avatar with full name if a value is specified"
(let [event (h/mock-fn)]
(h/render [profile-input/profile-input
{:on-change event
:placeholder "Your Name"
:image-picker-props {:full-name "Test Name"}}])
(h/fire-event :change (h/get-by-text "TN"))
(-> (js/expect (h/get-by-text "TN"))
(.toBeTruthy))))
(h/test "on press event fires"
(let [event (h/mock-fn)]
(h/render [profile-input/profile-input
@@ -1,7 +1,7 @@
(ns quo2.components.inputs.profile-input.view
(:require
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.buttons.button.view :as buttons]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.inputs.profile-input.style :as style]
[quo2.components.inputs.title-input.view :as title-input]
[react-native.core :as rn]
@@ -13,40 +13,38 @@
on-press
title-input-props
image-picker-props]}]
(let [full-name (:full-name image-picker-props)]
[rn/view
{:style (style/container customization-color)}
[rn/view
[hole-view/hole-view
;; Force re-render hole view when props are changed
;; https://github.com/status-im/status-mobile/issues/15577
{:key (hash
(if (:profile-picture image-picker-props)
(:profile-picture image-picker-props)
image-picker-props))
:holes [{:x 33
:y 24
:width 24
:height 24
:borderRadius 12}]}
[user-avatar/user-avatar
(assoc image-picker-props
:static? true
:status-indicator? false
:full-name (if (seq full-name) full-name placeholder)
:size :medium)]]
[buttons/button
{:accessibility-label :select-profile-picture-button
:type :grey
:background :blur
:on-press on-press
:size 24
:icon-only? true
:container-style style/button
:inner-style style/button-inner} :i/camera]]
[rn/view {:style style/input-container}
[title-input/title-input
(merge title-input-props
{:blur? true
:placeholder placeholder
:customization-color customization-color})]]]))
[rn/view
{:style (style/container customization-color)}
[rn/view
[hole-view/hole-view
;; Force re-render hole view when props are changed
;; https://github.com/status-im/status-mobile/issues/15577
{:key (hash
(if (:profile-picture image-picker-props)
(:profile-picture image-picker-props)
image-picker-props))
:holes [{:x 33
:y 24
:width 24
:height 24
:borderRadius 12}]}
[user-avatar/user-avatar
(assoc image-picker-props
:static? true
:status-indicator? false
:size :medium)]]
[buttons/button
{:accessibility-label :select-profile-picture-button
:type :grey
:background :blur
:on-press on-press
:size 24
:icon-only? true
:container-style style/button
:inner-style style/button-inner} :i/camera]]
[rn/view {:style style/input-container}
[title-input/title-input
(merge title-input-props
{:blur? true
:placeholder placeholder
:customization-color customization-color})]]])
@@ -21,6 +21,12 @@
:hole-size 26
:hole-x 19
:hole-y -1}
20 {:border-radius {:circular 11 :rounded 8}
:hole-radius {:circular 10 :rounded 9}
:margin-left -4
:hole-size 22
:hole-x 15
:hole-y -1}
16 {:border-radius {:circular 8 :rounded 8}
:hole-radius {:circular 9 :rounded 9}
:margin-left -4
@@ -38,6 +44,7 @@
:size (case size
32 :small
24 :xs
20 :xxs
16 :xxxs)}
item)]
(:photo :collectible) [fast-image/fast-image
@@ -47,11 +54,10 @@
:border-radius border-radius}}]))
(defn list-item
[index type size item list-size margin-left
hole-size hole-radius hole-x hole-y border-radius]
(let [last-item? (= index (- list-size 1))]
[index type size item list-size margin-left hole-size hole-radius hole-x hole-y border-radius]
(let [last-item? (= index (dec list-size))]
[hole-view/hole-view
{:style {:margin-left (if (= index 0) 0 margin-left)}
{:style {:margin-left (if (zero? index) 0 margin-left)}
:holes (if last-item?
[]
[{:x hole-x
@@ -122,8 +128,7 @@
items preview list items (only 4 items is required for preview)
"
[{:keys [type size list-size transparent? theme more-than-99-label]} items]
(let [items-arr (into [] items)
list-size (or list-size (count items))
(let [list-size (or list-size (count items))
margin-left (get-in params [size :margin-left])
hole-size (get-in params [size :hole-size])
border-radius (get-in params [size :border-radius (border-type type)])
@@ -133,7 +138,7 @@
[rn/view {:style {:flex-direction :row}}
(for [index (range (if (> list-size 4) 3 list-size))]
^{:key (str index list-size)}
[list-item index type size (get items-arr index) list-size
[list-item index type size (get (vec items) index) list-size
margin-left hole-size hole-radius hole-x hole-y border-radius])
(when (> list-size 4)
[overflow-label
+10 -9
View File
@@ -1,11 +1,11 @@
(ns quo2.components.list-items.user-list
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icons]
(:require [react-native.core :as rn]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.markdown.text :as text]
[quo2.components.messages.author.view :as author]
[quo2.components.selectors.selectors.view :as selectors]
[quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
[quo2.components.messages.author.view :as author]
[quo2.components.selectors.selectors.view :as selectors]))
(def container-style
{:margin-horizontal 8
@@ -45,10 +45,11 @@
:on-press (when on-press on-press)
:on-long-press (when on-long-press on-long-press)}
[user-avatar/user-avatar
{:full-name primary-name
:profile-picture photo-path
:online? online?
:size :small}]
{:full-name primary-name
:profile-picture photo-path
:status-indicator? true
:online? online?
:size :small}]
[rn/view {:style {:margin-left 8}}
[author/author
{:primary-name primary-name
+10 -6
View File
@@ -1,12 +1,12 @@
(ns quo2.components.markdown.list.view
(:require [react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.counter.step.view :as step]
[quo2.components.markdown.list.style :as style]
(:require [quo2.components.counter.step.view :as step]
[quo2.components.icon :as icon]
[quo2.components.markdown.list.style :as style]
[quo2.components.markdown.text :as text]
[quo2.components.tags.context-tag.view :as context-tag]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[quo2.components.tags.context-tag.view :as context-tag]))
[react-native.core :as rn]))
(defn get-colors
[theme blur?]
@@ -27,7 +27,11 @@
:size :paragraph-2}
description]
[rn/view {:style {:margin-left 4}}
[context-tag/context-tag {:blur? blur?} tag-picture tag-name]]
[context-tag/view
{:blur? blur?
:size 24
:profile-picture tag-picture
:full-name tag-name}]]
[text/text
{:style {:margin-left 4}
:accessibility-label :list-item-description-after-tag
@@ -0,0 +1,59 @@
(ns quo2.components.navigation.floating-shell-button
(:require [quo2.components.buttons.dynamic-button.view :as dynamic-button]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]))
(defn dynamic-button-view
[type dynamic-buttons style]
(when-let [{:keys [on-press customization-color label] :as props} (get dynamic-buttons type)]
[dynamic-button/view
{:type type
:label label
:on-press on-press
:count (:count props)
:style style
:customization-color customization-color}]))
(defn- section
[children]
[rn/view {:style {:flex 1} :pointer-events :box-none} children])
(defn- f-floating-shell-button
[dynamic-buttons style opacity-anim]
(let [original-style (merge {:flex-direction :row
:margin-horizontal 12
:pointer-events :box-none}
style)
animated-style (reanimated/apply-animations-to-style
(if opacity-anim
{:opacity opacity-anim}
{})
original-style)]
[reanimated/view {:style animated-style}
;; Left Section
[section
[dynamic-button-view :search dynamic-buttons
{:position :absolute
:right 8}]]
;; Mid Section (jump-to)
[dynamic-button-view :jump-to dynamic-buttons nil]
;; Right Section
[section
[rn/view
{:style {:position :absolute
:flex-direction :row
:right 0}}
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :scroll-to-bottom dynamic-buttons {:margin-left 8}]]]]))
(defn floating-shell-button
"[floating-shell-button dynamic-buttons style opacity-anim pointer-anim]
dynamic-buttons {:button-type {:on-press on-press :count count}}
style override style
opacity-anim reanimated value (optional)"
([dynamic-buttons style]
[:f> f-floating-shell-button dynamic-buttons style nil])
([dynamic-buttons style opacity-anim]
[:f> f-floating-shell-button dynamic-buttons style opacity-anim]))
@@ -1,22 +0,0 @@
(ns quo2.components.navigation.floating-shell-button.style
(:require [react-native.reanimated :as reanimated]))
(defn floating-shell-button
[style opacity-anim]
(reanimated/apply-animations-to-style
(if opacity-anim
{:opacity opacity-anim}
{})
(merge
{:flex-direction :row
:height 44
:align-self :center
:padding-top 8
:padding-horizontal 12
:pointer-events :box-none}
style)))
(def right-section
{:position :absolute
:flex-direction :row
:right 0})
@@ -1,49 +0,0 @@
(ns quo2.components.navigation.floating-shell-button.view
(:require [react-native.core :as rn]
[react-native.reanimated :as reanimated]
[quo2.components.buttons.dynamic-button.view :as dynamic-button]
[quo2.components.navigation.floating-shell-button.style :as style]))
(defn dynamic-button-view
[type dynamic-buttons style]
(when-let [{:keys [on-press customization-color label] :as props} (get dynamic-buttons type)]
[dynamic-button/view
{:type type
:label label
:on-press on-press
:count (:count props)
:style style
:customization-color customization-color}]))
(defn- section
[children]
[rn/view {:style {:flex 1} :pointer-events :box-none} children])
(defn- f-floating-shell-button
[dynamic-buttons style opacity-anim]
[reanimated/view {:style (style/floating-shell-button style opacity-anim)}
;; Left Section
[section
[dynamic-button-view :search dynamic-buttons
{:position :absolute
:right 8}]]
;; Mid Section (jump-to)
[dynamic-button-view :jump-to dynamic-buttons nil]
;; Right Section
[section
[rn/view
{:style style/right-section}
[dynamic-button-view :mention dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-down dynamic-buttons {:margin-left 8}]
[dynamic-button-view :notification-up dynamic-buttons {:margin-left 8}]
[dynamic-button-view :scroll-to-bottom dynamic-buttons {:margin-left 8}]]]])
(defn view
"[floating-shell-button dynamic-buttons style opacity-anim pointer-anim]
dynamic-buttons {:button-type {:on-press on-press :count count}}
style override style
opacity-anim reanimated value (optional)"
([dynamic-buttons style]
[:f> f-floating-shell-button dynamic-buttons style nil])
([dynamic-buttons style opacity-anim]
[:f> f-floating-shell-button dynamic-buttons style opacity-anim]))
@@ -1,9 +1,9 @@
(ns quo2.components.profile.select-profile.view
(:require
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.markdown.text :as text]
[quo2.components.profile.select-profile.style :as style]
[react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[reagent.core :as reagent]))
(defn- on-change-handler
@@ -24,27 +24,31 @@
(let [internal-selected? (reagent/atom (or default-selected? false))]
(fn [{:keys [selected?
profile-picture
ring-background
name
customization-color
on-change]
:or {customization-color :turquoise}}]
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
(reset! internal-selected? selected?))
[rn/touchable-opacity
{:style (style/container customization-color @internal-selected?)
:on-press #(on-change-handler internal-selected? on-change)
:active-opacity 1
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
:profile-picture profile-picture}]
[rn/view {:style (style/select-radio @internal-selected?)}
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]])))
(let [avatar-image-key (if profile-picture :profile-picture :ring-background)
picture (or profile-picture ring-background)]
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
(reset! internal-selected? selected?))
[rn/touchable-opacity
{:style (style/container customization-color @internal-selected?)
:on-press #(on-change-handler internal-selected? on-change)
:active-opacity 1
:accessibility-label :select-profile}
[rn/view {:style style/header}
[user-avatar/user-avatar
{:full-name name
:status-indicator? false
:size :medium
avatar-image-key picture}]
[rn/view {:style (style/select-radio @internal-selected?)}
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
[text/text
{:size :heading-2
:weight :semi-bold
:style style/profile-name}
name]]))))
+87 -37
View File
@@ -1,31 +1,11 @@
(ns quo2.components.tags.context-tag.style
(:require [quo2.foundations.colors :as colors]))
(defn base-tag
[override-theme blur?]
{:border-radius 100
:padding-vertical 3
:flex-direction :row
:padding-right 8
:padding-left 8
:background-color (if blur?
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 override-theme)
(colors/theme-colors colors/neutral-10 colors/neutral-90 override-theme))})
(defn context-tag-icon-color
[blur?]
[theme blur?]
(if blur?
(colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40)
(colors/theme-colors colors/neutral-50 colors/neutral-40)))
(def context-tag-text-container
{:align-items :center
:margin-left 4
:flex-direction :row})
(def audio-tag-container
{:padding-left 2
:padding-vertical 2})
(colors/theme-colors colors/neutral-80-opa-40 colors/white-opa-40 theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme)))
(def audio-tag-icon-container
{:width 20
@@ -37,21 +17,91 @@
(def audio-tag-icon-color colors/white)
(defn audio-tag-text-color
[override-theme]
(colors/theme-colors colors/neutral-100 colors/white override-theme))
(defn container
[{:keys [theme type size state blur? customization-color]}]
(let [background-color (if blur?
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)
(colors/theme-colors colors/neutral-10 colors/neutral-90 theme))
border-radius (cond
(not (#{:account :collectible} type)) 16
(= size 24) 8
:else 10)
border-color (colors/theme-colors
(colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)]
(cond-> {:padding 2
:flex-direction :row
:align-items :center
:height size
:background-color background-color
:border-radius border-radius}
(= state :selected) (assoc :height (+ size 2)
:border-color border-color
:border-width 1))))
(def community-tag
{:padding-vertical 2
:padding-left 2})
(def community-tag-text-container
{:margin-left 4
:flex 1
(defn tag-container
[size]
{:margin-right (if (= size 24) 6 10)
:flex-direction :row
:align-items :center})
(defn community-tag-text
[override-theme]
{:margin-left 2
:color (colors/theme-colors colors/neutral-100 colors/white override-theme)})
(defn tag-spacing
[size]
{:margin-left (if (= size 24) 4 8)})
(defn text
[theme]
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
(defn circle-logo
[size]
(if (= size 24)
{:width 20 :height 20 :border-radius 10}
{:width 28 :height 28 :border-radius 14}))
(defn rounded-logo
[size]
(if (= size 24)
{:width 20
:height 20
:border-radius 6}
{:width 28
:height 28
:border-radius 8}))
(defn address
[size]
(if (= size 24)
{:margin-horizontal 6
:margin-vertical 1
:flex-direction :row
:align-items :center}
{:margin-horizontal 10
:margin-vertical 3
:flex-direction :row
:align-items :center}))
(defn icon
[size]
(if (= size 24)
{:margin-horizontal 6
:margin-vertical 1
:flex-direction :row
:align-items :center}
{:margin-left 8
:margin-right 10
:margin-vertical 3
:flex-direction :row
:align-items :center}))
(defn icon-spacing
[size]
(if (= size 24)
{:margin-left 4}
{:margin-left 2}))
(def audio
{:margin-right 6
:flex-direction :row
:align-items :center})
+197 -91
View File
@@ -1,106 +1,212 @@
(ns quo2.components.tags.context-tag.view
(:require [quo2.components.avatars.group-avatar.view :as group-avatar]
[quo2.components.avatars.user-avatar.style :as user-avatar.style]
(:require [quo2.components.avatars.account-avatar.view :as account-avatar]
[quo2.components.avatars.group-avatar.view :as group-avatar]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icons]
[quo2.components.list-items.preview-list :as preview-list]
[quo2.components.markdown.text :as text]
[quo2.components.tags.context-tag.style :as style]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]))
(defn trim-public-key
(defn- tag-skeleton
[{:keys [theme size text] :or {size 24}} logo-component]
[rn/view {:style (style/tag-container size)}
logo-component
[rn/view {:style (style/tag-spacing size)}
[text/text
{:style (style/text theme)
:weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)}
text]]])
(defn- communities-tag
[{:keys [theme size community-logo community-name blur? channel? channel-name]}]
(let [text-size (if (= size 24) :paragraph-2 :paragraph-1)
icon-size (if (= size 24) 16 20)]
[rn/view {:style (style/tag-container size)}
[rn/image {:style (style/circle-logo size) :source community-logo}]
[rn/view {:style (style/tag-spacing size)}
[text/text
{:style (style/text theme)
:weight :medium
:size text-size}
community-name]]
(when channel?
[:<>
[icons/icon :i/chevron-right
{:color (style/context-tag-icon-color theme blur?)
:size icon-size}]
[text/text
{:style (style/text theme)
:weight :medium
:size text-size}
(str "# " channel-name)]])]))
(defn- trim-public-key
[pk]
(str (subs pk 0 6) "..." (subs pk (- (count pk) 3))))
(str (subs pk 0 5) "..." (subs pk (- (count pk) 3))))
(defn base-tag
[{:keys [override-theme style blur?]} & children]
(into
[rn/view {:style (merge (style/base-tag override-theme blur?) style)}]
children))
(defn group-avatar-tag
[label opts]
[base-tag
(-> opts
(select-keys [:override-theme :style :blur?])
(assoc-in [:style :padding-left] 3)
(assoc-in [:style :padding-vertical] 2))
[group-avatar/view opts]
(defn- address-tag
[{:keys [theme size address]}]
[rn/view {:style (style/address size)}
[text/text
{:weight :medium
:size :paragraph-2
:style (:text-style opts)}
(str " " label)]])
{:style (style/text theme)
:weight :monospace ;; TODO: fix this style (issue #17009)
:size (if (= size 24) :paragraph-2 :paragraph-1)}
(trim-public-key address)]])
(defn public-key-tag
[params public-key]
[base-tag params
[text/text
{:weight :monospace
:size :paragraph-2}
(trim-public-key public-key)]])
(defn- icon-tag
[{:keys [theme size icon blur? context]}]
[rn/view {:style (style/icon size)}
[icons/icon icon
{:color (style/context-tag-icon-color theme blur?)
:size (if (= size 24) 12 20)}]
[rn/view {:style (style/icon-spacing size)}
[text/text
{:style (style/text theme)
:weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)}
context]]])
(defn context-tag
[{:keys [text-style blur? no-avatar-placeholder? text-container-style ellipsize-text? ring?]
:as props}
photo
name
channel-name]
(let [text-props {:weight :medium
:size :paragraph-2
:style (assoc text-style :justify-content :center)
:number-of-lines 1
:ellipsize-mode :tail}
empty-photo? (nil? photo)
avatar-size :xxs
avatar-outer-size (get-in user-avatar.style/sizes [avatar-size :outer])]
[base-tag (update-in props [:style :padding-left] #(or % 3))
(if (and empty-photo? no-avatar-placeholder?)
[rn/view {:style {:width avatar-outer-size}}]
[user-avatar/user-avatar
{:full-name name
:profile-picture photo
:size avatar-size
:ring? ring?
:status-indicator? false}])
[rn/view {:style (or text-container-style style/context-tag-text-container)}
(if ellipsize-text?
[rn/view {:style {:flex 1}}
[text/text text-props name]]
[text/text text-props (str " " name)])
(when channel-name
[:<>
[icons/icon
:i/chevron-right
{:color (style/context-tag-icon-color blur?)
:size 16}]
[text/text text-props (str "# " channel-name)]])]]))
(defn- view-internal
[{:keys [theme type size state blur? customization-color profile-picture full-name users
group-name token-logo amount token-name network-logo network-name networks
account-name emoji collectible collectible-name collectible-number duration]
:or {customization-color :blue
type :default
state :default}
:as props}]
[rn/view
{:style (style/container {:theme theme
:type type
:size size
:state state
:blur? blur?
:customization-color customization-color})}
(case type
:default
[tag-skeleton {:theme theme :size size :text full-name}
[user-avatar/user-avatar
{:full-name full-name
:profile-picture profile-picture
:size (if (= size 24) :xxs 28)
:status-indicator? false}]]
(defn user-avatar-tag
[params username photo]
[context-tag params photo username])
:multiuser
[preview-list/preview-list {:type :user :size 20}
users]
(defn audio-tag
[duration params]
[base-tag (merge {:style style/audio-tag-container} params)
[rn/view {:style style/audio-tag-icon-container}
[icons/icon
:i/play
{:color style/audio-tag-icon-color
:size 12}]]
[text/text
{:weight :medium
:size :paragraph-2
:style {:margin-left 4
:color (style/audio-tag-text-color (:override-theme params))}}
duration]])
:multinetwork ;; TODO: use multinetwork preview-list type when available (issue #17008)
[preview-list/preview-list {:type :user :size 20}
(map #(hash-map :profile-picture %) networks)]
(defn community-tag
[avatar community-name {:keys [override-theme] :as params}]
[context-tag
(merge {:style style/community-tag
:text-style (style/community-tag-text override-theme)
:text-container-style style/community-tag-text-container
:ellipsize-text? true}
params)
avatar
community-name])
:audio
[tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style style/audio-tag-icon-container}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:group
[tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view
{:icon-name :i/members
:size (if (= size 24) :x-small :small)
:customization-color (colors/custom-color :purple 50)}]]
(:channel :community)
[communities-tag (assoc props :channel? (= type :channel))]
:token
[tag-skeleton {:theme theme :size size :text (str amount " " token-name)}
[rn/image {:style (style/circle-logo size) :source token-logo}]]
:network
[tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]]
:collectible
[tag-skeleton
{:theme theme
:size size
:text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]]
:account
[tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view {:emoji emoji :size (if (= size 24) 20 28)}]]
:address
[address-tag props]
:icon
[icon-tag props]
nil)])
(def view
"Properties:
type, state, blur? & customization-color
Depending on the `type` selected, different properties are accepted:
- `:default` or `nil`:
- size
- profile-picture
- full-name
- `:multiuser`:
- users (vector of {:profile-picture pic, :full-name \"a name\"})
- `:group`
- size
- group-name
- `:community`
- size
- community-logo (valid rn/image :source value)
- community-name
- `:channel`
- size
- community-logo (valid rn/image :source value)
- community-name
- channel-name
- `:token`
- size
- token-logo (valid rn/image :source value)
- amount
- token-name
- `:network`
- size
- network-logo (valid rn/image :source value)
- network-name
- `:multinetworks`
- networks (vector of {:network-logo pic, :network-name \"a name\"})
- `:account`
- size
- account-name
- emoji (string containing an emoji)
- `:collectible`
- size
- collectible (valid rn/image :source value)
- collectible-name
- collectible-number
- `:address`
- size
- address (string)
- `:icon`
- size
- icon
- context (string)
- `:audio`
- duration (string)
"
(quo.theme/with-theme view-internal))
@@ -1,61 +0,0 @@
(ns quo2.components.wallet.keypair.component-spec
(:require [test-helpers.component :as h]
[quo2.components.wallet.keypair.view :as keypair]))
(def accounts
[{:account-props {:customization-color :turquoise
:size 32
:emoji "\uD83C\uDFB2"
:type :default
:name "Trip to Vegas"
:address "0x0ah...71a"}
:networks [:ethereum :optimism]
:state :default
:action :none}])
(def default-details
{:full-name "John Doe"
:address "zQ3...6fBd2"})
(def other-details {:full-name "Metamask"})
(h/describe "Wallet: Keypair"
(h/test "Default keypair title renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :default-keypair
:stored :on-device
:action :selector
:details default-details}])
(h/is-truthy (h/get-by-label-text :title)))
(h/test "On device renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-device
:action :selector
:details other-details}])
(h/is-truthy (h/get-by-label-text :details)))
(h/test "Selector action renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-keycard
:action :selector
:details other-details}])
(h/is-truthy (h/get-by-label-text :radio-on)))
(h/test "Options action renders"
(h/render [keypair/view
{:accounts accounts
:customization-color :blue
:type :other
:stored :on-keycard
:action :options
:details other-details}])
(h/is-truthy (h/get-by-label-text :options-button))))
@@ -1,26 +0,0 @@
(ns quo2.components.wallet.keypair.style
(:require [quo2.foundations.colors :as colors]))
(defn container
[selected? customization-color theme]
{:border-radius 20
:border-width 1
:border-color (if selected?
(colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)
(colors/theme-colors colors/neutral-10 colors/neutral-80 theme))
:padding-bottom 8})
(def header-container
{:padding-horizontal 12
:padding-top 8
:padding-bottom 12
:flex-direction :row
:align-items :center})
(def title-container
{:flex-direction :row
:align-items :center
:justify-content :space-between
:flex 1})
@@ -1,93 +0,0 @@
(ns quo2.components.wallet.keypair.view
(:require
[quo2.components.avatars.icon-avatar :as icon-avatar]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icon]
[quo2.components.list-items.account-list-card.view :as account-list-card]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[quo2.components.selectors.selectors.view :as selectors]
[reagent.core :as reagent]
[utils.i18n :as i18n]
[quo2.components.wallet.keypair.style :as style]
[clojure.string :as string]))
(defn keypair-string
[full-name]
(let [first-name (first (string/split full-name #" "))]
(i18n/label :t/keypair-title {:name first-name})))
(defn details-string
[address stored]
(str (when address (str address " ∙ "))
(if (= stored :on-device) (i18n/label :t/on-device) (i18n/label :t/on-keycard))))
(defn avatar
[type full-name customization-color]
(if (= type :default-keypair)
[user-avatar/user-avatar
{:full-name full-name
:ring? true
:size :small
:customization-color customization-color}]
[icon-avatar/icon-avatar
{:size :medium
:icon :i/placeholder
:border? true}]))
(defn title-view
[full-name action selected? type customization-color on-options-press theme]
[rn/view
{:style style/title-container
:accessibility-label :title}
[text/text {:weight :semi-bold}
(if (= type :default-keypair) (keypair-string full-name) full-name)]
(if (= action :selector)
[selectors/radio
{:checked? selected?
:customization-color customization-color}]
[rn/pressable {:on-press on-options-press}
[icon/icon :i/options
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)
:accessibility-label :options-button}]])])
(defn details-view
[address stored theme]
[rn/view
{:style {:flex-direction :row
:align-items :center}}
[text/text
{:size :paragraph-2
:accessibility-label :details
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(details-string address stored)]
(when (= stored :on-keycard)
[rn/view {:style {:margin-left 4}}
[icon/icon :i/keycard-card
{:size 16
:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]])])
(defn- view-internal
[]
(let [selected? (reagent/atom true)]
(fn [{:keys [theme accounts customization-color type details stored action on-options-press]}]
(let [{:keys [address full-name]} details]
[rn/pressable
{:style (style/container @selected? customization-color theme)
:on-press #(when (= action :selector) (reset! selected? (not @selected?)))}
[rn/view {:style style/header-container}
[avatar type full-name customization-color]
[rn/view
{:style {:margin-left 8
:flex 1}}
[title-view full-name action @selected? type customization-color on-options-press theme]
[details-view address stored theme]]]
[rn/flat-list
{:data accounts
:render-fn account-list-card/view
:separator [rn/view {:style {:height 8}}]
:style {:padding-horizontal 8}}]]))))
(def view (quo.theme/with-theme view-internal))
@@ -1,85 +0,0 @@
(ns quo2.components.wallet.network-link.view
(:require
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.svg :as svg]))
(defn link-linear
[{:keys [source theme]}]
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "10" :fill :none}
[svg/path {:stroke (get colors/networks source) :d "M68 5H5"}]
[svg/circle
{:cx "68"
:cy "5"
:r "4"
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
:stroke (get colors/networks source)}]
[svg/circle
{:cx "5"
:cy "5"
:r "4"
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
:stroke (get colors/networks source)}]])
(defn link-1x
[{:keys [source destination theme]}]
[svg/svg {:xmlns "http://www.w3.org/2000/svg" :width "73" :height "66" :fill :none}
[svg/path
{:stroke "url(#gradient)" :d "M68 5h-9.364c-11.046 0-20 8.954-20 20v16c0 11.046-8.955 20-20 20H5"}]
[svg/circle
{:cx "68"
:cy "5"
:r "4"
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
:stroke (get colors/networks destination)}]
[svg/circle
{:cx "5"
:cy "61"
:r "4"
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
:stroke (get colors/networks source)}]
[svg/defs
[svg/linear-gradient
{:id "gradient" :x1 "72.271" :x2 "82.385" :y1 "5" :y2 "34.155" :gradientUnits "userSpaceOnUse"}
[svg/stop {:stopColor (get colors/networks destination)}]
[svg/stop {:offset "1" :stopColor (get colors/networks source)}]]]])
(defn link-2x
[{:keys [source destination theme]}]
[svg/svg
{:width "73" :height "122" :viewBox "0 0 73 122" :fill "none" :xmlns "http://www.w3.org/2000/svg"}
[svg/path
{:d
"M67.9999 5L58.6356 5C47.5899 5 38.6356 13.9543 38.6356 25L38.6356 97C38.6356 108.046 29.6813 117 18.6356 117L5.00006 117"
:stroke "url(#gradient)"}]
[svg/circle
{:cx "68"
:cy "5"
:r "4"
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
:stroke (get colors/networks destination)}]
[svg/circle
{:cx "5"
:cy "117"
:r "4"
:fill (colors/theme-colors colors/white colors/neutral-90 theme)
:stroke (get colors/networks source)}]
[svg/defs
[svg/linear-gradient
{:id "gradient"
:x1 "72.2711"
:y1 "5.00001"
:x2 "102.867"
:y2 "49.0993"
:gradientUnits "userSpaceOnUse"}
[svg/stop {:stop-color (get colors/networks destination)}]
[svg/stop {:offset "1" :stop-color (get colors/networks source)}]]]])
(defn- view-internal
[{:keys [shape] :as props}]
(case shape
:linear [link-linear props]
:1x [link-1x props]
:2x [link-2x props]))
(def view (quo.theme/with-theme view-internal))
@@ -0,0 +1,19 @@
(ns quo2.components.wallet.wallet-activity.component-spec
(:require [quo2.components.wallet.wallet-activity.view :as wallet-activity]
[test-helpers.component :as h]))
(def props
{})
(h/describe "Wallet activity"
(h/test "default render"
(h/render [wallet-activity/view props])
(h/is-truthy (h/query-by-label-text :wallet-activity)))
(h/test "Should call :on-press"
(let [on-press (h/mock-fn)]
(h/render [wallet-activity/view
(assoc props :on-press on-press)])
(h/is-truthy (h/query-by-label-text :wallet-activity))
(h/fire-event :press (h/query-by-label-text :wallet-activity))
(h/was-called on-press))))
@@ -0,0 +1,83 @@
(ns quo2.components.wallet.wallet-activity.style
(:require [quo2.foundations.colors :as colors]))
(defn wallet-activity-container
[{:keys [pressed?
theme
blur?]}]
(merge
{:border-radius 16
:padding-top 8
:padding-left 12
:padding-right 12
:padding-bottom 12}
(when pressed?
{:background-color (if blur?
colors/white-opa-5
(colors/theme-colors colors/neutral-5 colors/neutral-90 theme))})))
(def transaction-header-container
{:flex-direction :row
:align-items :center})
(defn transaction-header
[theme]
{:color (colors/theme-colors colors/neutral-100 colors/white theme)
:margin-right 4})
(defn transaction-counter
[theme]
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
(defn transaction-counter-container
[theme blur?]
{:border-width 1
:border-radius 6
:margin-right 8
:padding-horizontal 2
:border-color (if-not blur?
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
colors/white-opa-10)})
(defn timestamp
[theme blur?]
{:color (if-not blur?
(colors/theme-colors colors/neutral-40 colors/neutral-50 theme)
colors/white-opa-40)})
(defn prop-text
[theme]
{:margin-right 4
:color (colors/theme-colors colors/neutral-100 colors/white theme)})
(def icon-container
{:width 32
:height 32
:margin-top 8})
(def content-container
{:margin-left 8})
(def content-line
{:flex-direction :row :margin-top 2 :align-items :center})
(defn icon-hole-view
[theme blur?]
{:width 32
:height 32
:border-width 1
:border-color (if-not blur?
(colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
colors/white-opa-5)
:border-radius 16
:align-items :center
:justify-content :center})
(defn icon-color
[theme]
(colors/theme-colors colors/neutral-100 colors/white theme))
(def icon-status-container
{:position :absolute :bottom 0 :right 0})
@@ -0,0 +1,169 @@
(ns quo2.components.wallet.wallet-activity.view
(:require [quo2.theme :as quo.theme]
[quo2.components.wallet.wallet-activity.style :as style]
[react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.icon :as icon]
[quo2.components.tags.context-tag.view :as context-tag]
[react-native.hole-view :as hole-view]
[utils.i18n :as i18n]
[reagent.core :as reagent]))
(def transaction-translation
{:receive [i18n/label :t/receive]
:send [i18n/label :t/send]
:swap [i18n/label :t/swap]
:bridge [i18n/label :t/bridge]
:buy [i18n/label :t/buy]
:destroy [i18n/label :t/destroy]
:mint [i18n/label :t/mint]})
(def transaction-icon
{:receive :i/receive
:send :i/send
:swap :i/swap
:bridge :i/bridge
:buy :i/buy
:destroy :i/destroy
:mint :i/mint})
(def status-icon
{:pending :i/pending-state
:confirmed :i/positive-state
:finalised :i/diamond-blue
:failed :i/negative-state})
(defn transaction-header
[{:keys [transaction
timestamp
counter
theme
blur?]
:or {transaction :receive
counter 1}}]
[rn/view
{:style style/transaction-header-container}
[text/text
{:weight :semi-bold
:size :paragraph-1
:style (style/transaction-header theme)}
(transaction transaction-translation)]
(when (> counter 1)
[rn/view (style/transaction-counter-container theme blur?)
[text/text
{:weight :medium
:size :label
:style (style/transaction-counter theme)}
(str "x" counter "")]])
[rn/view
[text/text
{:weight :regular
:size :label
:style (style/timestamp theme blur?)}
timestamp]]])
(defn transaction-icon-view
[{:keys [theme blur? transaction status]
:or {transaction :receive
status :pending}}]
[rn/view {:style style/icon-container}
[hole-view/hole-view
{:style (style/icon-hole-view theme blur?)
:holes [{:x 20
:y 20
:right 0
:width 12
:height 12
:borderRadius 6}]}
[icon/icon (transaction-icon transaction)
{:color (style/icon-color theme)}]]
[rn/view {:style style/icon-status-container}
[icon/icon (status-icon status)
{:size 12
:no-color :true}]]])
(defn prop-text
[label theme]
[text/text
{:weight :regular
:size :paragraph-2
:style (style/prop-text theme)}
[i18n/label label]])
(defn prop-tag
[props]
[rn/view {:style {:margin-right 4}}
[context-tag/view (merge {:size 24} props)]])
(defn- view-internal
[_]
(let [pressed? (reagent/atom false)]
(fn
[{:keys [state theme blur?
on-press
first second third fourth
second-prefix third-prefix fourth-prefix]
:as props}]
[rn/pressable
{:style (style/wallet-activity-container {:pressed? @pressed?
:theme theme
:blur? blur?})
:accessibility-label :wallet-activity
:disabled (= state :disabled)
:on-press on-press
:on-press-in (fn [] (reset! pressed? true))
:on-press-out (fn [] (reset! pressed? false))}
[rn/view
{:style {:flex-direction :row}}
[transaction-icon-view props]
[rn/view ;content
{:style style/content-container}
[transaction-header props]
[rn/view {:style style/content-line}
(when first [prop-tag first])
(when second-prefix [prop-text second-prefix theme])
(when second [prop-tag second])]
[rn/view {:style style/content-line}
(when third-prefix [prop-text third-prefix theme])
(when third [prop-tag third])
(when fourth-prefix [prop-text fourth-prefix theme])
(when fourth [prop-tag fourth])]]]])))
(def view
"Properties:
- :transaction - type of transaction`. Possible values:
- :receive
- :send
- :swap
- :bridge
- :buy
- :destroy
- :mint
- :status - transaction status. Possible values:
- :pending
- :confirmed
- :finalised
- :failed
- :counter - amount of transactions shown by instance of the component
- :timestamp - when transaction occured (string)
- :blur?
- :first - props for context tag component that will be first on the first line
- :second - props for context tag component that will be second on the first line
- :third - props for context tag component that will be first on the second line
- :fourth - props for context tag component that will be second on the second line
- :second-prefix - translation keyword to be used with label before second context tag
- :third-prefix - translation keyword to be used with label before third context tag
- :fourth-prefix - translation keyword to be used with label before fourth context tag
"
(quo.theme/with-theme view-internal))
@@ -12,10 +12,6 @@
{:flex-direction :row
:justify-content :space-between})
(def container-info-bottom
{:flex-direction :row
:padding-top 4})
(def network-dropdown
{:border-color colors/neutral-50
:border-width 1
@@ -24,10 +20,8 @@
:height 32})
(defn color-metrics
[metrics theme]
(if (= metrics :positive)
(colors/theme-colors colors/success-50 colors/success-60 theme)
(colors/theme-colors colors/danger-50 colors/danger-60 theme)))
[metrics]
(if (= metrics :positive) colors/success-50 colors/danger-50))
(defn color-text-heading
[theme]
@@ -46,8 +40,8 @@
{:color (color-text-paragraph theme)})
(defn dot-separator
[metrics theme]
{:background-color (color-metrics metrics theme)
[metrics]
{:background-color (color-metrics metrics)
:margin-horizontal 4
:width 2
:height 2})
@@ -42,38 +42,38 @@
[network-dropdown-temporary]])
(defn- view-metrics
[{:keys [metrics currency-change percentage-change theme]}]
[metrics currency-change percentage-change]
[rn/view
{:style {:flex-direction :row
:align-items :center}}
[text/text
{:weight :medium
:size :paragraph-2
:style {:color (style/color-metrics metrics theme)}}
:style {:color (style/color-metrics metrics)}}
percentage-change]
[rn/view
{:style (style/dot-separator metrics theme)}]
{:style (style/dot-separator metrics)}]
[text/text
{:weight :medium
:size :paragraph-2
:style {:color (style/color-metrics metrics theme)
:style {:color (style/color-metrics metrics)
:margin-right 4}}
currency-change]
[icons/icon
(if (= metrics :positive) :i/positive :i/negative)
{:color (style/color-metrics metrics theme)
{:color (style/color-metrics metrics)
:size 16}]])
(defn- view-info-bottom
[{:keys [state time-frame metrics date begin-date end-date
currency-change percentage-change theme]}]
[rn/view {:style style/container-info-bottom}
[rn/view {:flex-direction :row}
(when (= state :loading)
[rn/view
{:style {:flex-direction :row
:align-items :center}}
(loading-bars [{:width 32 :height 10 :margin 8}
{:width 32 :height 10 :margin 2}
{:width 32 :height 10 :margin 4}
{:width 62 :height 10 :margin 4}
{:width 10 :height 10 :margin 0}]
theme)])
@@ -107,11 +107,7 @@
:margin-right 8}}
(time-frame time-frames)]
(when (and (= state :default) (not= metrics :none))
[view-metrics
{:metrics metrics
:currency-change currency-change
:percentage-change percentage-change
:theme theme}])])])
[view-metrics metrics currency-change percentage-change])])])
(defn- view-internal
[props]
+7 -16
View File
@@ -13,8 +13,6 @@
quo2.components.buttons.dynamic-button.view
quo2.components.buttons.predictive-keyboard.view
quo2.components.buttons.slide-button.view
quo2.components.buttons.wallet-button.view
quo2.components.buttons.wallet-ctas.view
quo2.components.browser.browser-input.view
quo2.components.calendar.calendar.view
quo2.components.calendar.calendar-day.view
@@ -72,7 +70,7 @@
quo2.components.messages.author.view
quo2.components.messages.gap
quo2.components.messages.system-message
quo2.components.navigation.floating-shell-button.view
quo2.components.navigation.floating-shell-button
quo2.components.navigation.page-nav
quo2.components.notifications.activity-log.view
quo2.components.notifications.activity-logs-photos.view
@@ -111,14 +109,13 @@
quo2.components.text-combinations.title.view
quo2.components.wallet.account-overview.view
quo2.components.wallet.account-card.view
quo2.components.wallet.keypair.view
quo2.components.wallet.network-amount.view
quo2.components.wallet.network-bridge.view
quo2.components.wallet.network-link.view
quo2.components.wallet.progress-bar.view
quo2.components.wallet.summary-info.view
quo2.components.wallet.token-input.view
quo2.components.wallet.wallet-overview.view))
quo2.components.wallet.wallet-overview.view
quo2.components.wallet.wallet-activity.view))
(def separator quo2.components.common.separator.view/separator)
@@ -139,8 +136,6 @@
(def dynamic-button quo2.components.buttons.dynamic-button.view/view)
(def predictive-keyboard quo2.components.buttons.predictive-keyboard.view/view)
(def slide-button quo2.components.buttons.slide-button.view/view)
(def wallet-button quo2.components.buttons.wallet-button.view/view)
(def wallet-ctas quo2.components.buttons.wallet-ctas.view/view)
;;;; Browser
(def browser-input quo2.components.browser.browser-input.view/view)
@@ -244,7 +239,7 @@
(def static-skeleton quo2.components.loaders.skeleton.view/view)
;;;; Navigation
(def floating-shell-button quo2.components.navigation.floating-shell-button.view/view)
(def floating-shell-button quo2.components.navigation.floating-shell-button/floating-shell-button)
(def page-nav quo2.components.navigation.page-nav/page-nav)
;;;; Markdown
@@ -307,11 +302,8 @@
(def permission-tag quo2.components.tags.permission-tag/tag)
(def status-tag quo2.components.tags.status-tags/status-tag)
(def token-tag quo2.components.tags.token-tag/tag)
(def user-avatar-tag quo2.components.tags.context-tag.view/user-avatar-tag)
(def context-tag quo2.components.tags.context-tag.view/context-tag)
(def group-avatar-tag quo2.components.tags.context-tag.view/group-avatar-tag)
(def audio-tag quo2.components.tags.context-tag.view/audio-tag)
(def community-tag quo2.components.tags.context-tag.view/community-tag)
(def context-tag quo2.components.tags.context-tag.view/view)
;;;; Title
(def title quo2.components.text-combinations.title.view/title)
@@ -319,11 +311,10 @@
;;;; Wallet
(def account-card quo2.components.wallet.account-card.view/view)
(def account-overview quo2.components.wallet.account-overview.view/view)
(def keypair quo2.components.wallet.keypair.view/view)
(def network-amount quo2.components.wallet.network-amount.view/view)
(def network-bridge quo2.components.wallet.network-bridge.view/view)
(def progress-bar quo2.components.wallet.progress-bar.view/view)
(def summary-info quo2.components.wallet.summary-info.view/view)
(def network-link quo2.components.wallet.network-link.view/view)
(def token-input quo2.components.wallet.token-input.view/view)
(def wallet-overview quo2.components.wallet.wallet-overview.view/view)
(def wallet-activity quo2.components.wallet.wallet-activity.view/view)
+2 -4
View File
@@ -8,8 +8,6 @@
[quo2.components.buttons.composer-button.component-spec]
[quo2.components.buttons.predictive-keyboard.component-spec]
[quo2.components.buttons.slide-button.component-spec]
[quo2.components.buttons.wallet-button.component-spec]
[quo2.components.buttons.wallet-ctas.component-spec]
[quo2.components.calendar.calendar.component-spec]
[quo2.components.calendar.calendar-day.component-spec]
[quo2.components.calendar.calendar.month-picker.component-spec]
@@ -56,10 +54,10 @@
[quo2.components.tags.status-tags-component-spec]
[quo2.components.wallet.account-overview.component-spec]
[quo2.components.wallet.account-card.component-spec]
[quo2.components.wallet.keypair.component-spec]
[quo2.components.wallet.network-amount.component-spec]
[quo2.components.wallet.network-bridge.component-spec]
[quo2.components.wallet.progress-bar.component-spec]
[quo2.components.wallet.summary-info.component-spec]
[quo2.components.wallet.token-input.component-spec]
[quo2.components.wallet.wallet-overview.component-spec]))
[quo2.components.wallet.wallet-overview.component-spec]
[quo2.components.wallet.wallet-activity.component-spec]))
+2 -4
View File
@@ -1,6 +1,5 @@
(ns quo2.foundations.colors
(:require [clojure.string :as string]
[react-native.platform :as platform]
[quo2.theme :as theme]))
(defn alpha
@@ -127,13 +126,12 @@
(def neutral-5-opa-70-blur (alpha neutral-5 0.7))
(def neutral-10-opa-10-blur (alpha neutral-10 0.1))
(def neutral-10-opa-40-blur (alpha neutral-10 0.4))
;; https://github.com/status-im/status-mobile/issues/14903
(def neutral-80-opa-80-blur (if platform/android? (alpha "#192438" 0.8) "#1E2430CC"))
(def neutral-80-opa-80-blur (alpha "#192438" 0.8))
(def neutral-90-opa-10-blur (alpha neutral-90 0.1))
(def neutral-90-opa-40-blur (alpha neutral-90 0.4))
(def neutral-90-opa-70-blur (alpha neutral-90 0.7))
(def neutral-95-opa-70-blur neutral-95-opa-70)
(def neutral-100-opa-70-blur (if platform/android? neutral-100-opa-70 "#0D1014B3"))
(def neutral-100-opa-70-blur neutral-100-opa-70)
;;;;Black
+4
View File
@@ -28,3 +28,7 @@
{:ethereum (js/require "../resources/images/tokens/mainnet/ETH-network.png")
:optimism (js/require "../resources/images/tokens/mainnet/OP.png")
:arbitrum (js/require "../resources/images/tokens/mainnet/ARB.png")})
(defn get-network
[n]
(get networks n))
-8
View File
@@ -42,11 +42,3 @@
(defn cache-dir
[]
(.-CachesDirectoryPath ^js react-native-fs))
(defn copy-assets
[src dest]
(.copyFileAssets ^js react-native-fs src dest))
(defn main-bundle-path
[]
(.-MainBundlePath ^js react-native-fs))
-2
View File
@@ -10,5 +10,3 @@
(def circle (reagent/adapt-react-class Svg/Circle))
(def svgxml (reagent/adapt-react-class Svg/SvgXml))
(def g (reagent/adapt-react-class Svg/G))
(def linear-gradient (reagent/adapt-react-class Svg/LinearGradient))
(def stop (reagent/adapt-react-class Svg/Stop))
+9
View File
@@ -220,6 +220,15 @@
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
(rf/defn join
{:events [:communities/join]}
[_ community-id]
{:json-rpc/call [{:method "wakuext_joinCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::joined %])
:on-error #(log/error "failed to join community" community-id %)}]})
(rf/defn request-to-join
{:events [:communities/request-to-join]}
[_ community-id]
+2 -8
View File
@@ -1,6 +1,6 @@
(ns status-im.contact.core
(:require [status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(:require [utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))
(rf/defn open-contact-toggle-list
{:events [:contact.ui/start-group-chat-pressed]}
@@ -10,9 +10,3 @@
:group/selected-contacts #{}
:new-chat-name "")}
(navigation/navigate-to :contact-toggle-list nil)))
(defn displayed-photo
[{:keys [images]}]
(or (:large images)
(:thumbnail images)
(first images)))
+9 -10
View File
@@ -1,13 +1,13 @@
(ns status-im.multiaccounts.logout.core
(:require [native-module.core :as native-module]
[re-frame.core :as re-frame]
(:require [re-frame.core :as re-frame]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[native-module.core :as native-module]
[status-im.notifications.core :as notifications]
[utils.re-frame :as rf]
[status-im.wallet.core :as wallet]
[status-im2.common.keychain.events :as keychain]
[status-im2.db :as db]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[status-im2.db :as db]))
(re-frame/reg-fx
::logout
@@ -15,15 +15,14 @@
(native-module/logout)))
(rf/defn initialize-app-db
[{{:keys [keycard initials-avatar-font-file]
[{{:keys [keycard]
:biometric/keys [supported-type]
:network/keys [type]}
:db}]
{:db (assoc db/app-db
:network/type type
:initials-avatar-font-file initials-avatar-font-file
:keycard (dissoc keycard :secrets :pin :application-info)
:biometric/supported-type supported-type)})
:network/type type
:keycard (dissoc keycard :secrets :pin :application-info)
:biometric/supported-type supported-type)})
(rf/defn logout-method
{:events [::logout-method]}
+5 -8
View File
@@ -1,6 +1,5 @@
(ns status-im.multiaccounts.update.core
(:require [status-im.ethereum.ens :as ens]
[status-im.utils.types :as types]
(:require [status-im.utils.types :as types]
[status-im2.constants :as constants]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -20,12 +19,10 @@
display-name]} (:profile/profile db)
account (some #(and (= (:key-uid %) key-uid) %) raw-multiaccounts-from-status-go)]
(when-let [new-name (and account (or preferred-name display-name name))]
(rf/merge
cofx
{:db (assoc-in db [:profile/profile :ens-name?] (ens/is-valid-eth-name? new-name))
:json-rpc/call [{:method "multiaccounts_updateAccount"
:params [(assoc account :name new-name)]
:on-success #(log/debug "sent multiaccount update")}]}))))
(rf/merge cofx
{:json-rpc/call [{:method "multiaccounts_updateAccount"
:params [(assoc account :name new-name)]
:on-success #(log/debug "sent multiaccount update")}]}))))
(rf/defn multiaccount-update
"Takes effects (containing :db) + new multiaccount fields, adds all effects necessary for multiaccount update.
@@ -2,11 +2,8 @@
(:require [clojure.string :as string]
[quo.design-system.colors :as colors]
[quo.react-native :as rn]
[quo2.components.avatars.user-avatar.style :as user-avatar.style]
[quo2.core :as quo]
[quo2.theme :as theme]
[re-frame.core :as re-frame.core]
[status-im.ethereum.ens :as ens]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.styles :as styles]
[status-im.ui.components.icons.icons :as icons]
@@ -50,7 +47,7 @@
[rn/text {:style (:default-chat-icon-text styles)} emoji]]))
(defn profile-photo-plus-dot-view
[{:keys [public-key full-name customization-color photo-container photo-path community?]}]
[{:keys [public-key photo-container photo-path community?]}]
(let [photo-container (if (nil? photo-container)
styles/container-chat-list
photo-container)
@@ -58,28 +55,11 @@
dot-styles (visibility-status-utils/icon-visibility-status-dot
public-key
size)
dot-accessibility-label (:accessibility-label dot-styles)
text-style (styles/default-chat-icon-text size)]
dot-accessibility-label (:accessibility-label dot-styles)]
[rn/view
{:style photo-container
:accessibility-label :profile-photo}
(if (:fn photo-path)
;; temp support new media server avatar for old component
[photos/photo
{:uri ((:fn photo-path)
{:size size
:full-name full-name
:font-size (get text-style :font-size)
:background-color (user-avatar.style/customization-color customization-color
(theme/get-theme))
:indicator-size 0
:indicator-border 0
:indicator-color "#000000"
:color (get text-style :color)
:length 2
:ring? (not (ens/is-valid-eth-name? full-name))})}
{:size size}]
[photos/photo photo-path {:size size}])
[photos/photo photo-path {:size size}]
(when-not community?
[rn/view
{:style dot-styles
@@ -199,28 +179,14 @@
(defn profile-icon-view
[photo-path name color emoji edit? size override-styles public-key community?]
(let [styles (merge {:container {:width size :height size}
:size size
:chat-icon styles/chat-icon-profile
:default-chat-icon (styles/default-chat-icon-profile color size)
:default-chat-icon-text (if (string/blank? emoji)
(styles/default-chat-icon-text size)
(styles/emoji-chat-icon-text size))}
override-styles)
photo-path (if (:fn photo-path)
;; temp support new media server avatar for old component
{:uri ((:fn photo-path)
{:size size
:full-name name
:font-size (get-in styles [:default-chat-icon-text :font-size])
:background-color (get-in styles [:default-chat-icon :background-color])
:indicator-size 0
:indicator-border 0
:indicator-color "#000000"
:color (get-in styles [:default-chat-icon-text :color])
:length 2
:ring? (not (ens/is-valid-eth-name? name))})}
photo-path)]
(let [styles (merge {:container {:width size :height size}
:size size
:chat-icon styles/chat-icon-profile
:default-chat-icon (styles/default-chat-icon-profile color size)
:default-chat-icon-text (if (string/blank? emoji)
(styles/default-chat-icon-text size)
(styles/emoji-chat-icon-text size))}
override-styles)]
[rn/view (:container styles)
(if (and photo-path (seq photo-path))
[profile-photo-plus-dot-view
@@ -2,25 +2,23 @@
(:require [quo.core :as quo]
[quo.design-system.colors :as colors]
[re-frame.core :as re-frame]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.invite.views :as invite]
[status-im.ui.components.list.views :as list.views]
[status-im.ui.components.react :as react]
[utils.i18n :as i18n])
[status-im.ui.components.react :as react])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn contacts-list-item
[{:keys [public-key] :as contact}]
(let [{:keys [primary-name secondary-name customization-color]} contact]
(let [{:keys [primary-name secondary-name]} contact]
[quo/list-item
{:title primary-name
:subtitle secondary-name
:icon [chat-icon.screen/profile-photo-plus-dot-view
{:public-key public-key
:full-name primary-name
:customization-color (or customization-color :primary)
:photo-path (multiaccounts/displayed-photo contact)}]
{:public-key public-key
:photo-path (multiaccounts/displayed-photo contact)}]
:chevron true
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}]))
@@ -3,10 +3,9 @@
[quo.components.list.item :as list-item]
[quo.core :as quo]
[quo.design-system.colors :as colors]
[quo2.components.avatars.user-avatar.style :as user-avatar.style]
[quo2.theme :as theme]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
[status-im.ui.components.profile-header.view :as profile-header]
@@ -14,9 +13,8 @@
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.profile.components.sheets :as sheets]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[status-im2.constants :as constants]))
(defn actions
[{:keys [public-key added? blocked? ens-name mutual?] :as contact} muted?]
@@ -181,11 +179,9 @@
:as contact}
@(re-frame/subscribe
[:contacts/current-contact])
muted? @(re-frame/subscribe [:chats/muted
public-key])
{:keys [primary-name secondary-name customization-color]} contact
customization-color (or customization-color :primary)
{:keys [primary-name secondary-name]} contact
on-share #(re-frame/dispatch
[:show-popover
(merge
@@ -205,17 +201,14 @@
:on-press #(re-frame/dispatch [:navigate-back])}]}]
[:<>
[(profile-header/extended-header
{:on-press on-share
{:on-press on-share
:bottom-separator false
:title primary-name
:color
(user-avatar.style/customization-color customization-color
(theme/get-theme))
:photo (multiaccounts/displayed-photo contact)
:monospace (not ens-verified)
:subtitle secondary-name
:compressed-key compressed-key
:public-key public-key})]
:title primary-name
:photo (multiaccounts/displayed-photo contact)
:monospace (not ens-verified)
:subtitle secondary-name
:compressed-key compressed-key
:public-key public-key})]
[react/view
{:height 1 :background-color colors/gray-lighter :margin-top 8}]
[nickname-settings contact]
@@ -2,16 +2,16 @@
(:require [quo.core :as quo]
[quo.design-system.colors :as colors]
[quo.design-system.spacing :as spacing]
[quo2.components.avatars.user-avatar.style :as user-avatar.style]
[quo2.theme :as theme]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.ethereum.stateofus :as stateofus]
[utils.i18n :as i18n]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.components.common.common :as components.common]
[status-im.ui.components.copyable-text :as copyable-text]
[status-im.ui.components.list-selection :as list-selection]
[status-im.ui.components.profile-header.view :as profile-header]
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
[status-im.ui.components.react :as react]
[status-im.ui.screens.profile.user.edit-picture :as edit]
[status-im.ui.screens.profile.user.styles :as styles]
@@ -19,9 +19,7 @@
[status-im.utils.gfycat.core :as gfy]
[status-im.utils.universal-links.utils :as universal-links]
[status-im.utils.utils :as utils]
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
[status-im2.config :as config]
[utils.i18n :as i18n])
[status-im2.config :as config])
(:require-macros [status-im.utils.views :as views]))
(views/defview share-chat-key
@@ -192,12 +190,9 @@
(let [{:keys [public-key
compressed-key
ens-verified
preferred-name
key-uid]
preferred-name]
:as account}
@(re-frame/subscribe [:profile/multiaccount])
customization-color (or (:color @(re-frame/subscribe [:onboarding-2/profile]))
@(re-frame/subscribe [:profile/customization-color key-uid]))
on-share #(re-frame/dispatch [:show-popover
{:view :share-chat-key
:address (or compressed-key
@@ -218,8 +213,6 @@
:on-edit #(re-frame/dispatch [:bottom-sheet/show-sheet-old
{:content (edit/bottom-sheet
has-picture)}])
:color (user-avatar.style/customization-color customization-color
(theme/get-theme))
:title (multiaccounts/displayed-name account)
:photo (multiaccounts/displayed-photo account)
:monospace (not ens-verified)
+3 -3
View File
@@ -101,7 +101,7 @@
[react/nested-text
{:style {:color colors/gray}
:ellipsize-mode :middle
:number-of-lines 1} (i18n/label :t/to) " "
:number-of-lines 1} (i18n/label :t/To) " "
[{:style {:color colors/black}} (displayed-name contact)]]
[react/text {:style {:margin-top 6 :color colors/gray}}
(str fee " " fee-display-symbol " " (string/lower-case (i18n/label :t/network-fee)))])]
@@ -497,9 +497,9 @@
[react/view
[network-item]
[separator]])
[contact-item (i18n/label :t/from) from]
[contact-item (i18n/label :t/From) from]
[separator]
[contact-item (i18n/label :t/to) contact]
[contact-item (i18n/label :t/To) contact]
(when-not cancel?
[separator])
(when-not cancel?
@@ -138,7 +138,7 @@
:align-items :center
:margin-vertical 16}]
[quo/list-header
(i18n/label :t/from)]
(i18n/label :t/From)]
[react/view {:flex-direction :row :flex 1 :align-items :center}
[react/view {:flex 1}
[render-account from nil ::commands/set-selected-account]]]
@@ -204,7 +204,7 @@
[fiat-value amount-text token prices wallet-currency]
[components/separator]
[quo/list-header
(i18n/label :t/to)]
(i18n/label :t/To)]
[react/view {:flex-direction :row :flex 1 :align-items :center}
[react/view {:flex 1}
[render-account from token :wallet.request/set-field]]]]]
@@ -280,12 +280,12 @@
(when-not (or request? from-chat?)
[set-max token])
[components/separator]
[quo/list-header (i18n/label :t/from)]
[quo/list-header (i18n/label :t/From)]
[react/view {:flex-direction :row :flex 1 :align-items :center}
[react/view {:flex 1}
[render-account from token :wallet.send/set-field]]]
[quo/list-header
(i18n/label :t/to)]
(i18n/label :t/To)]
[react/view {:flex-direction :row :flex 1 :align-items :center}
[react/view {:flex 1}
[render-contact to from-chat?]]]]]
@@ -245,13 +245,13 @@
[react/view {:style styles/details-block}
[details-list-row :t/block block]
[details-list-row :t/hash hash]
[details-list-row :t/from
[details-list-row :t/From
[{:accessibility-label (if from-wallet :sender-name-text :sender-address-text)}
(or from-wallet from-contact from)]
(when (or from-wallet from-contact)
[{:accessibility-label :sender-address-text}
from])]
[details-list-row :t/to
[details-list-row :t/To
[{:accessibility-label (if to-wallet :recipient-name-text :recipient-address-text)}
(or to-wallet to-contact to)]
(when (or to-wallet to-contact)
-4
View File
@@ -1,4 +0,0 @@
(ns status-im.utils.pixel-ratio
(:require ["react-native" :as rn]))
(def ratio (rn/PixelRatio.get))
@@ -14,7 +14,7 @@
:margin-vertical 8})
(defn sheet
[{:keys [top bottom]} window-height theme padding-bottom-override selected-item shell?]
[{:keys [top bottom]} window-height theme padding-bottom-override shell?]
{:position :absolute
:max-height (- window-height top)
:z-index 1
@@ -23,19 +23,13 @@
:right 0
:border-top-left-radius 20
:border-top-right-radius 20
:overflow (when-not selected-item :hidden)
:overflow (when shell? :hidden)
:flex 1
:padding-bottom (or padding-bottom-override (+ bottom 8))
:background-color (if shell?
:transparent
(colors/theme-colors colors/white colors/neutral-95 theme))})
(def gradient-bg
{:position :absolute
:top 0
:left 0
:right 0})
(def shell-bg
{:position :absolute
:background-color (if platform/ios? colors/white-opa-5 colors/neutral-100-opa-90)
+3 -9
View File
@@ -1,8 +1,7 @@
(ns status-im2.common.bottom-sheet.view
(:require [oops.core :as oops]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[quo2.theme :as theme]
[react-native.blur :as blur]
[react-native.core :as rn]
[react-native.gesture :as gesture]
@@ -58,8 +57,7 @@
[_ _]
(let [sheet-height (reagent/atom 0)]
(fn [{:keys [hide? insets theme]}
{:keys [content selected-item padding-bottom-override on-close shell?
gradient-cover? customization-color]}]
{:keys [content selected-item padding-bottom-override on-close shell?]}]
(let [{window-height :height} (rn/get-window)
bg-opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value window-height)
@@ -90,12 +88,8 @@
window-height
theme
padding-bottom-override
selected-item
shell?))
:on-layout #(reset! sheet-height (oops/oget % "nativeEvent" "layout" "height"))}
(when gradient-cover?
[rn/view {:style style/gradient-bg}
[quo/gradient-cover {:customization-color customization-color}]])
(when shell?
[blur/ios-view {:style style/shell-bg}])
(when selected-item
@@ -112,4 +106,4 @@
[args sheet]
[:f> f-view args sheet])
(def view (quo.theme/with-theme internal-view))
(def view (theme/with-theme internal-view))
@@ -1,9 +1,9 @@
(ns status-im2.common.confirmation-drawer.view
(:require [quo2.core :as quo]
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.confirmation-drawer.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn avatar
@@ -11,12 +11,12 @@
(if group-chat
[quo/group-avatar
{:customization-color color
:size :size/s-20}]
:size :x-small}]
[quo/user-avatar
{:full-name display-name
:profile-picture photo-path
:size :xxs
:status-indicator? false}]))
{:full-name display-name
:profile-picture photo-path
:size :xxs
:status-indicator false}]))
(defn extra-action-view
[extra-action extra-text extra-action-selected?]
@@ -41,7 +41,12 @@
(= contact-name-by-identity
nil) name
:else contact-name-by-identity)
photo-path (or profile-picture (rf/sub [:chats/photo-path id]))]
contact (when-not group-chat
(rf/sub [:contacts/contact-by-address
id]))
photo-path (or profile-picture
(when-not (empty? (:images contact))
(rf/sub [:chats/photo-path id])))]
[rn/view
{:style {:margin-horizontal 20}
:accessibility-label accessibility-label}
-17
View File
@@ -1,17 +0,0 @@
(ns status-im2.common.font
(:require
[clojure.string :as string]
[re-frame.core :as re-frame]
utils.image-server
[utils.re-frame :as rf]))
(re-frame/reg-fx
:font/get-font-file-for-initials-avatar
(fn [callback]
(utils.image-server/get-font-file-ready callback)))
(rf/defn init-abs-root-path
{:events [:font/init-font-file-for-initials-avatar]}
[{:keys [db]} initials-avatar-font-file]
(when-not (string/blank? initials-avatar-font-file)
{:db (assoc db :initials-avatar-font-file initials-avatar-font-file)}))
+6 -3
View File
@@ -60,7 +60,10 @@
{:accessibility-label :open-profile
:style style/left-section}
[quo/user-avatar
(merge {:size :small :online? online?} avatar)]]]))
(merge {:status-indicator? true
:size :small
:online? online?}
avatar)]]]))
(defn connectivity-sheet
[]
@@ -102,12 +105,12 @@
:on-press #(dispatch-and-chill [:open-modal :share-shell] 1000)})
:i/qr-code]
[rn/view
[unread-indicator]
[quo/button
(merge button-common-props
{:accessibility-label :open-activity-center-button
:on-press #(rf/dispatch [:activity-center/open])})
:i/activity-center]
[unread-indicator]]]))
:i/activity-center]]]))
;; TODO: should be moved to quo2 https://github.com/status-im/status-mobile/issues/16964
(defn top-nav
+3 -4
View File
@@ -1,11 +1,11 @@
(ns status-im2.common.log
(:require [clojure.string :as string]
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[status-im.utils.types :as types]
[status-im2.config :as config]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[native-module.core :as native-module]
[status-im.utils.types :as types]))
(def logs-queue (atom #queue []))
(def max-log-entries 1000)
@@ -28,7 +28,6 @@
:mobile-system? false
:log-level level
:callback handle-error}]
(log/merge-config! {:ns-whitelist ["*"]})
(if (string/blank? level)
(native-module/init-status-go-logging (merge logging-params {:log-level "WARN"}))
(do
+4 -6
View File
@@ -6,7 +6,7 @@
[status-im2.common.parallax.style :as style]))
(defn f-sensor-animated-video
[{:keys [offset stretch order source disable-parallax? enable-looping?]}]
[{:keys [offset stretch order source disable-parallax?]}]
(let [double-stretch (* 2 stretch)
{window-width :width
window-height :height} (rn/get-window)
@@ -25,15 +25,14 @@
image-style]}
[transparent-video/view
{:source source
:style style/video
:loop enable-looping?}]])))
:style style/video}]])))
(defn sensor-animated-video
[props]
[:f> f-sensor-animated-video props])
(defn f-video
[{:keys [layers disable-parallax? offset stretch container-style enable-looping?]
[{:keys [layers disable-parallax? offset stretch container-style]
:or {offset 50
stretch 0}}]
[rn/view
@@ -45,8 +44,7 @@
:offset offset
:stretch stretch
:order (inc idx)
:disable-parallax? disable-parallax?
:enable-looping? enable-looping?}])
:disable-parallax? disable-parallax?}])
layers)])
(defn video
@@ -16,11 +16,11 @@
[rn/view {:padding-horizontal 20}
[quo/text {:size :heading-1 :weight :semi-bold}
(i18n/label :t/enter-password)]
[quo/user-avatar-tag
{:size :small
:style {:margin-top 8 :margin-bottom 20}}
(multiaccounts/displayed-name account)
(multiaccounts/displayed-photo account)]
[rn/view {:style {:margin-top 8 :margin-bottom 20}}
[quo/context-tag
{:size 24
:profile-picture (multiaccounts/displayed-photo account)
:full-name (multiaccounts/displayed-name account)}]]
[quo/input
{:type :password
:label (i18n/label :t/profile-password)
+3 -10
View File
@@ -11,17 +11,10 @@
(defn toast
[toast-id]
(let [{:keys [type user-public-key] :as toast-opts} (rf/sub [:toasts/toast toast-id])
profile-picture (when user-public-key
(rf/sub [:chats/photo-path user-public-key]))
toast-opts-with-profile-picture (if profile-picture
(assoc-in toast-opts
[:user :profile-picture]
profile-picture)
toast-opts)]
(let [{:keys [type] :as toast-opts} (rf/sub [:toasts/toast toast-id])]
(if (= type :notification)
[quo/notification toast-opts-with-profile-picture]
[quo/toast toast-opts-with-profile-picture])))
[quo/notification toast-opts]
[quo/toast toast-opts])))
(defn f-container
[toast-id]
-8
View File
@@ -345,11 +345,3 @@
(def ^:const onboarding-modal-animation-duration 300)
(def ^:const onboarding-modal-animation-delay 400)
(def ^:const initials-avatar-font-conf
"we pass absolute font file path and uppercase ratio to status-go for media
server to serve initials avatar image
`:uppercase-ratio` is uppercase-height/line-height for Inter-Medium"
{:ios "Inter-Medium.otf"
:android "Inter-Medium.ttf"
:uppercase-ratio 0.603861228044709})
@@ -2,9 +2,10 @@
(:require
[clojure.string :as string]
[quo2.core :as quo]
[react-native.clipboard :as clipboard]
[react-native.core :as rn]
[react-native.clipboard :as clipboard]
[reagent.core :as reagent]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.qr-scanner.core :as qr-scanner]
[status-im2.contexts.add-new-contact.style :as style]
[utils.debounce :as debounce]
@@ -14,8 +15,8 @@
(defn found-contact
[public-key]
(let [{:keys [primary-name compressed-key]} (rf/sub [:contacts/contact-by-identity public-key])
photo-path (rf/sub [:chats/photo-path public-key])]
(let [{:keys [primary-name compressed-key]
:as contact} (rf/sub [:contacts/contact-by-identity public-key])]
(when primary-name
[rn/view style/found-user
[quo/text (style/text-description)
@@ -23,7 +24,7 @@
[rn/view (style/found-user-container)
[quo/user-avatar
{:full-name primary-name
:profile-picture photo-path
:profile-picture (multiaccounts/displayed-photo contact)
:size :small
:status-indicator? false}]
[rn/view style/found-user-text
@@ -65,16 +65,16 @@
:i/arrow-up]])
(defn send-button
[props {:keys [text-value] :as state} animations window-height images? edit btn-opacity]
(let [z-index (reagent/atom (if (and (empty? @text-value) (not images?)) 0 1))]
[props {:keys [text-value] :as state} animations window-height images? edit]
(let [btn-opacity (reanimated/use-shared-value 0)
z-index (reagent/atom (if (and (empty? @text-value) (not images?)) 0 1))]
[:f> f-send-button props state animations window-height images? btn-opacity z-index edit]))
(defn disabled-audio-button
[opacity]
[reanimated/view {:style (reanimated/apply-animations-to-style {:opacity opacity} {})}
[quo/composer-button
{:on-press #(js/alert "to be implemented")
:icon :i/audio}]])
[]
[quo/composer-button
{:on-press #(js/alert "to be implemented")
:icon :i/audio}])
(defn audio-button
[{:keys [record-reset-fn input-ref]}
@@ -169,8 +169,8 @@
[quo/composer-button
{:on-press #(go-to-camera images-count)
:icon :i/camera
:container-style {:margin-right 12}}]))
:container-style {:margin-right 12}}
]))
(defn open-photo-selector
[{:keys [input-ref]}
@@ -212,18 +212,16 @@
(defn view
[props state animations window-height insets {:keys [edit images]}]
(let [send-btn-opacity (reanimated/use-shared-value 0)
audio-btn-opacity (reanimated/interpolate send-btn-opacity [0 1] [1 0])]
[rn/view {:style style/actions-container}
[rn/view
{:style {:flex-direction :row
:display (if @(:recording? state) :none :flex)}}
[camera-button]
[image-button props animations insets]
[reaction-button]
[format-button]]
[:f> send-button props state animations window-height images edit send-btn-opacity]
(when (and (not edit) (not images))
;; TODO(alwx): needs to be replaced with an `audio-button` later.
;; See https://github.com/status-im/status-mobile/issues/16084 for more details.
[:f> disabled-audio-button audio-btn-opacity])]))
[rn/view {:style style/actions-container}
[rn/view
{:style {:flex-direction :row
:display (if @(:recording? state) :none :flex)}}
[camera-button]
[image-button props animations insets]
[reaction-button]
[format-button]]
[:f> send-button props state animations window-height images edit]
(when (and (not edit) (not images))
;; TODO(alwx): needs to be replaced with an `audio-button` later.
;; See https://github.com/status-im/status-mobile/issues/16084 for more details.
[disabled-audio-button])])
@@ -1,16 +1,16 @@
(ns status-im2.contexts.chat.composer.reply.view
(:require [clojure.string :as string]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im2.contexts.chat.composer.constants :as constants]
[utils.i18n :as i18n]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[react-native.reanimated :as reanimated]
[status-im.ethereum.stateofus :as stateofus]
[status-im2.constants :as constant]
[status-im2.contexts.chat.composer.constants :as constants]
[status-im.ethereum.stateofus :as stateofus]
[utils.re-frame :as rf]
[status-im2.contexts.chat.composer.reply.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[react-native.linear-gradient :as linear-gradient]))
(defn get-quoted-text-with-mentions
[parsed-text]
@@ -63,14 +63,14 @@
(defn reply-from
[{:keys [from contact-name current-public-key]}]
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
photo-path (rf/sub [:chats/photo-path from])]
contact (rf/sub [:contacts/contact-by-address from])
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))]
[rn/view {:style style/reply-from}
[quo/user-avatar
{:full-name display-name
:profile-picture photo-path
:status-indicator? false
:size :xxxs
:ring? false}]
:size :xxxs}]
[quo/text
{:weight :semi-bold
:size :paragraph-2
@@ -14,12 +14,6 @@
:shadow-offset {:width 0 :height (colors/theme-colors -4 -8)}}
{:elevation (if @focused? 10 0)}))
(def composer-sheet-and-jump-to-container
{:position :absolute
:bottom 0
:left 0
:right 0})
(defn sheet-container
[insets {:keys [focused?]} {:keys [container-opacity]}]
(reanimated/apply-animations-to-style
@@ -28,6 +22,10 @@
{:border-top-left-radius 20
:border-top-right-radius 20
:padding-horizontal 20
:position :absolute
:bottom 0
:left 0
:right 0
:background-color (colors/theme-colors colors/white colors/neutral-95)
:z-index 3
:padding-bottom (:bottom insets)}
@@ -89,7 +87,8 @@
:right 0
:bottom 0
:height window-height
:background-color colors/neutral-95-opa-70}))
:background-color colors/neutral-95-opa-70
:z-index 1}))
(defn blur-container
[height focused?]
@@ -111,11 +110,18 @@
:blur-type (colors/theme-colors :light :dark)
:blur-amount 20})
(defn shell-container
[bottom translate-y]
(reanimated/apply-animations-to-style
{:bottom bottom ; we use height of the input directly as bottom position
:transform [{:translate-y translate-y}]}
{:position :absolute
:left 0
:right 0}))
(defn shell-button
[translate-y opacity]
(reanimated/apply-animations-to-style
{:transform [{:translate-y translate-y}]
:opacity opacity}
{:position :absolute
:top 0
:align-self :center}))
{}))
@@ -5,7 +5,9 @@
[react-native.core :as rn]
[status-im2.config :as config]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[status-im2.contexts.chat.composer.style :as style]
[status-im2.contexts.chat.composer.utils :as utils]
[status-im2.contexts.chat.messages.list.view :as messages.list]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -25,8 +27,12 @@
[:f> f-blur-view layout-height focused?])
(defn- f-shell-button
[{:keys [focused?]}]
[{:keys [maximized? focused?]} {:keys [height]} {:keys [reply edit]}]
(let [customization-color (rf/sub [:profile/customization-color])
insets (safe-area/get-insets)
extra-height (utils/calc-top-content-height reply edit)
neg-y (utils/calc-shell-neg-y insets maximized? extra-height)
y-container (reanimated/use-shared-value neg-y)
hide-shell? (or @focused? @messages.list/show-floating-scroll-down-button)
y-shell (reanimated/use-shared-value (if hide-shell? 35 0))
opacity (reanimated/use-shared-value (if hide-shell? 0 1))]
@@ -35,7 +41,9 @@
(reanimated/animate opacity (if hide-shell? 0 1))
(reanimated/animate y-shell (if hide-shell? 35 0)))
[@focused? @messages.list/show-floating-scroll-down-button])
[:<>
(rn/use-effect #(reanimated/animate y-container neg-y) [reply edit])
[reanimated/view
{:style (style/shell-container height y-container)}
[reanimated/view
{:style (style/shell-button y-shell opacity)}
[quo/floating-shell-button
@@ -46,12 +54,11 @@
(rf/dispatch [:shell/navigate-to-jump-to]))
:customization-color customization-color
:label (i18n/label :t/jump-to)
:style {:align-self :center}}}
{}]]
:style {:align-self :center}}} {}]]
[quo/floating-shell-button
(when @messages.list/show-floating-scroll-down-button
{:scroll-to-bottom {:on-press messages.list/scroll-to-bottom}})
{}]]))
{:bottom 24}]]))
(defn shell-button
[state animations subs]
+48 -50
View File
@@ -66,64 +66,62 @@
(effects/link-previews props state animations subs)
(effects/images props state animations subs)
[:<>
[sub-view/shell-button state animations subs]
(when chat-screen-loaded?
[mentions/view props state animations max-height cursor-pos
(:images subs)
(:link-previews? subs)
(:reply subs)
(:edit subs)])
[rn/view
{:style style/composer-sheet-and-jump-to-container}
[sub-view/shell-button state]
[gesture/gesture-detector
{:gesture (drag-gesture/drag-gesture props state animations subs dimensions keyboard-shown)}
[reanimated/view
{:style (style/sheet-container insets state animations)
:on-layout #(handler/layout % state blur-height)}
[sub-view/bar]
[gesture/gesture-detector
{:gesture (drag-gesture/drag-gesture props state animations subs dimensions keyboard-shown)}
[reanimated/view
{:style (style/sheet-container insets state animations)
:on-layout #(handler/layout % state blur-height)}
[sub-view/bar]
(when chat-screen-loaded?
[:<>
[reply/view state]
[edit/view state]])
[reanimated/touchable-opacity
{:active-opacity 1
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
:style (style/input-container (:height animations) max-height)
:accessibility-label :message-input-container}
[rn/selectable-text-input
{:ref #(reset! (:selectable-input-ref props) %)
:menu-items @(:menu-items state)
:style (style/input-view state)}
[rn/text-input
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus #(handler/focus props state animations dimensions)
:on-blur #(handler/blur state animations dimensions subs)
:on-content-size-change #(handler/content-size-change %
state
animations
subs
dimensions
(or keyboard-shown (:edit subs)))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % props state)
:on-selection #(selection/on-selection % props state)
:keyboard-appearance (theme/theme-value :light :dark)
:max-height max-height
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-30 colors/neutral-50)
:style (style/input-text props state subs max-height)
:max-length constants/max-text-size
:accessibility-label :chat-message-input}]]
(when chat-screen-loaded?
[:<>
[reply/view state]
[edit/view state]])
[reanimated/touchable-opacity
{:active-opacity 1
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
:style (style/input-container (:height animations) max-height)
:accessibility-label :message-input-container}
[rn/selectable-text-input
{:ref #(reset! (:selectable-input-ref props) %)
:menu-items @(:menu-items state)
:style (style/input-view state)}
[rn/text-input
{:ref #(reset! (:input-ref props) %)
:default-value @(:text-value state)
:on-focus #(handler/focus props state animations dimensions)
:on-blur #(handler/blur state animations dimensions subs)
:on-content-size-change #(handler/content-size-change %
state
animations
subs
dimensions
(or keyboard-shown (:edit subs)))
:on-scroll #(handler/scroll % props state animations dimensions)
:on-change-text #(handler/change-text % props state)
:on-selection-change #(handler/selection-change % props state)
:on-selection #(selection/on-selection % props state)
:keyboard-appearance (theme/theme-value :light :dark)
:max-height max-height
:max-font-size-multiplier 1
:multiline true
:placeholder (i18n/label :t/type-something)
:placeholder-text-color (colors/theme-colors colors/neutral-30 colors/neutral-50)
:style (style/input-text props state subs max-height)
:max-length constants/max-text-size
:accessibility-label :chat-message-input}]]
(when chat-screen-loaded?
[:<>
[gradients/view props state animations show-bottom-gradient?]
[link-preview/view]
[images/images-list]])]
[:f> actions/view props state animations window-height insets subs]]]]]))
[gradients/view props state animations show-bottom-gradient?]
[link-preview/view]
[images/images-list]])]
[actions/view props state animations window-height insets subs]]]]))
(defn composer
[insets]
@@ -169,7 +169,7 @@
:padding-horizontal 20}}
[quo/group-avatar
{:customization-color color
:size :size/s-32}]
:size :small}]
[quo/text
{:weight :semi-bold
:size :heading-1
@@ -1,16 +1,16 @@
(ns status-im2.contexts.chat.home.chat-list-item.view
(:require [clojure.string :as string]
[quo2.components.icon :as icons]
[quo2.core :as quo]
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im2.common.home.actions.view :as actions]
[status-im2.constants :as constants]
[status-im2.contexts.chat.home.chat-list-item.style :as style]
[utils.datetime :as datetime]
[utils.debounce :as debounce]
[status-im2.common.home.actions.view :as actions]
[status-im2.contexts.chat.home.chat-list-item.style :as style]
[utils.re-frame :as rf]
[status-im2.constants :as constants]
[clojure.string :as string]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[quo2.components.icon :as icons]))
(def max-subheader-length 50)
@@ -201,17 +201,17 @@
[{:keys [contact chat-id full-name color muted?]}]
(if contact ; `contact` is passed when it's not a group chat
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])]
photo-path (rf/sub [:chats/photo-path chat-id])
image-key (if (seq (:images contact)) :profile-picture :ring-background)]
[quo/user-avatar
(cond-> {:full-name full-name
:size :small
:online? online?
:profile-picture photo-path}
muted?
(assoc :ring? false))])
{:full-name full-name
:size :small
:online? online?
image-key photo-path
:muted? muted?}])
[quo/group-avatar
{:customization-color color
:size :size/s-32}]))
:size :small}]))
(defn notification
[{:keys [muted group-chat unviewed-messages-count unviewed-mentions-count]}]
+13 -22
View File
@@ -1,6 +1,6 @@
(ns status-im2.contexts.chat.home.view
(:require [oops.core :as oops]
[quo2.theme :as quo.theme]
[quo2.theme :as theme]
[re-frame.core :as re-frame]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
@@ -27,32 +27,31 @@
(filter k)
(sort-by :timestamp >))))
(defn empty-state-content
[theme]
(def empty-state-content
#:tab{:contacts
{:title (i18n/label :t/no-contacts)
:description (i18n/label :t/no-contacts-description)
:image (resources/get-image
(quo.theme/theme-value :no-contacts-light :no-contacts-dark theme))}
(theme/theme-value :no-contacts-light :no-contacts-dark))}
:groups
{:title (i18n/label :t/no-group-chats)
:description (i18n/label :t/no-group-chats-description)
:image (resources/get-image
(quo.theme/theme-value :no-group-chats-light :no-group-chats-dark theme))}
(theme/theme-value :no-group-chats-light :no-group-chats-dark))}
:recent
{:title (i18n/label :t/no-messages)
:description (i18n/label :t/no-messages-description)
:image (resources/get-image
(quo.theme/theme-value :no-messages-light :no-messages-dark theme))}})
(theme/theme-value :no-messages-light :no-messages-dark))}})
(defn chats
[{:keys [theme selected-tab set-scroll-ref scroll-shared-value]}]
[{:keys [selected-tab set-scroll-ref scroll-shared-value]}]
(let [unfiltered-items (rf/sub [:chats-stack-items])
items (filter-and-sort-items-by-tab selected-tab unfiltered-items)]
(if (empty? items)
[common.home/empty-state-image
{:selected-tab selected-tab
:tab->content (empty-state-content theme)}]
:tab->content empty-state-content}]
[reanimated/flat-list
{:ref set-scroll-ref
:key-fn #(or (:chat-id %) (:public-key %) (:id %))
@@ -82,12 +81,12 @@
item]))
(defn contacts
[{:keys [theme pending-contact-requests set-scroll-ref scroll-shared-value]}]
[{:keys [pending-contact-requests set-scroll-ref scroll-shared-value]}]
(let [items (rf/sub [:contacts/active-sections])]
(if (and (empty? items) (empty? pending-contact-requests))
[common.home/empty-state-image
{:selected-tab :tab/contacts
:tab->content (empty-state-content theme)}]
:tab->content empty-state-content}]
[rn/section-list
{:ref set-scroll-ref
:key-fn :public-key
@@ -118,8 +117,8 @@
:title (i18n/label :t/invite-friends-to-status)
:description (i18n/label :t/share-invite-link)}})
(defn- f-view-internal
[{:keys [theme]}]
(defn home
[]
(let [scroll-ref (atom nil)
set-scroll-ref #(reset! scroll-ref %)]
(fn []
@@ -132,13 +131,11 @@
[contacts
{:pending-contact-requests pending-contact-requests
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}]
:scroll-shared-value scroll-shared-value}]
[chats
{:selected-tab selected-tab
:set-scroll-ref set-scroll-ref
:scroll-shared-value scroll-shared-value
:theme theme}])
:scroll-shared-value scroll-shared-value}])
[:f> common.home.banner/animated-banner
{:content banner-data
:customization-color customization-color
@@ -156,9 +153,3 @@
:selected-tab selected-tab
:on-tab-change (fn [tab] (rf/dispatch [:messages-home/select-tab tab]))
:scroll-shared-value scroll-shared-value}]]))))
(defn- internal-chats-home-view
[params]
[:f> f-view-internal params])
(def view (quo.theme/with-theme internal-chats-home-view))
@@ -1,19 +1,21 @@
(ns status-im2.contexts.chat.messages.avatar.view
(:require [quo2.core :as quo]
(:require [utils.re-frame :as rf]
[react-native.core :as rn]
[utils.re-frame :as rf]))
[quo2.core :as quo]))
(defn avatar
[public-key size]
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))
photo-path (rf/sub [:chats/photo-path public-key])
contact (rf/sub [:contacts/contact-by-address public-key])
photo-path (when (seq (:images contact)) (rf/sub [:chats/photo-path public-key]))
online? (rf/sub [:visibility-status-updates/online? public-key])]
[rn/view {:style {:padding-top 2}}
[rn/touchable-opacity
{:active-opacity 1
:on-press #(rf/dispatch [:chat.ui/show-profile public-key])}
[quo/user-avatar
{:full-name display-name
:profile-picture photo-path
:online? online?
:size size}]]]))
{:full-name display-name
:profile-picture photo-path
:status-indicator? true
:online? online?
:size size}]]]))
@@ -3,7 +3,6 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[quo2.core :as quo]
[status-im2.contexts.shell.jump-to.constants :as jump-to.constants]
[quo2.components.drawers.permission-context.view :as permission-context]
[status-im2.constants :as constants]
[react-native.core :as rn]
@@ -38,13 +37,13 @@
(= contact-request-state
constants/contact-request-state-sent)
(i18n/label :t/contact-request-chat-pending))]]
[quo/floating-shell-button
{:jump-to
{:on-press (fn []
(when config/shell-navigation-disabled?
(rf/dispatch [:chat/close true]))
(rf/dispatch [:shell/navigate-to-jump-to]))
:customization-color customization-color
:label (i18n/label :t/jump-to)}}
{:position :absolute
:top (- jump-to.constants/floating-shell-button-height)}]]))
[rn/view {:position :absolute :top -36 :align-self :center}
[quo/floating-shell-button
{:jump-to
{:on-press (fn []
(when config/shell-navigation-disabled?
(rf/dispatch [:chat/close true]))
(rf/dispatch [:shell/navigate-to-jump-to]))
:customization-color customization-color
:label (i18n/label :t/jump-to)}}
{}]]]))
@@ -28,7 +28,9 @@
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)]))
photo-path (rf/sub [:chats/photo-path (or deleted-by from)])]
contact (rf/sub [:contacts/contact-by-address (or deleted-by from)])
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path (or deleted-by from)]))]
[quo/system-message
{:type :deleted
:timestamp timestamp-str
@@ -13,14 +13,3 @@
(and (not in-pinned-view?) (or mentioned pinned-by last-in-group?))
(assoc :margin-top 8))))
(defn user-message-content
[{:keys [first-in-group? outgoing outgoing-status]}]
{:border-radius 16
:padding-horizontal 8
:padding-vertical (if first-in-group?
8
4)
:opacity (if (and outgoing (= outgoing-status :sending))
0.5
1)})
@@ -134,10 +134,9 @@
:message-sending
:message-sent)
:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
:style (style/user-message-content
{:first-in-group? (:first-in-group? message-data)
:outgoing outgoing
:outgoing-status outgoing-status})
:style {:border-radius 16
:padding 8
:opacity (if (and outgoing (= outgoing-status :sending)) 0.5 1)}
:on-press (fn []
(if (and platform/ios? keyboard-shown?)
(rn/dismiss-keyboard!)
@@ -1,30 +1,30 @@
(ns status-im2.contexts.chat.messages.list.view
(:require [oops.core :as oops]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.background-timer :as background-timer]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[quo2.foundations.colors :as colors]
[react-native.reanimated :as reanimated]
[status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.contexts.chat.messages.list.state :as state]
[status-im2.contexts.chat.messages.list.style :as style]
[status-im2.contexts.shell.jump-to.constants :as jump-to.constants]
[status-im2.contexts.chat.composer.constants :as composer.constants]
[status-im2.contexts.chat.messages.navigation.style :as navigation.style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[status-im2.contexts.chat.composer.constants :as composer.constants]
[utils.re-frame :as rf]
[utils.i18n :as i18n]))
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
(defonce ^:const loading-indicator-extra-spacing 250)
(defonce ^:const loading-indicator-page-loading-height 100)
(defonce ^:const scroll-animation-input-range [50 125])
(defonce ^:const spacing-between-composer-and-content 64)
(defonce ^:const min-message-height 32)
(defonce messages-list-ref (atom nil))
@@ -129,14 +129,15 @@
[insets able-to-send-message?]
[rn/view
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:margin-bottom (when platform/ios? (- style/overscroll-cover-height))
:margin-bottom (- 0
(:top insets)
(when platform/ios? style/overscroll-cover-height))
:height (+ (if able-to-send-message?
(+ composer.constants/composer-default-height
jump-to.constants/floating-shell-button-height
spacing-between-composer-and-content
(:bottom insets))
(- 70 (:bottom insets)))
(when platform/ios?
(- style/overscroll-cover-height (:top insets))))}])
(when platform/ios? style/overscroll-cover-height))}])
(defn f-list-footer-avatar
[{:keys [scroll-y display-name online? profile-picture]}]
@@ -202,7 +203,8 @@
online? (rf/sub [:visibility-status-updates/online? chat-id])
contact (when-not group-chat
(rf/sub [:contacts/contact-by-address chat-id]))
photo-path (rf/sub [:chats/photo-path chat-id])
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path chat-id]))
border-animation (reanimated/interpolate scroll-y
[30 125]
[14 0]
@@ -5,15 +5,15 @@
[re-frame.db]
[react-native.blur :as blur]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[status-im2.common.home.actions.view :as actions]
[status-im2.config :as config]
[status-im2.constants :as constants]
[react-native.reanimated :as reanimated]
[react-native.platform :as platform]
[status-im2.contexts.chat.messages.navigation.style :as style]
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner]
[status-im2.constants :as constants]
[utils.re-frame :as rf]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[status-im2.common.home.actions.view :as actions]))
(defn f-view
[{:keys [scroll-y]}]
@@ -27,7 +27,10 @@
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
(str emoji " " chat-name))
online? (rf/sub [:visibility-status-updates/online? chat-id])
photo-path (rf/sub [:chats/photo-path chat-id])
contact (when-not group-chat
(rf/sub [:contacts/contact-by-address chat-id]))
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path chat-id]))
opacity-animation (reanimated/interpolate scroll-y
[style/navigation-bar-height
(+ style/navigation-bar-height 30)]
@@ -12,6 +12,6 @@
:align-items :center
:justify-content :space-between})
(def context-tag
(def community-tag
{:margin-right :auto
:margin-top 8})
@@ -14,7 +14,10 @@
:weight :semi-bold
:size :heading-1}
title]]
[quo/context-tag
{:style style/context-tag}
(:thumbnail images) name]
[rn/view {:style style/community-tag}
[quo/context-tag
{:type :community
:size 24
:community-logo (:thumbnail images)
:community-name name}]]
children]))
@@ -37,11 +37,12 @@
:weight :semi-bold
:size :heading-1}
(request-to-join-text open?)]]
[quo/context-tag
{:style
{:margin-right :auto
:margin-top 8}}
(:thumbnail images) name]
[rn/view {:style {:margin-right :auto :margin-top 8}}
[quo/context-tag
{:type :community
:size 24
:community-logo (:thumbnail images)
:community-name name}]]
[quo/text
{:style {:margin-top 24}
:accessibility-label :communities-rules-title
@@ -67,7 +68,7 @@
:on-press (fn []
(if can-join?
(do
(rf/dispatch [:communities/request-to-join id])
(rf/dispatch [:communities/join id])
(rf/dispatch [:navigate-back]))
(do (and can-request-access?
(not pending?)
@@ -1,7 +1,7 @@
(ns status-im2.contexts.communities.home.view
(:require [oops.core :as oops]
[quo2.core :as quo]
[quo2.theme :as quo.theme]
[quo2.theme :as theme]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[status-im2.common.home.banner.view :as common.home.banner]
@@ -37,9 +37,7 @@
{:id :pending :label (i18n/label :t/pending) :accessibility-label :pending-tab}
{:id :opened :label (i18n/label :t/opened) :accessibility-label :opened-tab}])
(defn empty-state-content
[theme]
(def empty-state-content
{:joined
{:title (i18n/label :t/no-communities)
:description [:<>
@@ -47,21 +45,18 @@
(i18n/label :t/no-communities-description-strikethrough)]
" "
(i18n/label :t/no-communities-description)]
:image (resources/get-image (quo.theme/theme-value :no-communities-light
:no-communities-dark
theme))}
:image (resources/get-image (theme/theme-value :no-communities-light
:no-communities-dark))}
:pending
{:title (i18n/label :t/no-pending-communities)
:description (i18n/label :t/no-pending-communities-description)
:image (resources/get-image (quo.theme/theme-value :no-pending-communities-light
:no-pending-communities-dark
theme))}
:image (resources/get-image (theme/theme-value :no-pending-communities-light
:no-pending-communities-dark))}
:opened
{:title (i18n/label :t/no-opened-communities)
:description (i18n/label :t/no-opened-communities-description)
:image (resources/get-image (quo.theme/theme-value :no-opened-communities-light
:no-opened-communities-dark
theme))}})
:image (resources/get-image (theme/theme-value :no-opened-communities-light
:no-opened-communities-dark))}})
(def ^:private banner-data
{:title-props
@@ -75,8 +70,8 @@
:banner (resources/get-image :discover)
:accessibility-label :communities-home-discover-card}})
(defn- f-view-internal
[{:keys [theme]}]
(defn home
[]
(let [flat-list-ref (atom nil)
set-flat-list-ref #(reset! flat-list-ref %)]
(fn []
@@ -92,7 +87,7 @@
(if (empty? selected-items)
[common.home/empty-state-image
{:selected-tab selected-tab
:tab->content (empty-state-content theme)}]
:tab->content empty-state-content}]
[reanimated/flat-list
{:ref set-flat-list-ref
:key-fn :id
@@ -114,9 +109,3 @@
:selected-tab selected-tab
:on-tab-change (fn [tab] (rf/dispatch [:communities/select-tab tab]))
:scroll-shared-value scroll-shared-value}]]))))
(defn- internal-communities-home-view
[params]
[:f> f-view-internal params])
(def view (quo.theme/with-theme internal-communities-home-view))
@@ -256,7 +256,7 @@
[description]
[quo/text
{:accessibility-label :community-description-text
:number-of-lines 4
:number-of-lines 2
:ellipsize-mode :tail
:weight :regular
:size :paragraph-1
@@ -367,4 +367,4 @@
:customization-color customization-color
:label (i18n/label :t/jump-to)}}
{:position :absolute
:bottom 34}]]))
:bottom 41}]]))
@@ -1,8 +1,8 @@
(ns status-im2.contexts.contacts.drawers.nickname-drawer.view
(:require [clojure.string :as string]
[quo2.foundations.colors :as colors]
[quo2.components.icon :as icons]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
@@ -28,7 +28,8 @@
[{:keys [contact]}]
(let [{:keys [primary-name nickname public-key]} contact
entered-nickname (reagent/atom (or nickname ""))
photo-path (rf/sub [:chats/photo-path public-key])
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path public-key]))
insets (safe-area/get-insets)]
(fn [{:keys [title description accessibility-label
close-button-text]}]
@@ -40,10 +41,10 @@
:size :heading-1} title]
[rn/view {:style (style/context-container)}
[quo/user-avatar
{:full-name primary-name
:profile-picture photo-path
:size :xxs
:status-indicator? false}]
{:full-name primary-name
:profile-picture photo-path
:size :xxs
:status-indicator false}]
[quo/text
{:weight :medium
:size :paragraph-2
@@ -4,7 +4,6 @@
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[oops.core :refer [oget]]
[react-native.platform :as platform]
[status-im2.common.resources :as resources]
[status-im.async-storage.core :as async-storage]
[status-im2.contexts.shell.jump-to.state :as shell.state]
@@ -89,9 +88,10 @@
(when dark-overlay?
[blur/view
{:style style/background-blur-overlay
:blur-amount (if platform/android? 30 20)
:blur-radius (if platform/android? 25 10)
:blur-amount 30
:blur-radius 25
:blur-type :transparent
:overlay-color :transparent}])]))
(defn view [dark-overlay?] [:f> f-view dark-overlay?])
@@ -3,7 +3,6 @@
[react-native.blur :as blur]
[react-native.core :as rn]
[reagent.core :as reagent]
[react-native.platform :as platform]
[status-im2.contexts.onboarding.common.overlay.style :as style]
[status-im2.constants :as constants]))
@@ -62,7 +61,7 @@
:style (style/blur-container opacity)}
[blur/view
{:blur-amount @blur-amount
:blur-radius (if platform/android? 25 10)
:blur-radius 25
:blur-type :transparent
:overlay-color :transparent
:style style/blur-style}]]))
@@ -1,20 +1,20 @@
(ns status-im2.contexts.onboarding.create-profile.view
(:require [clojure.string :as string]
[oops.core :as oops]
[quo2.core :as quo]
(:require [quo2.core :as quo]
[clojure.string :as string]
[quo2.foundations.colors :as colors]
[react-native.blur :as blur]
[status-im2.contexts.onboarding.create-profile.style :as style]
[utils.i18n :as i18n]
[react-native.core :as rn]
[react-native.platform :as platform]
[react-native.safe-area :as safe-area]
[react-native.hooks :as hooks]
[reagent.core :as reagent]
[status-im2.constants :as c]
[status-im2.contexts.onboarding.common.navigation-bar.view :as navigation-bar]
[status-im2.contexts.onboarding.create-profile.style :as style]
[status-im2.contexts.onboarding.select-photo.method-menu.view :as method-menu]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[oops.core :as oops]
[react-native.blur :as blur]
[status-im2.constants :as c]
[react-native.platform :as platform]))
;; NOTE - validation should match with Desktop
;; https://github.com/status-im/status-desktop/blob/2ba96803168461088346bf5030df750cb226df4c/ui/imports/utils/Constants.qml#L468
@@ -51,7 +51,7 @@
(defn show-button-background
[keyboard-height keyboard-shown content-scroll-y]
[keyboard-height keyboard-shown]
(let [button-container-height 64
keyboard-view-height (+ keyboard-height button-container-height)]
(when keyboard-shown
@@ -60,7 +60,7 @@
(< (- @scroll-view-height button-container-height) @content-container-height)
platform/ios?
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
(< (- @scroll-view-height keyboard-view-height) @content-container-height)
:else
false))))
@@ -93,7 +93,6 @@
(defn- f-page
[{:keys [onboarding-profile-data navigation-bar-top]}]
(reagent/with-let [show-keyboard? (reagent/atom false)
content-scroll-y (reagent/atom 0)
show-listener (oops/ocall rn/keyboard
"addListener"
(if platform/android?
@@ -130,8 +129,7 @@
:else :success)
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
show-background? (show-button-background keyboard-height
keyboard-shown
@content-scroll-y)]
keyboard-shown)]
[rn/view {:style style/page-container}
[navigation-bar/navigation-bar
{:stack-id :new-to-status
@@ -139,12 +137,7 @@
[rn/scroll-view
{:on-layout (fn [event]
(let [height (oops/oget event "nativeEvent.layout.height")]
(reset! scroll-view-height height)
(reset! content-scroll-y 0)))
:on-scroll (fn [event]
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
(reset! content-scroll-y y)))
:scroll-event-throttle 64
(reset! scroll-view-height height)))
:content-container-style {:flexGrow 1}}
[rn/view
{:on-layout (fn [event]
@@ -169,12 +162,9 @@
[:show-bottom-sheet
{:content
(fn []
[method-menu/view on-change-profile-pic])}]))
:image-picker-props {:profile-picture (or
@profile-pic
(rf/sub
[:profile/onboarding-placeholder-avatar
@profile-pic]))
[method-menu/view on-change-profile-pic])
:theme :dark}]))
:image-picker-props {:profile-picture (when @profile-pic {:uri @profile-pic})
:full-name (if (seq @full-name)
@full-name
(i18n/label :t/your-name))
@@ -125,8 +125,7 @@
:container-style {:top 40
:left 20}
:layers (:generate-keys resources/parallax-video)
:disable-parallax? true
:enable-looping? false}]
:disable-parallax? true}]
[:f> f-page-title insets]])
(defn f-simple-page
@@ -1,7 +1,7 @@
(ns status-im2.contexts.onboarding.identifiers.profile-card.style
(:require [quo2.foundations.colors :as colors]
[quo2.foundations.typography :as typography]
[react-native.reanimated :as reanimated]))
[react-native.reanimated :as reanimated]
[quo2.foundations.typography :as typography]))
(def card-view
{:margin-horizontal 20
@@ -36,7 +36,7 @@
:background-color :transparent
:height 48
:border-color :black
:border-width 3
:border-width 2
:border-radius 44}))
(def picture-avatar-mask

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