Compare commits

...
Author SHA1 Message Date
alwx 349c707066 Updated Go version 2023-08-17 11:46:49 +02:00
Churikova Tetiana aecad2136e e2e: starting to-dos 2023-08-17 05:09:19 +03:00
codemaster 673b1afc3a chore: update group-avatar component (#17014)
We merge it without QA because it only changes the API and doesn't need design review because nothing has been changed 👍
2023-08-17 06:44:30 +10:00
Icaro Motta b0f748cb73 Refactor Quo preview (#16996)
Improvements to quo previews:

- Change quo-preview.preview code to be more aligned with our guidelines.
- Remove duplication when setting up preview screens in quo-preview.main. Now we
  only need to specify the :name and :component keys and fallback to a good
  default for "{:options {:topBar {:visible true}}".
- Auto-generate descriptor labels based on the key.
- Fix form field colors for dark & light, especially for Android.
- Redesigned form fields to look nicer 💄
- Create component that abstracts away the code for rendering the form fields
  and the preview area. This will aid us in creating more consistent looking
  preview screens and keep things DRY.

How do we use the new code?

Just as before, define a state binding and use it to build up the arguments of
the component. Then, use the preview/preview-container to wrap the component.
You can use certain props to control how the preview is styled, etc, but that's
about it.

    (def descriptor
      [{:type :text :key :label}
       {:key     :chevron-position
        :type    :select
        :options [{:key :left}
                  {:key :right}]}])
    
    (defn view
      []
      (let [state (reagent/atom {:chevron-position :left
                                 :label            "Welcome"})]
        (fn []
          [preview/preview-container {:state state :descriptor descriptor}
           [quo/divider-label @state]])))
2023-08-16 11:30:21 +00:00
Andrea Maria Piana d988296ecf Add next in line for communities 2023-08-16 12:16:32 +01:00
Andrea Maria Piana dc8a09ce75 Update wallet team members 2023-08-16 12:16:08 +01:00
Andrea Maria Piana 0dea703ca0 3 lines community description 2023-08-16 12:15:12 +01:00
Ibrahem Khalil 50134ebeff Fix jump to button showing inside composer (#16999) 2023-08-15 11:31:50 +03:00
yqrashawn a6710f902f feat: render all avatars using media server (#16193) 2023-08-15 09:59:40 +08:00
77 changed files with 1551 additions and 1389 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
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?
react-native.fs/move-file
react-native.fs/read-dir
react-native.fs/mkdir
react-native.fs/unlink
react-native.fs/file-exists?
quo.animated/code
quo.animated/eq
quo.animated/neq
+3 -5
View File
@@ -16,7 +16,7 @@ The responsibilities of the team are to implement the new wallet UI, with the su
## Decision
Some team members have already expressed interest and some have been asked and accepted to join the wallet team, these team members are:
The team members for the initial wallet team are:
- @rasom
- @OmarBasem
@@ -25,7 +25,5 @@ Some team members have already expressed interest and some have been asked and a
- @briansztamfater
- @smohamedjavid
- @ulisesmac
# Follow-up Actions
- We still need 3/4 team members to join the wallet team
- @erikseppanen
- @mmilad75
+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
- Communities @ilmotta, followed by @ajayesivan
- Activity Center & Shell @J-Son89, followed by @Parveshdhull
- Wallet (once the vertical team is created) @J-Son89, followed by @briansztamfater
+2 -1
View File
@@ -90,7 +90,8 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
:configureNext (fn [])}
:requireNativeComponent (fn [] {:propTypes ""})
:Appearance {:getColorScheme (fn [])
:addChangeListener (fn [])}}))
:addChangeListener (fn [])}
:PixelRatio {:get (fn [])}}))
(set! js/ReactNative react-native)
@@ -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)
: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)
:overflow :hidden
:background-color (colors/theme-colors (colors/custom-color customization-color 50)
(colors/custom-color customization-color 60)
theme)})
@@ -7,34 +7,27 @@
[quo2.components.avatars.group-avatar.style :as style]))
(def sizes
{: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}})
{20 {:icon 12}
28 {:icon 16}
32 {:icon 16}
48 {:icon 20}
80 {:icon 32}})
(defn- view-internal
[_]
(fn [{:keys [size theme customization-color picture]
:or {size :x-small
customization-color :blue
picture nil}}]
(let [container-size (get-in sizes [:container size])
icon-size (get-in sizes [:icon size])]
:or {size 20
customization-color :blue}}]
(let [icon-size (get-in sizes [size :icon])]
[rn/view
{:style (style/container {:container-size container-size
{:style (style/container {:container-size size
:customization-color customization-color
:theme theme})}
(if picture
[fast-image/fast-image
{:source picture
:style {:width container-size
:height container-size}}]
:style {:width size
:height size}}]
[icon/icon :i/members
{:size icon-size
:color colors/white-opa-70}])])))
@@ -2,14 +2,9 @@
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[test-helpers.component :as h]))
(defonce mock-picture (js/require "../resources/images/mock2/user_picture_male4.png"))
(defonce mock-picture {:uri (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
@@ -18,124 +13,5 @@
(h/test "Renders even if `:full-name` is passed"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:full-name "New User1"}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-null (h/query-by-label-text :initials-avatar)))
(h/describe "Status indicator"
(h/test "Render"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:status-indicator? true}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-truthy (h/get-by-label-text :status-indicator)))
(h/test "Do not render"
(h/render
[user-avatar/user-avatar
{:profile-picture mock-picture
:status-indicator? false}])
(h/is-truthy (h/get-by-label-text :profile-picture))
(h/is-null (h/query-by-label-text :status-indicator)))))
(h/describe "Initials Avatar"
(h/describe "Render initials"
(letfn [(user-avatar-component [size]
[user-avatar/user-avatar
{:full-name "New User"
:size size}])]
(h/describe "Two letters"
(h/test "Size :big"
(h/render (user-avatar-component :big))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Size :medium"
(h/render (user-avatar-component :medium))
(h/is-truthy (h/get-by-text "NU")))
(h/test "Size :small"
(h/render (user-avatar-component :small))
(h/is-truthy (h/get-by-text "NU")))
(h/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))))))
[user-avatar/user-avatar {:profile-picture mock-picture}])
(h/is-truthy (h/get-by-label-text :profile-picture)))))
@@ -2,92 +2,61 @@
(:require [quo2.foundations.colors :as colors]))
(def sizes
{:big {:outer 80
:inner 72
{:big {:dimensions 80
:status-indicator 20
:status-indicator-border 4
:font-size :heading-1}
:medium {:outer 48
:inner 44
:medium {:dimensions 48
:status-indicator 12
:status-indicator-border 2
:font-size :heading-2}
:small {:outer 32
:inner 28
:small {:dimensions 32
:status-indicator 12
:status-indicator-border 2
:font-size :paragraph-2}
:xs {:outer 24
:inner 24
:xs {:dimensions 24
:status-indicator 0
:status-indicator-border 0
:font-size :paragraph-2}
:xxs {:outer 20
:inner 20
:xxs {:dimensions 20
:status-indicator 0
:status-indicator-border 0
:font-size :label}
:xxxs {:outer 16
:inner 16
:xxxs {:dimensions 16
:status-indicator 0
:status-indicator-border 0
:font-size :label}})
(defn outer
[size]
(let [dimensions (get-in sizes [size :outer])]
{:width dimensions
:height dimensions
:border-radius dimensions}))
(defn initials-avatar
[size draw-ring? customization-color theme]
(let [outer-dimensions (get-in sizes [size :outer])
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
[size customization-color theme]
(let [dimensions (get-in sizes [size :dimensions])]
{:position :absolute
:top (/ (- outer-dimensions inner-dimensions) 2)
:left (/ (- outer-dimensions inner-dimensions) 2)
:width inner-dimensions
:height inner-dimensions
:border-radius inner-dimensions
:top 0
:left 0
:width dimensions
:height dimensions
:border-radius 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,64 +1,104 @@
(ns quo2.components.avatars.user-avatar.view
(: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))
(: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))
(defn initials-avatar
[{:keys [full-name size draw-ring? customization-color theme]}]
[{:keys [full-name size 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 draw-ring? customization-color theme)}
:style (style/initials-avatar size customization-color theme)}
[text/text
{:style style/initials-avatar-text
:size font-size
:weight :semi-bold}
(utils.string/get-initials full-name amount-initials)]]))
(def valid-ring-sizes #{:big :medium :small})
(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}
(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
`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
online? true
ring? true
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,
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,
;; 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? rn/image fast-image/fast-image)]
[rn/view {:style outer-styles :accessibility-label :user-avatar}
;; The `profile-picture` already has the ring in it
(when-let [image (or profile-picture ring-background)]
[image-view
{: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?)}]])]))
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)]
(def user-avatar (quo.theme/with-theme user-avatar-internal))
[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]
[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})}])]))
(def user-avatar (quo2.theme/with-theme user-avatar-internal))
@@ -0,0 +1,49 @@
(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,23 +3,6 @@
[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.buttons.button.view :as buttons]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.buttons.button.view :as buttons]
[quo2.components.inputs.profile-input.style :as style]
[quo2.components.inputs.title-input.view :as title-input]
[react-native.core :as rn]
@@ -13,38 +13,40 @@
on-press
title-input-props
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
: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})]]])
(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})]]]))
+9 -10
View File
@@ -1,11 +1,11 @@
(ns quo2.components.list-items.user-list
(:require [react-native.core :as rn]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.markdown.text :as text]
(:require [quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[quo2.components.markdown.text :as text]
[quo2.components.messages.author.view :as author]
[quo2.components.selectors.selectors.view :as selectors]))
[quo2.components.selectors.selectors.view :as selectors]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]))
(def container-style
{:margin-horizontal 8
@@ -45,11 +45,10 @@
: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
:status-indicator? true
:online? online?
:size :small}]
{:full-name primary-name
:profile-picture photo-path
:online? online?
:size :small}]
[rn/view {:style {:margin-left 8}}
[author/author
{:primary-name primary-name
@@ -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,31 +24,27 @@
(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}}]
(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]]))))
(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]])))
@@ -1,6 +1,6 @@
(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]
[quo2.components.avatars.user-avatar.style :as user-avatar.style]
[quo2.components.avatars.user-avatar.view :as user-avatar]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
@@ -40,7 +40,7 @@
(trim-public-key public-key)]])
(defn context-tag
[{:keys [text-style blur? no-avatar-placeholder? text-container-style ellipsize-text?]
[{:keys [text-style blur? no-avatar-placeholder? text-container-style ellipsize-text? ring?]
:as props}
photo
name
@@ -52,7 +52,7 @@
:ellipsize-mode :tail}
empty-photo? (nil? photo)
avatar-size :xxs
avatar-outer-size (get-in user-avatar-style/sizes [avatar-size :outer])]
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}}]
@@ -60,6 +60,7 @@
{: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?
+8
View File
@@ -42,3 +42,11 @@
(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))
+8 -2
View File
@@ -1,6 +1,6 @@
(ns status-im.contact.core
(:require [utils.re-frame :as rf]
[status-im2.navigation.events :as navigation]))
(:require [status-im2.navigation.events :as navigation]
[utils.re-frame :as rf]))
(rf/defn open-contact-toggle-list
{:events [:contact.ui/start-group-chat-pressed]}
@@ -10,3 +10,9 @@
: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)))
+10 -9
View File
@@ -1,13 +1,13 @@
(ns status-im.multiaccounts.logout.core
(:require [re-frame.core :as re-frame]
[utils.i18n :as i18n]
(:require [native-module.core :as native-module]
[re-frame.core :as re-frame]
[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]))
[status-im2.db :as db]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(re-frame/reg-fx
::logout
@@ -15,14 +15,15 @@
(native-module/logout)))
(rf/defn initialize-app-db
[{{:keys [keycard]
[{{:keys [keycard initials-avatar-font-file]
:biometric/keys [supported-type]
:network/keys [type]}
:db}]
{:db (assoc db/app-db
:network/type type
:keycard (dissoc keycard :secrets :pin :application-info)
:biometric/supported-type supported-type)})
:network/type type
:initials-avatar-font-file initials-avatar-font-file
:keycard (dissoc keycard :secrets :pin :application-info)
:biometric/supported-type supported-type)})
(rf/defn logout-method
{:events [::logout-method]}
+8 -5
View File
@@ -1,5 +1,6 @@
(ns status-im.multiaccounts.update.core
(:require [status-im.utils.types :as types]
(:require [status-im.ethereum.ens :as ens]
[status-im.utils.types :as types]
[status-im2.constants :as constants]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
@@ -19,10 +20,12 @@
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
{:json-rpc/call [{:method "multiaccounts_updateAccount"
:params [(assoc account :name new-name)]
:on-success #(log/debug "sent multiaccount update")}]}))))
(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/defn multiaccount-update
"Takes effects (containing :db) + new multiaccount fields, adds all effects necessary for multiaccount update.
@@ -2,8 +2,11 @@
(: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]
@@ -47,7 +50,7 @@
[rn/text {:style (:default-chat-icon-text styles)} emoji]]))
(defn profile-photo-plus-dot-view
[{:keys [public-key photo-container photo-path community?]}]
[{:keys [public-key full-name customization-color photo-container photo-path community?]}]
(let [photo-container (if (nil? photo-container)
styles/container-chat-list
photo-container)
@@ -55,11 +58,28 @@
dot-styles (visibility-status-utils/icon-visibility-status-dot
public-key
size)
dot-accessibility-label (:accessibility-label dot-styles)]
dot-accessibility-label (:accessibility-label dot-styles)
text-style (styles/default-chat-icon-text size)]
[rn/view
{:style photo-container
:accessibility-label :profile-photo}
[photos/photo photo-path {:size size}]
(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}])
(when-not community?
[rn/view
{:style dot-styles
@@ -179,14 +199,28 @@
(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)]
(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)]
[rn/view (:container styles)
(if (and photo-path (seq photo-path))
[profile-photo-plus-dot-view
@@ -2,23 +2,25 @@
(: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])
[status-im.ui.components.react :as react]
[utils.i18n :as i18n])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn contacts-list-item
[{:keys [public-key] :as contact}]
(let [{:keys [primary-name secondary-name]} contact]
(let [{:keys [primary-name secondary-name customization-color]} contact]
[quo/list-item
{:title primary-name
:subtitle secondary-name
:icon [chat-icon.screen/profile-photo-plus-dot-view
{:public-key public-key
:photo-path (multiaccounts/displayed-photo contact)}]
{:public-key public-key
:full-name primary-name
:customization-color (or customization-color :primary)
:photo-path (multiaccounts/displayed-photo contact)}]
:chevron true
:on-press #(re-frame/dispatch [:chat.ui/show-profile public-key])}]))
@@ -3,9 +3,10 @@
[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]
@@ -13,8 +14,9 @@
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.profile.components.sheets :as sheets]
[utils.re-frame :as rf]
[status-im2.constants :as constants]))
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn actions
[{:keys [public-key added? blocked? ens-name mutual?] :as contact} muted?]
@@ -179,9 +181,11 @@
:as contact}
@(re-frame/subscribe
[:contacts/current-contact])
muted? @(re-frame/subscribe [:chats/muted
public-key])
{:keys [primary-name secondary-name]} contact
{:keys [primary-name secondary-name customization-color]} contact
customization-color (or customization-color :primary)
on-share #(re-frame/dispatch
[:show-popover
(merge
@@ -201,14 +205,17 @@
: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
:photo (multiaccounts/displayed-photo contact)
:monospace (not ens-verified)
:subtitle secondary-name
:compressed-key compressed-key
:public-key public-key})]
: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})]
[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,7 +19,9 @@
[status-im.utils.gfycat.core :as gfy]
[status-im.utils.universal-links.utils :as universal-links]
[status-im.utils.utils :as utils]
[status-im2.config :as config])
[status-im2.common.qr-code-viewer.view :as qr-code-viewer]
[status-im2.config :as config]
[utils.i18n :as i18n])
(:require-macros [status-im.utils.views :as views]))
(views/defview share-chat-key
@@ -190,9 +192,12 @@
(let [{:keys [public-key
compressed-key
ens-verified
preferred-name]
preferred-name
key-uid]
: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
@@ -213,6 +218,8 @@
: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)
+4
View File
@@ -0,0 +1,4 @@
(ns status-im.utils.pixel-ratio
(:require ["react-native" :as rn]))
(def ratio (rn/PixelRatio.get))
@@ -1,9 +1,9 @@
(ns status-im2.common.confirmation-drawer.view
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
(:require [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
@@ -13,10 +13,10 @@
{:customization-color color
: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,12 +41,7 @@
(= contact-name-by-identity
nil) name
:else contact-name-by-identity)
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])))]
photo-path (or profile-picture (rf/sub [:chats/photo-path id]))]
[rn/view
{:style {:margin-horizontal 20}
:accessibility-label accessibility-label}
+17
View File
@@ -0,0 +1,17 @@
(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)}))
+1 -4
View File
@@ -60,10 +60,7 @@
{:accessibility-label :open-profile
:style style/left-section}
[quo/user-avatar
(merge {:status-indicator? true
:size :small
:online? online?}
avatar)]]]))
(merge {:size :small :online? online?} avatar)]]]))
(defn connectivity-sheet
[]
+10 -3
View File
@@ -11,10 +11,17 @@
(defn toast
[toast-id]
(let [{:keys [type] :as toast-opts} (rf/sub [:toasts/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)]
(if (= type :notification)
[quo/notification toast-opts]
[quo/toast toast-opts])))
[quo/notification toast-opts-with-profile-picture]
[quo/toast toast-opts-with-profile-picture])))
(defn f-container
[toast-id]
+8
View File
@@ -345,3 +345,11 @@
(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,10 +2,9 @@
(:require
[clojure.string :as string]
[quo2.core :as quo]
[react-native.core :as rn]
[react-native.clipboard :as clipboard]
[react-native.core :as rn]
[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]
@@ -15,8 +14,8 @@
(defn found-contact
[public-key]
(let [{:keys [primary-name compressed-key]
:as contact} (rf/sub [:contacts/contact-by-identity 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])]
(when primary-name
[rn/view style/found-user
[quo/text (style/text-description)
@@ -24,7 +23,7 @@
[rn/view (style/found-user-container)
[quo/user-avatar
{:full-name primary-name
:profile-picture (multiaccounts/displayed-photo contact)
:profile-picture photo-path
:size :small
:status-indicator? false}]
[rn/view style/found-user-text
@@ -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]
[status-im2.constants :as constant]
[react-native.core :as rn]
[react-native.linear-gradient :as linear-gradient]
[react-native.reanimated :as reanimated]
[status-im.ethereum.stateofus :as stateofus]
[utils.re-frame :as rf]
[status-im2.constants :as constant]
[status-im2.contexts.chat.composer.constants :as constants]
[status-im2.contexts.chat.composer.reply.style :as style]
[react-native.linear-gradient :as linear-gradient]))
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn get-quoted-text-with-mentions
[parsed-text]
@@ -63,8 +63,7 @@
(defn reply-from
[{:keys [from contact-name current-public-key]}]
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
contact (rf/sub [:contacts/contact-by-address from])
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))]
photo-path (rf/sub [:chats/photo-path from])]
[rn/view {:style style/reply-from}
[quo/user-avatar
{:full-name display-name
@@ -41,7 +41,6 @@
(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
@@ -1,16 +1,16 @@
(ns status-im2.contexts.chat.home.chat-list-item.view
(:require [quo2.core :as quo]
(:require [clojure.string :as string]
[quo2.components.icon :as icons]
[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]
[quo2.components.icon :as icons]))
[utils.re-frame :as rf]))
(def max-subheader-length 50)
@@ -201,14 +201,14 @@
[{: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])
image-key (if (seq (:images contact)) :profile-picture :ring-background)]
photo-path (rf/sub [:chats/photo-path chat-id])]
[quo/user-avatar
{:full-name full-name
:size :small
:online? online?
image-key photo-path
:muted? muted?}])
(cond-> {:full-name full-name
:size :small
:online? online?
:profile-picture photo-path}
muted?
(assoc :ring? false))])
[quo/group-avatar
{:customization-color color
:size :small}]))
@@ -1,21 +1,19 @@
(ns status-im2.contexts.chat.messages.avatar.view
(:require [utils.re-frame :as rf]
(:require [quo2.core :as quo]
[react-native.core :as rn]
[quo2.core :as quo]))
[utils.re-frame :as rf]))
(defn avatar
[public-key size]
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))
contact (rf/sub [:contacts/contact-by-address public-key])
photo-path (when (seq (:images contact)) (rf/sub [:chats/photo-path public-key]))
photo-path (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
:status-indicator? true
:online? online?
:size size}]]]))
{:full-name display-name
:profile-picture photo-path
:online? online?
:size size}]]]))
@@ -28,9 +28,7 @@
on-long-press-fn]
(let [;; deleted message with nil deleted-by is deleted by (:from message)
display-name (first (rf/sub [:contacts/contact-two-names-by-identity (or deleted-by from)]))
contact (rf/sub [:contacts/contact-by-address (or deleted-by from)])
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path (or deleted-by from)]))]
photo-path (rf/sub [:chats/photo-path (or deleted-by from)])]
[quo/system-message
{:type :deleted
:timestamp timestamp-str
@@ -1,24 +1,24 @@
(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.composer.constants :as composer.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.chat.messages.navigation.style :as navigation.style]
[status-im2.contexts.chat.composer.constants :as composer.constants]
[utils.re-frame :as rf]
[utils.i18n :as i18n]))
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
(defonce ^:const loading-indicator-extra-spacing 250)
@@ -203,8 +203,7 @@
online? (rf/sub [:visibility-status-updates/online? 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]))
photo-path (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]
[status-im2.config :as config]
[react-native.reanimated :as reanimated]
[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]
[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]
[status-im2.common.home.actions.view :as actions]))
[utils.re-frame :as rf]))
(defn f-view
[{:keys [scroll-y]}]
@@ -27,10 +27,7 @@
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
(str emoji " " chat-name))
online? (rf/sub [:visibility-status-updates/online? 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]))
photo-path (rf/sub [:chats/photo-path chat-id])
opacity-animation (reanimated/interpolate scroll-y
[style/navigation-bar-height
(+ style/navigation-bar-height 30)]
@@ -256,7 +256,7 @@
[description]
[quo/text
{:accessibility-label :community-description-text
:number-of-lines 2
:number-of-lines 4
:ellipsize-mode :tail
:weight :regular
:size :paragraph-1
@@ -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,8 +28,7 @@
[{:keys [contact]}]
(let [{:keys [primary-name nickname public-key]} contact
entered-nickname (reagent/atom (or nickname ""))
photo-path (when-not (empty? (:images contact))
(rf/sub [:chats/photo-path public-key]))
photo-path (rf/sub [:chats/photo-path public-key])
insets (safe-area/get-insets)]
(fn [{:keys [title description accessibility-label
close-button-text]}]
@@ -41,10 +40,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
@@ -1,20 +1,20 @@
(ns status-im2.contexts.onboarding.create-profile.view
(:require [quo2.core :as quo]
[clojure.string :as string]
(:require [clojure.string :as string]
[oops.core :as oops]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[status-im2.contexts.onboarding.create-profile.style :as style]
[utils.i18n :as i18n]
[react-native.blur :as blur]
[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.contexts.onboarding.common.navigation-bar.view :as navigation-bar]
[status-im2.contexts.onboarding.select-photo.method-menu.view :as method-menu]
[utils.re-frame :as rf]
[oops.core :as oops]
[react-native.blur :as blur]
[status-im2.constants :as c]
[react-native.platform :as platform]))
[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]))
;; NOTE - validation should match with Desktop
;; https://github.com/status-im/status-desktop/blob/2ba96803168461088346bf5030df750cb226df4c/ui/imports/utils/Constants.qml#L468
@@ -162,9 +162,12 @@
[:show-bottom-sheet
{:content
(fn []
[method-menu/view on-change-profile-pic])
:theme :dark}]))
:image-picker-props {:profile-picture (when @profile-pic {:uri @profile-pic})
[method-menu/view on-change-profile-pic])}]))
:image-picker-props {:profile-picture (or
@profile-pic
(rf/sub
[:profile/onboarding-placeholder-avatar
@profile-pic]))
:full-name (if (seq @full-name)
@full-name
(i18n/label :t/your-name))
@@ -1,7 +1,7 @@
(ns status-im2.contexts.onboarding.identifiers.profile-card.style
(:require [quo2.foundations.colors :as colors]
[react-native.reanimated :as reanimated]
[quo2.foundations.typography :as typography]))
[quo2.foundations.typography :as typography]
[react-native.reanimated :as reanimated]))
(def card-view
{:margin-horizontal 20
@@ -36,7 +36,7 @@
:background-color :transparent
:height 48
:border-color :black
:border-width 2
:border-width 3
:border-radius 44}))
(def picture-avatar-mask
@@ -1,12 +1,12 @@
(ns status-im2.contexts.onboarding.identifiers.profile-card.view
(:require [react-native.core :as rn]
[react-native.reanimated :as reanimated]
[react-native.masked-view :as masked-view]
[reagent.core :as reagent]
[quo2.core :as quo]
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[utils.worklets.identifiers-highlighting :as worklets.identifiers-highlighting]
[status-im2.contexts.onboarding.identifiers.profile-card.style :as style]))
[react-native.core :as rn]
[react-native.masked-view :as masked-view]
[react-native.reanimated :as reanimated]
[reagent.core :as reagent]
[status-im2.contexts.onboarding.identifiers.profile-card.style :as style]
[utils.worklets.identifiers-highlighting :as worklets.identifiers-highlighting]))
(defn- f-profile-card-component
[{:keys [profile-picture name hash emoji-hash
@@ -20,29 +20,24 @@
ring-opacity (worklets.identifiers-highlighting/ring-opacity @progress)
user-hash-color (worklets.identifiers-highlighting/user-hash-color @progress)
user-hash-opacity (worklets.identifiers-highlighting/user-hash-opacity @progress)
emoji-hash-style (worklets.identifiers-highlighting/emoji-hash-style @progress)]
emoji-hash-style (worklets.identifiers-highlighting/emoji-hash-style @progress)
avatar [quo/user-avatar
{:full-name name
:profile-picture profile-picture
:size :medium
:status-indicator? false
:customization-color customization-color}]]
[rn/view
{:style style/card-view}
[reanimated/view
{:style (style/card-container container-background)}
[rn/view {:style style/card-header}
[reanimated/view
{:style (style/avatar avatar-opacity)}
[quo/user-avatar
{:full-name name
:profile-picture profile-picture
:size :medium
:status-indicator? false
:customization-color customization-color}]]
[reanimated/view {:style (style/avatar avatar-opacity)} avatar]
[masked-view/masked-view
{:style {:position :absolute}
:mask-element (reagent/as-element
[reanimated/view {:style (style/mask-view ring-opacity)}])}
(when profile-picture
[rn/image
{:accessibility-label :ring-background
:style style/picture-avatar-mask
:source profile-picture}])]]
(when profile-picture avatar)]]
[reanimated/view
{:style (style/user-name-container opacity)}
[quo/text
@@ -111,7 +111,7 @@
:customization-color (or customization-color :primary)
:keycard-account? keycard-pairing
:show-options-button? true
:profile-picture (when profile-picture {:uri profile-picture})
:profile-picture profile-picture
:card-style (style/profiles-profile-card last-item?)
:on-options-press #(show-profile-options
key-uid
@@ -257,7 +257,7 @@
[quo/profile-card
{:name name
:customization-color (or customization-color :primary)
:profile-picture (when profile-picture {:uri profile-picture})
:profile-picture profile-picture
:card-style style/login-profile-card}]
[quo/input
{:type :password
+3 -1
View File
@@ -1,9 +1,11 @@
(ns status-im2.contexts.profile.rpc
(:require [clojure.string :as string]))
(:require [clojure.string :as string]
[status-im.ethereum.ens :as ens]))
(defn rpc->profiles-overview
[{:keys [customizationColor keycard-pairing] :as profile}]
(-> profile
(dissoc :customizationColor)
(assoc :customization-color (keyword customizationColor))
(assoc :ens-name? (ens/is-valid-eth-name? (:name profile)))
(assoc :keycard-pairing (when-not (string/blank? keycard-pairing) keycard-pairing))))
@@ -10,28 +10,28 @@
[{:label "Size"
:key :size
:type :select
:options [{:key :x-small
:value "x-small"}
{:key :small
:value "Small"}
{:key :medium
:value "Medium"}
{:key :large
:value "Large"}
{:key :x-large
:value "x-Large"}]}
:options [{:key 20
:value 20}
{:key 28
:value 28}
{:key 32
:value 32}
{:key 48
:value 48}
{:key 80
:value 80}]}
{:label "Avatar"
:key :picture?
:type :boolean}
(preview/customization-color-option)])
(def avatar (resources/get-mock-image :user-picture-male4))
(def avatar (resources/get-mock-image :photo1))
(defn cool-preview
[]
(let [state (reagent/atom {:theme :light
:customization-color :blue
:size :small
:size 20
:picture? false})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
@@ -67,12 +67,7 @@
{:padding-vertical 60
:flex-direction :row
:justify-content :center}
(let [{:keys [profile-picture ring?]} @state
ring-bg (resources/get-mock-image :ring)
params (cond-> @state
(and (not profile-picture) ring?)
(assoc :ring-background ring-bg))]
[quo2/user-avatar params])]]])))
[quo2/user-avatar @state]]]])))
(defn preview-user-avatar
[]
@@ -1,48 +1,26 @@
(ns status-im2.contexts.quo-preview.colors.color-picker
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.blur :as blur]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Color:"
:key :color
[{:key :selected
:type :select
:options (map (fn [color]
(let [k (get color :name)]
{:key k :value k}))
(quo/picker-colors))}
{:label "Blur?"
:key :blur
:type :boolean}])
{:key :blur?
:type :boolean}])
(defn cool-preview
(defn view
[]
(let [state (reagent/atom {:color "orange" :blur false})
blur (reagent/cursor state [:blur])
color (reagent/cursor state [:color])]
(let [state (reagent/atom {:selected :orange
:blur? false})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[(if @blur blur/view :<>)
[rn/view {:padding-vertical 60 :align-items :center}
[quo/color-picker
{:blur? @blur
:selected @color
:on-change #(reset! color %)}]]]]])))
(defn preview-color-picker
[]
[rn/view
{:background-color (colors/theme-colors
colors/white
colors/neutral-95)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? true}
[quo/color-picker (assoc @state :on-change #(swap! state assoc :selected %))]])))
@@ -1,54 +1,29 @@
(ns status-im2.contexts.quo-preview.dividers.divider-label
(:require [quo2.components.dividers.divider-label :as divider-label]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
(:require [quo2.core :as quo]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Label:"
:key :label
:type :text}
{:label "Chevron position:"
:key :chevron-position
[{:type :text :key :label}
{:type :text :key :counter-value}
{:type :boolean :key :increase-padding-top?}
{:type :boolean :key :blur?}
{:key :chevron-position
:type :select
:options [{:key :left
:value "Left"}
{:key :right
:value "Right"}]}
{:label "Counter value:"
:key :counter-value
:type :text}
{:label "Increase padding top:"
:key :increase-padding-top?
:type :boolean}
{:label "Blur:"
:key :blur?
:type :boolean}])
:options [{:key :left}
{:key :right}]}])
(defn cool-preview
(defn view
[]
(let [state (reagent/atom {:label "Welcome"
(let [state (reagent/atom {:blur? false
:chevron-position :left
:counter-value 0
:counter-value "0"
:increase-padding-top? true
:blur? false})]
:label "Welcome"})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 150}
[preview/customizer state descriptor]
[rn/view {:padding-vertical 60}
[divider-label/divider-label @state]]]])))
(defn preview-divider-label
[]
[rn/view
{:background-color (colors/theme-colors
colors/white
colors/neutral-90)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? true}
[quo/divider-label @state]])))
@@ -1,100 +1,56 @@
(ns status-im2.contexts.quo-preview.links.link-preview
(:require [clojure.string :as string]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
(:require [quo2.core :as quo]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]
utils.number))
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Title"
:key :title
:type :text}
{:label "Description"
:key :description
:type :text}
{:label "Link"
:key :link
:type :text}
{:label "Container width"
:key :width
:type :text}
{:label "With logo?"
:key :with-logo?
:type :boolean}
{:label "With description?"
:key :with-description?
:type :boolean}
{:label "With thumbnail?"
:key :with-thumbnail?
:type :boolean}
{:label "Disabled text"
:key :disabled-text
:type :text}
{:label "Enabled?"
:key :enabled?
:type :boolean}
{:label "Thumbnail"
:key :thumbnail
[{:type :text :key :title}
{:type :text :key :description}
{:type :text :key :link}
{:type :number :key :width}
{:type :boolean :key :with-logo?}
{:type :boolean :key :with-description?}
{:type :boolean :key :with-thumbnail?}
{:type :text :key :disabled-text}
{:type :boolean :key :enabled?}
{:key :thumbnail
:type :select
:options (mapv (fn [k]
{:key k
:value (string/capitalize (name k))})
:options (mapv (fn [k] {:key k})
(keys resources/mock-images))}
{:label "Thumbnail size"
:key :thumbnail-size
{:key :thumbnail-size
:type :select
:options [{:key :normal
:value :normal}
{:key :large
:value :large}]}])
:options [{:key :normal}
{:key :large}]}])
(defn cool-preview
(defn view
[]
(let [state (reagent/atom
{:title "Rarible - NFT Marketplace"
:description "Turn your products or services into publicly tradeable items"
{:description "Turn your products or services into publicly tradeable items"
:disabled-text "Enable Preview"
:enabled? true
:link "rarible.com"
:thumbnail :collectible
:width "295"
:with-logo? true
:with-thumbnail? true
:with-description? true
:enabled? true
:thumbnail-size :normal
:disabled-text "Enable Preview"})]
:title "Rarible - NFT Marketplace"
:width 295
:with-description? true
:with-logo? true
:with-thumbnail? true})]
(fn []
(let [width (utils.number/parse-int (:width @state) 295)
thumbnail (get resources/mock-images (:thumbnail @state))]
[rn/view {:style {:margin-bottom 20}}
[preview/customizer state descriptor]
[rn/view
{:style {:align-items :center
:margin-top 20}}
[quo/link-preview
{:logo (when (:with-logo? @state)
(resources/get-mock-image :status-logo))
:title (:title @state)
:description (when (:with-description? @state)
(:description @state))
:enabled? (:enabled? @state)
:on-enable #(js/alert "Button pressed")
:disabled-text (:disabled-text @state)
:link (:link @state)
:thumbnail (when (:with-thumbnail? @state)
thumbnail)
:thumbnail-size (:thumbnail-size @state)
:container-style {:width width}}]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
(let [thumbnail (get resources/mock-images (:thumbnail @state))]
[preview/preview-container {:state state :descriptor descriptor}
[quo/link-preview
{:logo (when (:with-logo? @state)
(resources/get-mock-image :status-logo))
:title (:title @state)
:description (when (:with-description? @state)
(:description @state))
:enabled? (:enabled? @state)
:on-enable #(js/alert "Button pressed")
:disabled-text (:disabled-text @state)
:link (:link @state)
:thumbnail (when (:with-thumbnail? @state)
thumbnail)
:thumbnail-size (:thumbnail-size @state)
:container-style {:width (:width @state)}}]]))))
@@ -1,30 +1,18 @@
(ns status-im2.contexts.quo-preview.links.url-preview
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Title"
:key :title
:type :text}
{:label "Body"
:key :body
:type :text}
{:label "With logo?"
:key :with-logo?
:type :boolean}
{:label "Loading?"
:key :loading?
:type :boolean}
{:label "Loading message"
:key :loading-message
:type :text}])
[{:type :text :key :title}
{:type :text :key :body}
{:type :boolean :key :with-logo?}
{:type :boolean :key :loading?}
{:type :text :key :loading-message}])
(defn cool-preview
(defn view
[]
(let [state (reagent/atom
{:title "Status - Private, Secure Communication"
@@ -33,29 +21,12 @@
:loading? false
:loading-message "Generating preview"})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:style {:padding-bottom 150}}
[preview/customizer state descriptor]
[rn/view
{:style {:align-items :center
:padding-horizontal 16
:margin-top 50}}
[quo/url-preview
{:title (:title @state)
:body (:body @state)
:logo (when (:with-logo? @state)
(resources/get-mock-image :status-logo))
:loading? (:loading? @state)
:loading-message (:loading-message @state)
:on-clear #(js/alert "Clear button pressed")}]]]])))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
[preview/preview-container {:state state :descriptor descriptor}
[quo/url-preview
{:title (:title @state)
:body (:body @state)
:logo (when (:with-logo? @state)
(resources/get-mock-image :status-logo))
:loading? (:loading? @state)
:loading-message (:loading-message @state)
:on-clear #(js/alert "Clear button pressed")}]])))
@@ -1,50 +1,34 @@
(ns status-im2.contexts.quo-preview.links.url-preview-list
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview]
utils.number))
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Number of previews"
:key :previews-length
:type :text}])
[{:type :number :key :previews-length}])
(defn cool-preview
(defn view
[]
(let [state (reagent/atom {:previews-length "3"})]
(let [state (reagent/atom {:previews-length 3})
padding 20]
(fn []
(let [previews-length (min 6 (utils.number/parse-int (:previews-length @state)))
padding 20]
[rn/view {:style {:padding-bottom 150}}
[preview/customizer state descriptor]
[rn/view
{:style {:align-items :center
:margin-top 50}}
[quo/url-preview-list
{:horizontal-spacing padding
:preview-width (- (:width (rn/get-window))
(* 2 padding))
:on-clear #(js/alert "Clear button pressed")
:key-fn :url
:data (for [index (range previews-length)
:let [index (inc index)]]
{:title (str "Title " index)
:body (str "status.im." index)
:logo (resources/get-mock-image :status-logo)
:loading? false
:url (str "status.im." index)})}]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
[preview/preview-container
{:state state
:descriptor descriptor
:component-container-style {:padding-horizontal 0}}
[quo/url-preview-list
{:horizontal-spacing padding
:preview-width (- (:width (rn/get-window))
(* 2 padding))
:on-clear #(js/alert "Clear button pressed")
:key-fn :url
:data (for [index (range (:previews-length @state))
:let [index (inc index)]]
{:title (str "Title " index)
:body (str "status.im." index)
:logo (resources/get-mock-image
:status-logo)
:loading? false
:url (str "status.im." index)})}]])))
@@ -2,39 +2,33 @@
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.community.data :as data]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor-type
{:label "Type:"
{:type :select
:key :type
:type :select
:options [{:key :discover :value "Discover"}
{:key :engage :value "Engage"}
{:key :share :value "Share"}]})
:options [{:key :discover}
{:key :engage}
{:key :share}]})
(def descriptor-locked
{:label "Locked?" :key :locked? :type :boolean})
{:type :boolean :key :locked?})
(def descriptor-unread-count
{:label "Unread count:" :key :unread-count :type :number})
{:type :number :key :unread-count})
(def descriptor-title
{:label "Title:" :key :title :type :text})
{:type :text :key :title})
(def descriptor-blur
{:label "Blur?" :key :blur? :type :boolean})
{:type :boolean :key :blur?})
(def descriptor-member-stats
[{:label "Total member count:"
:key :members-count
:type :number}
{:label "Active member count:"
:key :active-count
:type :number}])
[{:type :number :key :members-count}
{:type :number :key :active-count}])
(def descriptors-base
[descriptor-type
@@ -43,29 +37,27 @@
(def descriptors-type-discover
(conj descriptors-base
{:label "Info:"
{:type :select
:key :info
:type :select
:options [{:key :token-gated :value "Token gated"}
{:key :default :value "Default"}]}
:options [{:key :token-gated}
{:key :default}]}
{:label "Member stats?"
:key :members?
:type :boolean}))
:type :boolean
:key :members?}))
(def descriptors-type-engage
(conj descriptors-base
{:label "Info:"
{:type :select
:key :info
:type :select
:options [{:key :notification :value "Notification"}
{:key :mention :value "Mention"}
{:key :muted :value "Muted"}
{:key :token-gated :value "Token gated"}
{:key :navigation :value "Navigation"}
{:key :default :value "Default"}]}))
:options [{:key :notification}
{:key :mention}
{:key :muted}
{:key :token-gated}
{:key :navigation}
{:key :default}]}))
(def descriptors-type-share
(conj descriptors-base {:label "Subtitle:" :key :subtitle :type :text}))
(conj descriptors-base {:type :text :key :subtitle}))
(defn descriptors
[{:keys [members? info] :as state}]
@@ -88,7 +80,7 @@
(into [descriptor-blur] descs)
descs)))
(defn cool-preview
(defn view
[]
(let [state (reagent/atom {:blur? false
:customization-color :blue
@@ -103,30 +95,16 @@
:unread-count 5})]
(fn []
(let [customization-color (colors/custom-color-by-theme (:customization-color @state) 50 60)]
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:style {:margin-bottom 20}}
[preview/customizer state (descriptors @state)]
[rn/view {:style {:margin-vertical 30 :align-items :center}}
[quo/community-list-item
(merge @state
{:container-style {:width 335}
:logo (resources/get-mock-image :status-logo)
:tokens (:tokens data/community)
:customization-color customization-color
:on-press #(js/alert "List item pressed")
:on-long-press #(js/alert "Long pressed item")
:on-press-info #(js/alert "Info pressed")
:members (when (:members? @state)
{:members-count (:members-count @state)
:active-count (:active-count @state)})})]]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)
:flex 1}}
[rn/flat-list
{:style {:flex 1}
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])
[preview/preview-container {:state state :descriptor (descriptors @state)}
[quo/community-list-item
(merge @state
{:container-style {:width 335}
:logo (resources/get-mock-image :status-logo)
:tokens (:tokens data/community)
:customization-color customization-color
:on-press #(js/alert "List item pressed")
:on-long-press #(js/alert "Long pressed item")
:on-press-info #(js/alert "Info pressed")
:members (when (:members? @state)
{:members-count (:members-count @state)
:active-count (:active-count @state)})})]]))))
+48 -156
View File
@@ -2,9 +2,9 @@
(:refer-clojure :exclude [filter])
(:require
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[reagent.core :as reagent]
[react-native.core :as rn]
[status-im2.contexts.quo-preview.style :as style]
[status-im2.common.theme.core :as theme]
[status-im2.contexts.quo-preview.animated-header-list.animated-header-list :as animated-header-list]
[status-im2.contexts.quo-preview.avatars.account-avatar :as account-avatar]
@@ -120,344 +120,233 @@
(def screens-categories
{:foundations [{:name :shadows
:options {:topBar {:visible true}}
:component shadows/preview-shadows}]
:animated-list [{:name :animated-header-list
:options {:topBar {:visible false}}
:component animated-header-list/mock-screen}]
:avatar [{:name :group-avatar
:options {:topBar {:visible true}}
:component group-avatar/preview-group-avatar}
{:name :icon-avatar
:options {:topBar {:visible true}}
:component icon-avatar/preview-icon-avatar}
{:name :user-avatar
:options {:topBar {:visible true}}
:component user-avatar/preview-user-avatar}
{:name :wallet-user-avatar
:options {:topBar {:visible true}}
:component wallet-user-avatar/preview-wallet-user-avatar}
{:name :channel-avatar
:options {:topBar {:visible true}}
:component channel-avatar/preview-channel-avatar}
{:name :account-avatar
:options {:topBar {:visible true}}
:component account-avatar/preview-account-avatar}]
:banner [{:name :banner
:options {:topBar {:visible true}}
:component banner/preview-banner}]
:buttons [{:name :button
:options {:topBar {:visible true}}
:component button/preview-button}
{:name :composer-button
:options {:topBar {:visible true}}
:component composer-button/preview-composer-button}
{:name :dynamic-button
:options {:topBar {:visible true}}
:component dynamic-button/preview-dynamic-button}
{:name :slide-button
:options {:topBar {:visible true}}
:component slide-button/preview-slide-button}
{:name :predictive-keyboard
:options {:topBar {:visible true}}
:component predictive-keyboard/preview-predictive-keyboard}]
:browser [{:name :browser-input
:options {:topBar {:visible false}}
:component browser-input/preview-browser-input}]
:calendar [{:name :calendar
:options {:topBar {:visible true}}
:component calendar/preview-calendar}
{:name :calendar-day
:options {:topBar {:visible true}}
:component calendar-day/preview-calendar-day}
{:name :calendar-year
:options {:topBar {:visible true}}
:component calendar-year/preview-calendar-year}]
:code [{:name :snippet
:options {:topBar {:visible true}}
:component code-snippet/preview-code-snippet}]
:colors [{:name :color-picker
:options {:topBar {:visible true}}
:component color-picker/preview-color-picker}]
:component color-picker/view}]
:community [{:name :community-card-view
:options {:topBar {:visible true}}
:component community-card/preview-community-card}
{:name :community-membership-list-view
:options {:topBar {:visible true}}
:component community-membership-list-view/preview-community-list-view}
{:name :discover-card
:options {:topBar {:visible true}}
:component discover-card/preview-discoverd-card}
{:name :token-gating
:options {:insets {:bottom? true}
:topBar {:visible true}}
:options {:insets {:bottom? true}}
:component token-gating/preview-token-gating}
{:name :channel-actions
:options {:insets {:bottom? true}
:topBar {:visible true}}
:options {:insets {:bottom? true}}
:component channel-actions/preview-channel-actions}]
:counter [{:name :counter
:options {:topBar {:visible true}}
:component counter/preview-counter}
{:name :step
:options {:topBar {:visible true}}
:component step/preview-step}]
:dividers [{:name :divider-label
:options {:topBar {:visible true}}
:component divider-label/preview-divider-label}
:component divider-label/view}
{:name :new-messages
:options {:topBar {:visible true}}
:component new-messages/preview-new-messages}
{:name :divider-date
:options {:topBar {:visible true}}
:component divider-date/preview-divider-date}
{:name :strength-divider
:options {:topBar {:visible true}}
:component strength-divider/preview-strength-divider}]
:drawers [{:name :action-drawers
:options {:topBar {:visible true}}
:component action-drawers/preview-action-drawers}
{:name :documentation-drawer
:options {:topBar {:visible true}}
:component documenation-drawers/preview-documenation-drawers}
{:name :drawer-buttons
:options {:topBar {:visible true}}
:component drawer-buttons/preview-drawer-buttons}
{:name :permission-drawers
:options {:topBar {:visible true}}
:component permission-drawers/preview-permission-drawers}]
:dropdowns [{:name :dropdown
:options {:topBar {:visible true}}
:component dropdown/preview-dropdown}]
:empty-state [{:name :empty-state
:options {:topBar {:visible true}}
:component empty-state/preview-empty-state}]
:gradient [{:name :gradient-cover
:options {:topBar {:visible true}}
:component gradient-cover/preview-gradient-cover}]
:graph [{:name :wallet-graph
:options {:topBar {:visible true}}
:component wallet-graph/preview-wallet-graph}]
:info [{:name :info-message
:options {:topBar {:visible true}}
:component info-message/preview-info-message}
{:name :information-box
:options {:topBar {:visible true}}
:component information-box/preview-information-box}]
:inputs [{:name :input
:options {:topBar {:visible true}}
:component input/preview-input}
{:name :locked-input
:options {:topBar {:visible true}}
:component locked-input/preview-locked-input}
{:name :profile-input
:options {:topBar {:visible true}}
:component profile-input/preview-profile-input}
{:name :recovery-phrase-input
:options {:topBar {:visible true}}
:component recovery-phrase-input/preview-recovery-phrase-input}
{:name :search-input
:options {:topBar {:visible true}}
:component search-input/preview-search-input}
{:name :title-input
:options {:topBar {:visible true}}
:component title-input/preview-title-input}]
:numbered-keyboard [{:name :keyboard-key
:options {:insets {:top? true}
:topBar {:visible true}}
:options {:insets {:top? true}}
:component keyboard-key/preview-keyboard-key}
{:name :numbered-keyboard
:options {:insets {:top? true}
:topBar {:visible true}}
:options {:insets {:top? true}}
:component numbered-keyboard/preview-numbered-keyboard}]
:links [{:name :url-preview
:options {:insets {:top? true}
:topBar {:visible true}}
:component url-preview/preview}
:options {:insets {:top? true}}
:component url-preview/view}
{:name :url-preview-list
:options {:insets {:top? true}
:topBar {:visible true}}
:component url-preview-list/preview}
:options {:insets {:top? true}}
:component url-preview-list/view}
{:name :link-preview
:options {:insets {:top? true}
:topBar {:visible true}}
:component link-preview/preview}]
:options {:insets {:top? true}}
:component link-preview/view}]
:list-items [{:name :account-list-card
:options {:topBar {:visible true}}
:component account-list-card/preview}
{:name :channel
:options {:topBar {:visible true}}
:component channel/preview-channel}
{:name :community-list
:options {:insets {:top? true}
:topBar {:visible true}}
:component community-list/preview}
:options {:insets {:top? true}}
:component community-list/view}
{:name :preview-lists
:options {:topBar {:visible true}}
:component preview-lists/preview-preview-lists}
{:name :user-list
:options {:topBar {:visible true}}
:component user-list/preview-user-list}
{:name :token-value
:options {:topBar {:visible true}}
:component token-value/preview}]
:loaders [{:name :skeleton
:options {:topBar {:visible true}}
:component skeleton/preview-skeleton}]
:markdown [{:name :texts
:options {:topBar {:visible true}}
:component text/preview-text}
{:name :markdown-list
:options {:topBar {:visible true}}
:component markdown-list/preview-markdown-list}]
:messages [{:name :gap
:options {:topBar {:visible true}}
:component messages-gap/preview-messages-gap}
{:name :system-messages
:options {:topBar {:visible true}}
:component system-message/preview-system-message}
{:name :author
:options {:topBar {:visible true}}
:component messages-author/preview-author}]
:navigation [{:name :bottom-nav-tab
:options {:topBar {:visible true}}
:component bottom-nav-tab/preview-bottom-nav-tab}
{:name :top-nav
:options {:topBar {:visible true}}
:component top-nav/preview-top-nav}
{:name :page-nav
:options {:topBar {:visible true}}
:component page-nav/preview-page-nav}
{:name :floating-shell-button
:options {:topBar {:visible true}}
:component floating-shell-button/preview-floating-shell-button}]
:notifications [{:name :activity-logs
:options {:topBar {:visible true}}
:component activity-logs/preview-activity-logs}
{:name :activity-logs-photos
:options {:topBar {:visible true}}
:component activity-logs-photos/preview-activity-logs-photos}
{:name :toast
:options {:topBar {:visible true}}
:component toast/preview-toasts}
{:name :notification
:options {:topBar {:visible true}}
:component notification/preview-notification}]
:onboarding [{:name :small-option-card
:options {:topBar {:visible true}}
:component small-option-card/preview-small-option-card}]
:password [{:name :tips
:options {:topBar {:visible true}}
:component tips/preview-tips}]
:profile [{:name :profile-card
:options {:topBar {:visible true}}
:component profile-card/preview-profile-card}
{:name :collectible
:options {:topBar {:visible true}}
:component collectible/preview-collectible}
{:name :select-profile
:options {:topBar {:visible true}}
:component select-profile/preview-select-profile}]
:reactions [{:name :react
:options {:topBar {:visible true}}
:component react/preview-react}]
:record-audio [{:name :record-audio
:options {:topBar {:visible true}}
:component record-audio/preview-record-audio}]
:switcher [{:name :switcher-cards
:options {:topBar {:visible true}}
:component switcher-cards/preview-switcher-cards}]
:selectors [{:name :disclaimer
:options {:topBar {:visible true}}
:component disclaimer/preview-disclaimer}
{:name :filter
:options {:topBar {:visible true}}
:component filter/preview}
{:name :selectors
:options {:topBar {:visible true}}
:component selectors/preview-selectors}
{:name :select-reactions
:options {:topBar {:visible true}}
:component selector-reactions/preview}]
:settings [{:name :privacy-option
:options {:topBar {:visible true}}
:component privacy-option/preview-options}
{:name :accounts
:options {:topBar {:visible true}}
:component accounts/preview-accounts}
{:name :settings-list
:options {:topBar {:visible true}}
:component settings-list/preview-settings-list}
{:name :reorder-item
:options {:topBar {:visible true}}
:component reorder-item/preview-reorder-item}
{:name :category
:options {:topBar {:visible true}}
:component category/preview}]
:share [{:name :qr-code
:options {:topBar {:visible true}}
:component qr-code/preview-qr-code}
{:name :share-qr-code
:options {:topBar {:visible true}}
:component share-qr-code/preview-share-qr-code}]
:tabs [{:name :segmented
:options {:topBar {:visible true}}
:component segmented/preview-segmented}
{:name :tabs
:options {:topBar {:visible true}}
:component tabs/preview-tabs}
{:name :account-selector
:options {:topBar {:visible true}}
:component account-selector/preview-this}]
:tags [{:name :context-tags
:options {:topBar {:visible true}}
:component context-tags/preview-context-tags}
{:name :tags
:options {:topBar {:visible true}}
:component tags/preview-tags}
{:name :permission-tag
:options {:topBar {:visible true}}
:component permission-tag/preview-permission-tag}
{:name :status-tags
:options {:topBar {:visible true}}
:component status-tags/preview-status-tags}
{:name :token-tag
:options {:topBar {:visible true}}
:component token-tag/preview-token-tag}]
:text-combinations [{:name :title
:options {:topBar {:visible true}}
:component title/preview-title}]
:wallet [{:name :account-card
:options {:topBar {:visible true}}
:component account-card/preview-account-card}
{:name :account-overview
:options {:topBar {:visible true}}
:component account-overview/preview-account-overview}
{:name :network-amount
:options {:topBar {:visible true}}
:component network-amount/preview}
{:name :network-bridge
:options {:topBar {:visible true}}
:component network-bridge/preview}
{:name :progress-bar
:options {:topBar {:visible true}}
:component progress-bar/preview}
{:name :summary-info
:options {:topBar {:visible true}}
:component summary-info/preview}
{:name :token-input
:options {:topBar {:visible true}}
:component token-input/preview}
{:name :wallet-overview
:options {:topBar {:visible true}}
:component wallet-overview/preview-wallet-overview}]
:keycard [{:name :keycard-component
:options {:topBar {:visible true}}
:component keycard/preview-keycard}]})
(def screens (flatten (map val screens-categories)))
(defn navigation-bar
(defn- navigation-bar
[]
(let [logged-in? (rf/sub [:multiaccount/logged-in?])
has-profiles? (boolean (rf/sub [:profile/profiles-overview]))
@@ -477,48 +366,51 @@
(theme/set-theme :dark)
(rf/dispatch [:init-root root]))))}}]))
(defn theme-switcher
(defn- theme-switcher
[]
[rn/view
{:style {:flex-direction :row
:justify-content :space-between
:padding-horizontal 24
:padding-vertical 12}}
[rn/view {:style style/theme-switcher}
[quo/button {:on-press #(theme/set-theme :light)} "Set light theme"]
[quo/button {:on-press #(theme/set-theme :dark)} "Set dark theme"]])
(defn category-view
(defn- category-view
[]
(let [open? (reagent/atom false)]
(let [open? (reagent/atom false)
on-change #(swap! open? not)]
(fn [category]
[rn/view {:style {:margin-vertical 8}}
[quo/dropdown {:selected @open? :on-change #(swap! open? not) :type :grey}
(clojure.core/name (key category))]
[quo/dropdown
{:selected @open?
:on-change on-change
:type :grey}
(name (key category))]
(when @open?
(for [{:keys [name]} (val category)]
^{:key name}
(for [{category-name :name} (val category)]
^{:key category-name}
[quo/button
{:type :outline
:container-style {:margin-vertical 8}
:on-press #(rf/dispatch [:navigate-to name])}
(clojure.core/name name)]))])))
:on-press #(rf/dispatch [:navigate-to category-name])}
(name category-name)]))])))
(defn main-screen
(defn- main-screen
[]
(fn []
[:<>
[navigation-bar]
[theme-switcher]
[rn/scroll-view
{:flex 1
:padding-bottom 8
:padding-horizontal 16
:background-color (colors/theme-colors colors/white colors/neutral-90)}
[rn/view
(map (fn [category]
^{:key (get category 0)}
[category-view category])
(sort screens-categories))]]]))
[:<>
[navigation-bar]
[theme-switcher]
[rn/scroll-view {:style (style/main)}
(for [category (sort screens-categories)]
^{:key (first category)}
[category-view category])]])
(def screens
(->> screens-categories
(map val)
flatten
(map (fn [subcategory]
(update-in subcategory
[:options :topBar]
merge
{:visible true})))))
(def main-screens
[{:name :quo2-preview
@@ -1,7 +1,6 @@
(ns status-im2.contexts.quo-preview.notifications.notification
(:require [quo2.core :as quo]
[react-native.core :as rn]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.code.snippet :as snippet-preview]
[utils.re-frame :as rf]))
@@ -34,8 +33,7 @@
:status-indicator? true
:online? true
:size :small
:customization-color :blue
:ring-background (resources/get-mock-image :ring)}]
:customization-color :blue}]
:title "Alisher Yakupov accepted your contact request"
:duration 4000
:title-weight :medium
@@ -50,8 +48,7 @@
:status-indicator? true
:online? true
:size :small
:customization-color :blue
:ring-background (resources/get-mock-image :ring)}]
:customization-color :blue}]
:title "Default to semibold title"
:text "The quick brown fox jumped over the lazy dog and ate a potatoe."
:duration 4000
@@ -66,8 +63,7 @@
:status-indicator? true
:online? true
:size :small
:customization-color :blue
:ring-background (resources/get-mock-image :ring)}]
:customization-color :blue}]
:header [rn/view
[quo/info-message
{:type :success
+163 -187
View File
@@ -1,216 +1,178 @@
(ns status-im2.contexts.quo-preview.preview
(:require [clojure.string :as string]
(:require [camel-snake-kebab.core :as camel-snake-kebab]
[clojure.string :as string]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[quo2.theme :as quo.theme]
[react-native.blur :as blur]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.style :as style]
utils.number)
(:require-macros status-im2.contexts.quo-preview.preview))
(def container
{:flex-direction :row
:padding-vertical 8
:flex 1
:align-items :center})
(defn touchable-style
[]
{:flex 1
:align-items :center
:justify-content :center
:padding-horizontal 16
:height 44})
(defn select-style
[]
{:flex 1
:flex-direction :row
:align-items :center
:padding-horizontal 16
:height 44
:border-radius 4
:background-color colors/neutral-20
:border-width 1
:border-color colors/neutral-100})
(defn select-option-style
[selected]
(merge (select-style)
{:margin-vertical 8
:justify-content :center}
(if selected
{:background-color colors/primary-50-opa-30}
{:background-color (colors/theme-colors colors/neutral-20 colors/white)})))
(def label-style
{:flex 0.4
:padding-right 8})
(defn label-view
(defn- label-view
[_ label]
[rn/view {:style label-style}
[rn/text
(when-let [label-color (colors/theme-colors colors/neutral-100 colors/white)]
{:style {:color label-color}})
[rn/view {:style style/label-container}
[rn/text {:style (style/label)}
label]])
(defn modal-container
[]
{:flex 1
:justify-content :center
:padding-horizontal 24
:background-color "rgba(0,0,0,0.4)"})
(defn- humanize
[k]
;; We explicitly convert `k` to string because sometimes it's a number and
;; Clojure would throw an exception.
(-> (if (keyword? k) k (str k))
camel-snake-kebab/->kebab-case-keyword
name
(string/replace "-" " ")
string/capitalize))
(defn modal-view
[]
{:padding-horizontal 16
:padding-vertical 8
:border-radius 8
:flex-direction :column
:margin-vertical 100
:background-color (colors/theme-colors colors/neutral-20 colors/white)})
(defn- key->boolean-label
[k]
(let [label (humanize k)]
(if (string/ends-with? label "?")
label
(str label "?"))))
(defn customizer-boolean
(defn- key->text-label
[k]
(str (humanize k) ":"))
(defn- customizer-boolean
[{:keys [label state] :as args}]
(let [state* (reagent/cursor state [(:key args)])]
[rn/view {:style container}
(let [label (or label (key->boolean-label (:key args)))
field-value (reagent/cursor state [(:key args)])
active? @field-value]
[rn/view {:style style/field-row}
[label-view state label]
[rn/view
{:style {:flex-direction :row
:flex 0.6
:border-radius 4
:background-color (colors/theme-colors colors/neutral-20 colors/white)
:border-width 1
:border-color (colors/theme-colors colors/neutral-100 colors/white)}}
[rn/touchable-opacity
{:style (merge (touchable-style) {:background-color (when @state* colors/primary-50-opa-30)})
:on-press #(reset! state* true)}
[rn/text
[rn/view {:style (style/boolean-container)}
[rn/pressable
{:style (style/boolean-button {:active? active? :left? true})
:on-press #(reset! field-value true)}
[rn/text {:style (style/field-text active?)}
"True"]]
[rn/view
{:width 1
:margin-vertical 4
:background-color (colors/theme-colors colors/neutral-20 colors/white)}]
[rn/touchable-opacity
{:style (merge (touchable-style)
{:background-color (when (not @state*) colors/primary-50-opa-30)})
:on-press #(reset! state* false)}
[rn/text {}
[rn/pressable
{:style (style/boolean-button {:active? (not active?) :left? false})
:on-press #(reset! field-value false)}
[rn/text {:style (style/field-text (not active?))}
"False"]]]]))
(defn customizer-text
(defn- customizer-text
[{:keys [label state limit suffix] :as args}]
(let [state* (reagent/cursor state [(:key args)])]
[rn/view {:style container}
(let [label (or label (key->text-label (:key args)))
field-value (reagent/cursor state [(:key args)])]
[rn/view {:style style/field-row}
[label-view state label]
[rn/view {:style {:flex 0.6}}
[rn/view {:style style/field-column}
[rn/text-input
(merge
{:value @state*
{:value @field-value
:show-cancel false
:style {:border-radius 4
:border-width 1
:color (colors/theme-colors colors/neutral-100 colors/white)
:border-color (colors/theme-colors colors/neutral-100 colors/white)}
:keyboard-appearance (theme/theme-value :light :dark)
:on-change-text #(do
(reset! state* (if (and suffix (> (count %) (count @state*)))
(str (string/replace % suffix "") suffix)
%))
(reagent/flush))}
:style (style/field-container false)
:keyboard-appearance (quo.theme/theme-value :light :dark)
:on-change-text (fn [text]
(reset! field-value (if (and suffix
(> (count text) (count @field-value)))
(str (string/replace text suffix "") suffix)
text))
(reagent/flush))}
(when limit
{:max-length limit}))]]]))
(defn customizer-number
(defn- customizer-number
[{:keys [label state default] :as args}]
(let [state* (reagent/cursor state [(:key args)])]
[rn/view {:style container}
(let [label (or label (key->text-label (:key args)))
field-value (reagent/cursor state [(:key args)])]
[rn/view {:style style/field-row}
[label-view state label]
[rn/view {:style {:flex 0.6}}
[rn/view {:style style/field-column}
[rn/text-input
(merge
{:value (str @state*)
{:value (str @field-value)
:show-cancel false
:style {:border-radius 4
:border-width 1
:color (colors/theme-colors colors/neutral-100 colors/white)
:border-color (colors/theme-colors colors/neutral-100 colors/white)}
:keyboard-appearance (theme/theme-value :light :dark)
:on-change-text (fn [v]
(reset! state* (utils.number/parse-int v default))
:style (style/field-container false)
:keyboard-appearance (quo.theme/theme-value :light :dark)
:on-change-text (fn [text]
(reset! field-value (utils.number/parse-int text default))
(reagent/flush))})]]]))
(defn value-for-key
(defn- find-selected-option
[id v]
(:value (first (filter #(= (:key %) id) v))))
(first (filter #(= (:key %) id) v)))
(defn customizer-select
(defn- customizer-select-modal
[{:keys [open options field-value]}]
[rn/modal
{:visible @open
:on-request-close #(reset! open false)
:status-bar-translucent true
:transparent true
:animation :slide}
[rn/view {:style (style/modal-overlay)}
[rn/view {:style (style/modal-container)}
[rn/scroll-view {:shows-vertical-scroll-indicator false}
(doall
(for [{k :key v :value} options
:let [v (or v (humanize k))]]
^{:key k}
[rn/pressable
{:style (style/select-option (= @field-value k))
:on-press (fn []
(reset! open false)
(reset! field-value k))}
[rn/text {:style (style/field-text (= @field-value k))}
v]]))]
[rn/view {:style (style/footer)}
[rn/pressable
{:style (style/select-button)
:on-press (fn []
(reset! field-value nil)
(reset! open false))}
[rn/text {:style (style/field-text false)}
"Clear"]]
[rn/view {:style {:width 16}}]
[rn/touchable-opacity
{:style (style/select-button)
:on-press #(reset! open false)}
[rn/text {:style (style/field-text false)}
"Close"]]]]]])
(defn- customizer-select-button
[{:keys [open selected-key]}]
[rn/pressable
{:style (style/select-container)
:on-press #(reset! open true)}
[rn/text
{:style (style/field-select)
:number-of-lines 1}
(if selected-key
(humanize selected-key)
"Select option")]
[rn/view
[quo/icon :i/chevron-right]]])
(defn- customizer-select
[]
(let [open (reagent/atom nil)]
(fn [{:keys [label state options] :as args}]
(let [state* (reagent/cursor state [(:key args)])
selected (value-for-key @state* options)]
[rn/view {:style container}
(let [label (or label (key->text-label (:key args)))
field-value (reagent/cursor state [(:key args)])
selected-key (:key (find-selected-option @field-value options))]
[rn/view {:style style/field-row}
[label-view state label]
[rn/view {:style {:flex 0.6}}
[rn/modal
{:visible @open
:on-request-close #(reset! open false)
:statusBarTranslucent true
:transparent true
:animation :slide}
[rn/view {:style (modal-container)}
[rn/view {:style (modal-view)}
[rn/scroll-view
(doall
(for [{k :key v :value} options]
^{:key k}
[rn/touchable-opacity
{:style (select-option-style (= @state* k))
:on-press #(do
(reset! open false)
(reset! state* k))}
[rn/text {:color (if (= @state* k) :link :secondary)}
v]]))]
[rn/view
{:flex-direction :row
:padding-top 20
:margin-top 10
:border-top-width 1
:border-top-color (colors/theme-colors colors/neutral-100 colors/white)}
[rn/touchable-opacity
{:style (select-option-style false)
:on-press #(do
(reset! state* nil)
(reset! open false))}
[rn/text "Clear"]]
[rn/view {:width 16}]
[rn/touchable-opacity
{:style (select-option-style false)
:on-press #(reset! open false)}
[rn/text "Close"]]]]]]
[rn/touchable-opacity
{:style (select-style)
:on-press #(reset! open true)}
(if selected
[rn/text {:color :link} selected]
[rn/text "Select option"])
[rn/view
{:position :absolute
:right 16
:top 0
:bottom 0
:justify-content :center}
[rn/text "↓"]]]]]))))
[rn/view {:style style/field-column}
[customizer-select-modal
{:open open
:options options
:field-value field-value}]
[customizer-select-button {:open open :selected-key selected-key}]]]))))
(defn customizer
[state descriptors]
[rn/view
{:style {:flex 1}
:padding-horizontal 16}
{:style {:flex-shrink 1
:padding-horizontal 20}}
(doall
(for [desc descriptors
:let [descriptor (merge desc {:state state})]]
@@ -237,19 +199,6 @@
{:key k :value (string/capitalize (name k))})))}
opts)))
(comment
[{:label "Show error:"
:key :error
:type :boolean}
{:label "Label:"
:key :label
:type :text}
{:label "Type:"
:key :type
:type :select
:options [{:key :primary :value "Primary"}
{:key :secondary :value "Secondary"}]}])
(defn blur-view
[{:keys [show-blur-background? image height blur-view-props style]} children]
[rn/view
@@ -262,8 +211,7 @@
:overflow :hidden}}
[rn/image
{:source (or image (resources/get-mock-image :community-cover))
:style {:height "100%"
:width "100%"}}]
:style {:height "100%" :width "100%"}}]
[blur/view
(merge {:style {:position :absolute
:top 0
@@ -271,9 +219,7 @@
:left 0
:right 0}
:blur-amount 10
:overlay-color (colors/theme-colors
colors/white-opa-70
colors/neutral-80-opa-80)}
:overlay-color (colors/theme-colors colors/white-opa-70 colors/neutral-80-opa-80)}
blur-view-props)]])
[rn/view
{:style (merge {:position :absolute
@@ -281,3 +227,33 @@
:padding-horizontal 16}
style)}
children]])
(defn preview-container
[{:keys [state descriptor blur?
component-container-style
blur-container-style blur-view-props blur-height show-blur-background?]
:or {blur-height 200}}
component]
[rn/scroll-view
{:style (style/panel-basic)
:shows-vertical-scroll-indicator false}
[rn/pressable {:on-press rn/dismiss-keyboard!}
[rn/view {:style style/customizer-container}
[customizer state descriptor]]
[rn/view
(merge {:style style/component-container}
component-container-style)
(if blur?
[blur-view
{:show-blur-background? show-blur-background?
:height blur-height
:style (merge {:width "100%"
:flex-grow 1}
(when-not show-blur-background?
{:padding-horizontal 0
:top 0})
blur-container-style)
:blur-view-props (merge {:blur-type (quo.theme/get-theme)}
blur-view-props)}
component]
component)]]])
@@ -0,0 +1,179 @@
(ns status-im2.contexts.quo-preview.style
(:require [quo2.foundations.colors :as colors]
[quo2.foundations.typography :as typography]))
;;;; Form fields
(def field-border-radius 12)
(def field-flex-percentage 0.6)
(def text-default typography/paragraph-1)
(defn field-active-bg-color
[]
(colors/theme-colors colors/primary-50 colors/primary-60))
(defn field-default-color
[]
(colors/theme-colors colors/neutral-100 colors/white))
(defn field-default-bg-color
[]
(colors/theme-colors colors/neutral-20 colors/neutral-80))
(defn field-default-border-color
[]
(colors/theme-colors colors/neutral-30 colors/neutral-70))
(def field-row
{:flex-direction :row
:padding-vertical 6
:align-items :center})
(def field-column
{:flex field-flex-percentage})
(defn field-container
[active?]
(merge text-default
{:color (if active?
(colors/theme-colors colors/white colors/white-opa-95)
(colors/theme-colors colors/neutral-100 colors/white))
:border-width 1
:border-color (field-default-border-color)
:border-radius field-border-radius
:padding-vertical 9
:padding-horizontal 12}))
(defn field-text
[active?]
(merge text-default
{:color (if active?
(colors/theme-colors colors/white colors/white-opa-95)
(field-default-color))}))
(def customizer-container
{:flex-shrink 1
:padding-top 12})
(defn select-container
[]
(merge (field-container false)
{:flex-direction :row
:align-items :center
:border-radius field-border-radius
:background-color (field-default-bg-color)
:border-width 1
:border-color (field-default-border-color)}))
(defn field-select
[]
(merge text-default
{:flex-grow 1
:color (field-default-color)}))
(defn select-option
[selected?]
(merge (field-container selected?)
{:justify-content :center
:flex 1
:margin-vertical 4}
(if selected?
{:border-color (field-active-bg-color)
:background-color (field-active-bg-color)}
{:background-color (field-default-bg-color)})))
(defn select-button
[]
(merge (select-option false) {:align-items :center}))
(def label-container
{:flex (- 1 field-flex-percentage)
:padding-right 8})
(defn label
[]
(merge text-default
typography/font-medium
{:color (field-default-color)}))
(defn boolean-container
[]
{:flex-direction :row
:flex field-flex-percentage
:border-radius field-border-radius})
(defn boolean-button
[{:keys [active? left?]}]
(cond-> {:flex 1
:align-items :center
:justify-content :center
:padding-vertical 9
:padding-horizontal 12
:border-color (if active?
(field-active-bg-color)
(field-default-border-color))
:border-top-width 1
:border-bottom-width 1
:background-color (if active?
(field-active-bg-color)
(field-default-bg-color))}
left?
(assoc :border-top-left-radius field-border-radius
:border-bottom-left-radius field-border-radius
:border-left-width 1)
(not left?)
(assoc :border-top-right-radius field-border-radius
:border-bottom-right-radius field-border-radius
:border-right-width 1)))
;;;; Modal
(defn modal-overlay
[]
{:flex 1
:justify-content :center
:padding-horizontal 24
:background-color (colors/theme-colors colors/neutral-80-opa-60 colors/neutral-80-opa-80)})
(defn modal-container
[]
{:padding-horizontal 16
:padding-vertical 8
:border-radius 12
:margin-vertical 100
:background-color (colors/theme-colors colors/white colors/neutral-95)})
(defn footer
[]
{:flex-direction :row
:padding-top 10
:margin-top 10
:border-top-width 1
:border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-80)})
;;;; Misc
(defn panel-basic
[]
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1})
(def component-container
{:flex-grow 1
:min-height 200
:padding-vertical 20
:padding-horizontal 20})
(defn main
[]
{:flex 1
:padding-bottom 8
:padding-horizontal 16
:background-color (colors/theme-colors colors/white colors/neutral-90)})
(def theme-switcher
{:flex-direction :row
:justify-content :space-between
:padding-horizontal 24
:padding-vertical 12})
@@ -141,7 +141,7 @@
:group-avatar [quo2/group-avatar-tag (:label @state)
{:blur? (:blur? @state)
:size :x-small
:size 20
:customization-color :purple}]
:public-key [quo2/public-key-tag
@@ -4,8 +4,8 @@
[status-im.data-store.chats :as data-store.chats]
[status-im2.common.toasts.events :as toasts]
[status-im2.constants :as constants]
[status-im2.contexts.shell.activity-center.notification-types :as types]
[status-im2.contexts.chat.events :as chat.events]
[status-im2.contexts.shell.activity-center.notification-types :as types]
[taoensso.timbre :as log]
[utils.collection :as collection]
[utils.i18n :as i18n]
@@ -502,33 +502,35 @@
{:events [:activity-center.notifications/show-toasts]}
[{:keys [db]} new-notifications]
(let [my-public-key (get-in db [:profile/profile :public-key])]
(reduce (fn [cofx {:keys [author type accepted dismissed message name] :as x}]
(reduce (fn [cofx {:keys [author chat-id type accepted dismissed message name] :as x}]
(let [user-avatar {:full-name name
:status-indicator? true
:online? nil
:size :small
:ring? false}]
:ring? true}]
(cond
(and (not= author my-public-key)
(= type types/contact-request)
(not accepted)
(not dismissed))
(toasts/upsert cofx
{:user user-avatar
:icon-color colors/primary-50-opa-40
:title (i18n/label :t/contact-request-sent-toast
{:name name})
:text (get-in message [:content :text])})
{:user user-avatar
:user-public-key author
:icon-color colors/primary-50-opa-40
:title (i18n/label :t/contact-request-sent-toast
{:name name})
:text (get-in message [:content :text])})
(and (= author my-public-key) ;; we show it for user who sent the request
(= type types/contact-request)
accepted
(not dismissed))
(toasts/upsert cofx
{:user user-avatar
:icon-color colors/success-50-opa-40
:title (i18n/label :t/contact-request-accepted-toast
{:name (or name (:alias message))})})
{:user user-avatar
:user-public-key chat-id ;; user public key who accepted the request
:icon-color colors/success-50-opa-40
:title (i18n/label :t/contact-request-accepted-toast
{:name (or name (:alias message))})})
:else
cofx)))
{:db db}
@@ -1,15 +1,15 @@
(ns status-im2.contexts.shell.activity-center.notification.common.view
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[quo2.foundations.colors :as colors]
[status-im.multiaccounts.core :as multiaccounts]
[status-im2.contexts.shell.activity-center.notification.common.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def tag-params
{:size :small
{:size 20
:customization-color :blue
:style style/user-avatar-tag
:text-style style/user-avatar-tag-text
@@ -22,7 +22,8 @@
{:color :purple
:size :small
:style style/user-avatar-tag
:text-style style/user-avatar-tag-text}
:text-style style/user-avatar-tag-text
:ring? false}
primary-name
(multiaccounts/displayed-photo contact)]))
@@ -67,7 +67,7 @@
:context [[common/user-avatar-tag author]
(i18n/label :t/added-you-to)
[quo/group-avatar-tag chat-name
{:size :x-small
{:size 20
:customization-color :purple}]]
:items (when-not (or accepted dismissed)
[{:type :button
+15 -12
View File
@@ -1,20 +1,21 @@
(ns status-im2.events
(:require [status-im2.common.json-rpc.events]
(:require [status-im.bottom-sheet.events]
[status-im.keycard.core :as keycard]
status-im2.common.font
[status-im2.common.json-rpc.events]
status-im2.common.password-authentication.events
status-im2.common.theme.events
[status-im2.common.toasts.events]
[status-im2.contexts.add-new-contact.events]
status-im2.contexts.chat.events
status-im2.contexts.chat.photo-selector.events
status-im2.contexts.communities.overview.events
status-im2.contexts.onboarding.events
[status-im.bottom-sheet.events]
[status-im2.db :as db]
[utils.re-frame :as rf]
status-im2.contexts.profile.events
status-im2.contexts.shell.share.events
status-im2.contexts.syncing.events
status-im2.contexts.chat.events
status-im2.common.password-authentication.events
status-im2.contexts.communities.overview.events
status-im2.contexts.chat.photo-selector.events
status-im2.common.theme.events
status-im2.contexts.profile.events
[status-im.keycard.core :as keycard]))
[status-im2.db :as db]
[utils.re-frame :as rf]))
(rf/defn start-app
{:events [:app-started]}
@@ -26,5 +27,7 @@
:biometric/get-supported-biometric-type nil
;;app starting flow continues in get-profiles-overview
:profile/get-profiles-overview #(rf/dispatch
[:profile/get-profiles-overview-success %])}
[:profile/get-profiles-overview-success %])
:font/get-font-file-for-initials-avatar #(rf/dispatch
[:font/init-font-file-for-initials-avatar %])}
(keycard/init)))
+3 -4
View File
@@ -2,9 +2,9 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.communities.core :as communities]
[status-im.contact.core :as contact]
[status-im.group-chats.core :as group-chat]
[status-im.group-chats.db :as group-chats.db]
[status-im.multiaccounts.core :as multiaccounts]
[status-im2.constants :as constants]
[status-im2.contexts.chat.composer.constants :as composer.constants]
[status-im2.contexts.chat.events :as chat.events]))
@@ -298,10 +298,9 @@
:chats/photo-path
:<- [:contacts/contacts]
:<- [:profile/multiaccount]
:<- [:mediaserver/port]
(fn [[contacts {:keys [public-key] :as multiaccount}] [_ id]]
(multiaccounts/displayed-photo (or (when (= id public-key) multiaccount)
(get contacts id)))))
(let [contact (or (when (= id public-key) multiaccount) (get contacts id))]
(contact/displayed-photo contact))))
(re-frame/reg-sub
:chats/unread-messages-number
+45 -29
View File
@@ -1,16 +1,16 @@
(ns status-im2.subs.contact
(:require [clojure.string :as string]
[utils.i18n :as i18n]
[quo2.theme :as theme]
[re-frame.core :as re-frame]
[status-im.contact.db :as contact.db]
[status-im.ethereum.core :as ethereum]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[status-im.utils.gfycat.core :as gfycat]
[utils.image-server :as image-server]
[utils.collection]
[status-im2.constants :as constants]
[quo2.theme :as theme]))
[utils.collection]
[utils.i18n :as i18n]
[utils.image-server :as image-server]))
(re-frame/reg-sub
::query-current-chat-contacts
@@ -32,28 +32,42 @@
(get multiaccount :profile-pictures-visibility)))
(defn- replace-contact-image-uri
[contact port contact-identity]
(let [theme (theme/get-theme)
contact-images (:images contact)
contact-images (reduce (fn [acc image]
(let [image-name (:type image)
; We pass the clock so that we reload the image if the image
; is updated
clock (:clock image)
uri (image-server/get-contact-image-uri port
contact-identity
image-name
clock
theme)]
(assoc-in acc [(keyword image-name) :uri] uri)))
contact-images
(vals contact-images))]
(assoc contact :images contact-images)))
[contact port public-key font-file]
(let [theme (theme/get-theme)
{:keys [images ens-name]} contact
images
(reduce (fn [acc image]
(let [image-name (:type image)
clock (:clock image)
uri (image-server/get-contact-image-uri-fn
{:port port
:public-key public-key
:image-name image-name
; We pass the clock so that we reload the
; image if the image is updated
:clock clock
:theme theme
:override-ring? (when ens-name false)})]
(assoc-in acc [(keyword image-name) :fn] uri)))
images
(vals images))
images (if (seq images)
images
{:thumbnail
{:fn (image-server/get-initials-avatar-uri-fn
{:port port
:public-key public-key
:override-ring? (when ens-name false)
:theme theme
:font-file font-file})}})]
(assoc contact :images images)))
(defn- reduce-contacts-image-uri
[contacts port]
[contacts port font-file]
(reduce-kv (fn [acc public-key contact]
(let [contact (replace-contact-image-uri contact port public-key)]
(let [contact (replace-contact-image-uri contact port public-key font-file)]
(assoc acc public-key contact)))
{}
contacts))
@@ -64,9 +78,10 @@
:<- [::profile-pictures-visibility]
:<- [:multiaccount/public-key]
:<- [:mediaserver/port]
(fn [[contacts profile-pictures-visibility public-key port]]
:<- [:initials-avatar-font-file]
(fn [[contacts profile-pictures-visibility public-key port font-file]]
(let [contacts (contact.db/enrich-contacts contacts profile-pictures-visibility public-key)]
(reduce-contacts-image-uri contacts port))))
(reduce-contacts-image-uri contacts port font-file))))
(re-frame/reg-sub
:contacts/active
@@ -175,10 +190,10 @@
contacts)))))
(defn- enrich-contact
[_ contact-identity ens-name port]
[_ contact-identity ens-name port font-file]
(let [contact (contact.db/enrich-contact
(contact.db/public-key-and-ens-name->new-contact contact-identity ens-name))]
(replace-contact-image-uri contact port contact-identity)))
(replace-contact-image-uri contact port contact-identity font-file)))
(re-frame/reg-sub
:contacts/current-contact
@@ -186,11 +201,12 @@
:<- [:contacts/current-contact-identity]
:<- [:contacts/current-contact-ens-name]
:<- [:mediaserver/port]
(fn [[contacts contact-identity ens-name port]]
:<- [:initials-avatar-font-file]
(fn [[contacts contact-identity ens-name port font-file]]
(let [contact (get contacts contact-identity)]
(cond-> contact
(nil? contact)
(enrich-contact contact-identity ens-name port)))))
(enrich-contact contact-identity ens-name port font-file)))))
(re-frame/reg-sub
:contacts/contact-by-identity
+8 -6
View File
@@ -1,8 +1,8 @@
(ns status-im2.subs.contact-test
(:require [cljs.test :refer [is testing]]
[re-frame.db :as rf-db]
[test-helpers.unit :as h]
status-im2.subs.contact
[test-helpers.unit :as h]
[utils.re-frame :as rf]))
(def contacts-sample-data
@@ -74,14 +74,13 @@
:has-added-us? true
:contact-request-state 1}}})
(def expected-sorted-contacts
(def expected-sorted-contacts-without-images
[{:title "F"
:data [{:active? true
:last-updated 1672582629695
:mutual? true
:blocked? false
:contactRequestClock 0
:images {}
:added? true
:name "slim.shady"
:primary-name "fslim.shady"
@@ -105,7 +104,6 @@
:mutual? true
:blocked? false
:contactRequestClock 0
:images {}
:added? true
:name "slim.shady"
:primary-name "islim.shady"
@@ -129,7 +127,6 @@
:mutual? true
:blocked? false
:contactRequestClock 0
:images {}
:added? true
:name "slim.shady"
:primary-name "rslim.shady"
@@ -148,6 +145,10 @@
:has-added-us? true
:contact-request-state 1}]}])
(defn remove-contact-images
[{:keys [data] :as contact}]
(assoc contact :data (mapv #(dissoc % :images) data)))
(h/deftest-sub :contacts/sorted-and-grouped-by-first-letter
[sub-name]
(testing "Returning empty sequence when no contacts"
@@ -170,4 +171,5 @@
(dissoc contact :identicon))
%)))
(rf/sub [sub-name]))]
(is (= expected-sorted-contacts contact-list-without-identicons)))))
(is (= expected-sorted-contacts-without-images
(mapv remove-contact-images contact-list-without-identicons))))))
+61 -32
View File
@@ -6,9 +6,9 @@
[status-im.ethereum.core :as ethereum]
[status-im.fleet.core :as fleet]
[status-im.multiaccounts.db :as multiaccounts.db]
[status-im2.constants :as constants]
[utils.image-server :as image-server]
[utils.security.core :as security]
[status-im2.constants :as constants]))
[utils.security.core :as security]))
(re-frame/reg-sub
:profile/customization-color
@@ -16,21 +16,44 @@
(fn [{:keys [customization-color]}]
(or customization-color constants/profile-default-color)))
(re-frame/reg-sub
:profile/onboarding-placeholder-avatar
:<- [:mediaserver/port]
:<- [:initials-avatar-font-file]
(fn [[port font-file] [_ profile-pic]]
{:fn
(if profile-pic
(image-server/get-account-image-uri-fn {:port port
:image-name profile-pic
:override-ring? false
:theme (theme/get-theme)})
(image-server/get-initials-avatar-uri-fn {:port port
:theme (theme/get-theme)
:override-ring? false
:font-file font-file}))}))
(re-frame/reg-sub
:profile/login-profiles-picture
:<- [:profile/profiles-overview]
:<- [:mediaserver/port]
(fn [[multiaccounts port] [_ target-key-uid]]
(let [image-name (-> multiaccounts
(get-in [target-key-uid :images])
first
:type)]
(when image-name
(image-server/get-account-image-uri {:port port
:image-name image-name
:key-uid target-key-uid
:theme (theme/get-theme)
:ring? true})))))
:<- [:initials-avatar-font-file]
(fn [[multiaccounts port font-file] [_ target-key-uid]]
(let [{:keys [images ens-name?] :as multiaccount} (get multiaccounts target-key-uid)
image-name (-> images first :type)
override-ring? (not ens-name?)]
(when multiaccount
{:fn
(if image-name
(image-server/get-account-image-uri-fn {:port port
:image-name image-name
:key-uid target-key-uid
:theme (theme/get-theme)
:override-ring? override-ring?})
(image-server/get-initials-avatar-uri-fn {:port port
:key-uid target-key-uid
:theme (theme/get-theme)
:override-ring? override-ring?
:font-file font-file}))}))))
(re-frame/reg-sub
:multiaccount/public-key
@@ -224,30 +247,36 @@
(pos? (count (get multiaccount :images)))))
(defn- replace-multiaccount-image-uri
[multiaccount port]
(let [public-key (:public-key multiaccount)
theme (theme/get-theme)
images (:images multiaccount)
images (reduce (fn [acc current]
(let [key-uid (:keyUid current)
image-name (:type current)
uri (image-server/get-account-image-uri {:port port
:public-key public-key
:image-name image-name
:key-uid key-uid
:theme theme
:ring? true})]
(conj acc (assoc current :uri uri))))
[]
images)]
(assoc multiaccount :images images)))
[multiaccount port font-file avatar-opts]
(let [{:keys [key-uid ens-name? images]} multiaccount
theme (theme/get-theme)
avatar-opts (assoc avatar-opts :override-ring? (when ens-name? false))
images-with-uri (mapv (fn [{key-uid :keyUid image-name :type :as image}]
(let [uri-fn (image-server/get-account-image-uri-fn
(merge {:port port
:image-name image-name
:key-uid key-uid
:theme theme}
avatar-opts))]
(assoc image :fn uri-fn)))
images)
new-images (if (seq images-with-uri)
images-with-uri
[{:fn (image-server/get-initials-avatar-uri-fn
(merge {:port port
:key-uid key-uid
:theme theme
:font-file font-file}
avatar-opts))}])]
(assoc multiaccount :images new-images)))
(re-frame/reg-sub
:profile/multiaccount
:<- [:profile/profile]
:<- [:mediaserver/port]
(fn [[multiaccount port]]
(replace-multiaccount-image-uri multiaccount port)))
:<- [:initials-avatar-font-file]
(fn [[multiaccount port font-file] [_ avatar-opts]]
(replace-multiaccount-image-uri multiaccount port font-file avatar-opts)))
(re-frame/reg-sub
:profile/login-profile
+1
View File
@@ -75,6 +75,7 @@
(reg-root-key-sub :password-authentication :password-authentication)
(reg-root-key-sub :shell/floating-screens :shell/floating-screens)
(reg-root-key-sub :shell/loaded-screens :shell/loaded-screens)
(reg-root-key-sub :initials-avatar-font-file :initials-avatar-font-file)
;;NOTE this one is not related to ethereum network
;; it is about cellular network/ wifi network
+19 -15
View File
@@ -1,12 +1,12 @@
(ns status-im2.subs.shell
(:require [utils.i18n :as i18n]
[re-frame.core :as re-frame]
[utils.datetime :as datetime]
(:require [re-frame.core :as re-frame]
[status-im.multiaccounts.core :as multiaccounts]
[status-im2.common.resources :as resources]
[status-im2.config :as config]
[status-im2.constants :as constants]
[status-im2.common.resources :as resources]
[status-im.multiaccounts.core :as multiaccounts]
[status-im2.contexts.shell.jump-to.constants :as shell.constants]))
[status-im2.contexts.shell.jump-to.constants :as shell.constants]
[utils.datetime :as datetime]
[utils.i18n :as i18n]))
;; Helper Functions
(defn community-avatar
@@ -79,13 +79,11 @@
:counter-label (:unviewed-mentions-count chat)})))
(defn one-to-one-chat-card
[contact names chat id communities]
(let [images (:images contact)
profile-picture (:uri (or (:thumbnail images) (:large images) (first images)))]
{:title (first names)
:avatar-params {:full-name (first names)
:profile-picture (when profile-picture
(str profile-picture "&addRing=0"))}
[contact names profile-picture chat id communities]
(let [display-name (first names)]
{:title display-name
:avatar-params {:full-name display-name
:profile-picture profile-picture}
:customization-color (or (:customization-color contact) :primary)
:content (get-card-content
{:chat chat
@@ -151,10 +149,16 @@
(fn [[_ id] _]
[(re-frame/subscribe [:contacts/contact-by-identity id])
(re-frame/subscribe [:contacts/contact-two-names-by-identity id])
(re-frame/subscribe [:chats/photo-path id])
(re-frame/subscribe [:chats/chat id])
(re-frame/subscribe [:communities])])
(fn [[contact names chat communities] [_ id]]
(one-to-one-chat-card contact names chat id communities)))
(fn [[contact names profile-picture chat communities] [_ id]]
(one-to-one-chat-card contact
names
profile-picture
chat
id
communities)))
(re-frame/reg-sub
:shell/private-group-chat-card
+187 -4
View File
@@ -1,13 +1,43 @@
(ns utils.image-server
(:require [utils.datetime :as datetime]))
(:require
[react-native.fs :as utils.fs]
[react-native.platform :as platform]
status-im.utils.pixel-ratio
[status-im2.constants :as constants]
[utils.datetime :as datetime]))
(def ^:const image-server-uri-prefix "https://localhost:")
(def ^:const account-images-action "/accountImages")
(def ^:const account-initials-action "/accountInitials")
(def ^:const contact-images-action "/contactImages")
(def ^:const generate-qr-action "/GenerateQRCode")
(def ^:const status-profile-base-url "https://join.status.im/u/")
(def ^:const status-profile-base-url-without-https "join.status.im/u/")
(defn get-font-file-ready
"setup font file and get the absolute path to it
this font file is passed to status-go later to render the initials avatar
for ios, it's located at main-bundle-path
for android, it's located in the assets dir which can not be accessed by status-go
so we copy one to the cache directory"
[callback]
(if platform/android?
(let [cache-dir (utils.fs/cache-dir)
font-file-name (:android constants/initials-avatar-font-conf)
src (str "fonts/" font-file-name)
dest (str cache-dir "/" font-file-name)
copy #(utils.fs/copy-assets src dest)
cb #(callback dest)]
(.then (utils.fs/file-exists? dest)
(fn [exists?]
(if exists?
(cb)
(.then (copy) cb)))))
(callback (str (utils.fs/main-bundle-path)
"/"
(:ios constants/initials-avatar-font-conf)))))
(defn timestamp [] (datetime/timestamp))
(defn current-theme-index
@@ -26,7 +56,22 @@
4))
(defn get-account-image-uri
[{:keys [port public-key image-name key-uid theme ring?]}]
"fn to get the avatar uri when multiaccount has custom image set
not directly called, check `get-account-image-uri-fn`
color formats (for all color options):
#RRGGBB
#RRGGBBAA
rgb(255,255,255)
rgba(255,255,255,0.1) note alpha is 0-1
non-placeholder-avatar: requires at least one of `public-key` or `key-uid`
placeholder-avatar: pass image file path as `image-name`
`indicator-size` is outer indicator radius
`indicator-size` - `indicator-border` is inner indicator radius"
[{:keys [port public-key image-name key-uid size theme indicator-size
indicator-border indicator-color ring?]}]
(str image-server-uri-prefix
port
account-images-action
@@ -36,15 +81,130 @@
key-uid
"&imageName="
image-name
"&size="
(Math/round (* size status-im.utils.pixel-ratio/ratio))
"&theme="
(current-theme-index theme)
"&clock="
(timestamp)
"&indicatorColor="
(js/encodeURIComponent indicator-color)
"&indicatorSize="
(* indicator-size status-im.utils.pixel-ratio/ratio)
"&indicatorBorder="
(* indicator-border status-im.utils.pixel-ratio/ratio)
"&addRing="
(if ring? 1 0)))
(defn get-account-image-uri-fn
"pass the result fn to user-avatar component as `:profile-picture`
use this fn in subs to set multiaccount `:images` as [{:fn ...}]
pass the image to user-avatar
user-avatar can fill the rest style related options
set `override-ring?` to a non-nil value to override `ring?`, mainly used to
hide ring for account with ens name
check `get-account-image-uri` for color formats"
[{:keys [port public-key key-uid image-name theme override-ring?]}]
(fn [{:keys [size indicator-size indicator-border indicator-color ring?
override-theme]}]
(get-account-image-uri
{:port port
:image-name image-name
:size size
:public-key public-key
:key-uid key-uid
:theme (if (nil? override-theme) theme override-theme)
:indicator-size indicator-size
:indicator-border indicator-border
:indicator-color indicator-color
:ring? (if (nil? override-ring?) ring? override-ring?)})))
(defn get-initials-avatar-uri
"fn to get the avatar uri when account/contact/placeholder has no custom pic set
not directly called, check `get-account-initials-uri-fn`
multiaccount: at least one of `key-uid`, `public-key` is required to render the ring
contact: `public-key` is required to render the ring
check `get-account-image-uri` for color formats
check `get-font-file-ready` for `font-file`
`uppercase-ratio` is the uppercase-height/line-height for `font-file`"
[{:keys [port public-key key-uid theme ring? length size background-color color
font-size font-file uppercase-ratio indicator-size indicator-border
indicator-color full-name]}]
(str
image-server-uri-prefix
port
account-initials-action
"?publicKey="
public-key
"&keyUid="
key-uid
"&length="
length
"&size="
(Math/round (* size status-im.utils.pixel-ratio/ratio))
"&bgColor="
(js/encodeURIComponent background-color)
"&color="
(js/encodeURIComponent color)
"&fontSize="
(* font-size status-im.utils.pixel-ratio/ratio)
"&fontFile="
(js/encodeURIComponent font-file)
"&uppercaseRatio="
uppercase-ratio
"&theme="
(current-theme-index theme)
"&clock="
"&name="
(js/encodeURIComponent full-name)
(timestamp)
"&indicatorColor="
(js/encodeURIComponent indicator-color)
"&indicatorSize="
(* indicator-size status-im.utils.pixel-ratio/ratio)
"&indicatorBorder="
(* indicator-border status-im.utils.pixel-ratio/ratio)
"&addRing="
(if ring? 1 0)))
(defn get-initials-avatar-uri-fn
"return a fn that calls `get-account-initials-uri`
pass the fn to user-avatar component to fill the style related options
check `get-account-image-uri` for color formats
check `get-font-file-ready` for `font-file`
check `get-account-image-uri-fn` for `override-ring?`"
[{:keys [port public-key key-uid theme override-ring? font-file]}]
(fn [{:keys [full-name length size background-color font-size color
indicator-size indicator-border indicator-color ring?
override-theme]}]
(get-initials-avatar-uri {:port port
:public-key public-key
:key-uid key-uid
:full-name full-name
:length length
:size size
:background-color background-color
:theme (if (nil? override-theme) theme override-theme)
:ring? (if (nil? override-ring?) ring? override-ring?)
:font-size font-size
:color color
:font-file font-file
:uppercase-ratio (:uppercase-ratio constants/initials-avatar-font-conf)
:indicator-size indicator-size
:indicator-border indicator-border
:indicator-color indicator-color})))
(defn get-contact-image-uri
[port public-key image-name clock theme]
[{:keys [port public-key image-name clock theme indicator-size indicator-border
indicator-color size ring?]}]
(str image-server-uri-prefix
port
contact-images-action
@@ -52,11 +212,34 @@
public-key
"&imageName="
image-name
"&size="
(Math/round (* size status-im.utils.pixel-ratio/ratio))
"&theme="
(current-theme-index theme)
"&clock="
clock
"&addRing=1"))
"&indicatorColor="
(js/encodeURIComponent indicator-color)
"&indicatorSize="
(* indicator-size status-im.utils.pixel-ratio/ratio)
"&indicatorBorder="
(* indicator-border status-im.utils.pixel-ratio/ratio)
"&addRing="
(if ring? 1 0)))
(defn get-contact-image-uri-fn
[{:keys [port public-key image-name theme override-ring? clock]}]
(fn [{:keys [size indicator-size indicator-border indicator-color ring? override-theme]}]
(get-contact-image-uri {:port port
:image-name image-name
:public-key public-key
:size size
:theme (if (nil? override-theme) theme override-theme)
:clock clock
:indicator-size indicator-size
:indicator-border indicator-border
:indicator-color indicator-color
:ring? (if (nil? override-ring?) ring? override-ring?)})))
(defn get-account-qr-image-uri
[{:keys [key-uid public-key port qr-size]}]
+38 -9
View File
@@ -1,17 +1,46 @@
(ns utils.image-server-test
(:require [cljs.test :as t]
status-im.utils.pixel-ratio
[utils.image-server :as sut]))
(t/deftest get-account-image-uri
(with-redefs
[sut/current-theme-index identity
sut/timestamp (constantly "timestamp")]
[sut/current-theme-index identity
status-im.utils.pixel-ratio/ratio 2
sut/timestamp (constantly "timestamp")]
(t/is
(=
(sut/get-account-image-uri {:port "port"
:public-key "public-key"
:image-name "image-name"
:key-uid "key-uid"
:theme "theme"
:ring? true})
"https://localhost:port/accountImages?publicKey=public-key&keyUid=key-uid&imageName=image-name&theme=theme&clock=timestamp&addRing=1"))))
(sut/get-account-image-uri {:port "port"
:public-key "public-key"
:image-name "image-name"
:key-uid "key-uid"
:theme :dark
:indicator-size 2
:indicator-color "rgba(9,16,28,0.08)"
:ring? true})
"https://localhost:port/accountImages?publicKey=public-key&keyUid=key-uid&imageName=image-name&size=0&theme=:dark&clock=timestamp&indicatorColor=rgba(9%2C16%2C28%2C0.08)&indicatorSize=4&indicatorBorder=0&addRing=1"))))
(t/deftest get-account-initials-uri
(with-redefs
[sut/current-theme-index identity
status-im.utils.pixel-ratio/ratio 2
sut/timestamp (constantly "timestamp")]
(t/is
(=
(sut/get-initials-avatar-uri
{:port "port"
:public-key "public-key"
:key-uid "key-uid"
:full-name "full-name"
:length "length"
:size 48
:theme :light
:ring? "ring?"
:background-color "background-color"
:color "#0E162000"
:font-size 12
:font-file "/font/Inter Medium.otf"
:uppercase-ratio "uppercase-ratio"
:indicator-size 2
:indicator-color "#0E1620"})
"https://localhost:port/accountInitials?publicKey=public-key&keyUid=key-uid&length=length&size=96&bgColor=background-color&color=%230E162000&fontSize=24&fontFile=%2Ffont%2FInter%20Medium.otf&uppercaseRatio=uppercase-ratio&theme=:light&clock=&name=full-nametimestamp&indicatorColor=%230E1620&indicatorSize=4&indicatorBorder=0&addRing=1"))))
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.163.8",
"commit-sha1": "d61f983d9555e98cf84a3b1273687914887c2e67",
"src-sha256": "1y0s5ivrkywj9simvv2i31ggfzg38li12if2lvfqn8nx10a5y9ai"
"version": "7603b10fb902244899836a19d906cd573fb26093",
"commit-sha1": "7603b10fb902244899836a19d906cd573fb26093",
"src-sha256": "0asnapan03skhxr1r9cmj3q2rfa36sky1qzczficw34kb2icgj15"
}
@@ -437,9 +437,6 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.verify_no_errors()
@marks.testrail_id(703133)
@marks.xfail(reason="Restoring communities issue: 16787; "
"restoring contacts issue: 15500",
run=False)
def test_restore_multiaccount_with_waku_backup_remove_switch(self):
self.home.jump_to_communities_home()
profile = self.home.profile_button.click()
@@ -458,12 +455,16 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
"Incorrect contacts number restored: %s instead of %s" % (contacts_number, len(waku_user.contacts)))
else:
for i in range(contacts_number):
self.home.click_system_back_button_until_element_is_shown()
contact_row = self.home.contact_details_row(index=i + 1)
shown_name_text = contact_row.username_text.text
if shown_name_text in waku_user.contacts:
waku_user.contacts.remove(shown_name_text)
continue
key = waku_user.contacts[i]
if not self.home.element_by_text(key).is_element_displayed(30):
self.errors.append('%s was not restored as a contact from waku backup!' % key)
# Disabled for simple check as sometimes from waku-backup users restored with 3-random names
# self.home.click_system_back_button_until_element_is_shown()
# contact_row = self.home.contact_details_row(index=i + 1)
# shown_name_text = contact_row.username_text.text
# if shown_name_text in waku_user.contacts:
# waku_user.contacts.remove(shown_name_text)
# continue
# else:
# contact_row.click()
# shown_name_text = profile.default_username_text.text
@@ -477,9 +478,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
# if chat.element_starts_with_text(name).is_element_displayed(sec=20):
# waku_user.contacts.remove(name)
# continue
if waku_user.contacts:
self.errors.append(
"Contact(s) was (were) not restored from backup: %s!" % ", ".join(waku_user.contacts))
# if waku_user.contacts:
# self.errors.append(
# "Contact(s) was (were) not restored from backup: %s!" % ", ".join(waku_user.contacts))
self.home.just_fyi("Check restored communities")
self.home.communities_tab.click()
@@ -564,10 +565,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.channel_1.send_message(self.text_message)
self.community_1, self.community_2 = self.home_1.get_community_view(), self.home_2.get_community_view()
self.community_1.send_invite_to_community(self.community_name, self.username_2)
self.community_1.share_community(self.community_name, self.username_2)
self.home_1.get_to_community_channel_from_home(self.community_name)
# self.chat_2 = self.home_2.get_chat(self.username_1).click()
self.home_2.just_fyi("Send message to contact (need for blocking contact) test")
self.chat_2.send_message(self.text_message)
self.chat_2.chat_element_by_text(self.community_name).view_community_button.click()
@@ -978,9 +978,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@marks.testrail_id(703086)
def test_community_mark_all_messages_as_read(self):
self.home_1.jump_to_communities_home()
self.channel_2.click_system_back_button_until_element_is_shown()
self.home_2.communities_tab.click()
for home in self.home_1, self.home_2:
home.click_system_back_button_until_element_is_shown()
home.communities_tab.click()
self.home_2.get_chat(self.community_name, community=True).click()
self.community_2.get_channel(self.channel_name).click()
self.channel_2.send_message(self.text_message)
@@ -1144,8 +1144,6 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.append('Community is still shown in the list after leave')
self.errors.verify_no_errors()
@marks.xfail(reason="Can't invite user to closed community https://github.com/status-im/status-mobile/issues/16968",
run=False)
@marks.testrail_id(702948)
def test_community_hashtag_links_to_community_channels(self):
for home in self.homes:
@@ -1156,7 +1154,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.home_1.just_fyi("Device 1 creates a closed community")
self.home_1.create_community(community_type="closed")
community_name = "closed community"
self.community_1.send_invite_to_community(community_name, self.username_2)
self.community_1.share_community(community_name, self.username_2)
self.home_2.just_fyi("Device 2 joins the community")
self.home_2.get_chat(self.username_1).click()
@@ -1165,31 +1163,40 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.chat_2.chat_element_by_text(community_name).view_community_button.click()
self.community_2.join_community()
self.home_1.just_fyi("Device 1 accepts the community request")
self.home_1.jump_to_communities_home()
try:
self.home_1.notifications_unread_badge.wait_for_visibility_of_element(120)
except TimeoutException:
self.errors.append("Unread indicator is not shown in notifications on membership request")
self.home_1.open_activity_center_button.click()
reply_element = self.home_1.get_element_from_activity_center_view(self.username_2)
reply_element.swipe_right_on_element()
self.home_1.activity_notification_swipe_button.click()
self.home_1.close_activity_centre.click()
dogs_channel, cats_channel = "dogs", "cats"
cats_message = "Where is a cat?"
self.home_1.just_fyi("Device 1 sends a message in the cats channel")
self.home_1.get_to_community_channel_from_home(community_name=community_name, channel_name=cats_channel)
self.channel_1.send_message(cats_message)
self.channel_1.click_system_back_button_until_element_is_shown(
element=self.community_1.get_channel(dogs_channel))
self.channel_1.jump_to_communities_home()
self.home_1.get_to_community_channel_from_home(community_name=community_name, channel_name=dogs_channel)
self.home_1.just_fyi("Device 1 sends a message with hashtag in the dogs channel")
self.community_1.get_channel(dogs_channel).click_until_presence_of_element(self.channel_1.chat_message_input)
message_with_hashtag = "#cats"
self.channel_1.send_message(message_with_hashtag)
self.home_2.just_fyi("Device 2 clicks on the message with hashtag in the community channel")
self.community_2.get_channel(dogs_channel).click_until_presence_of_element(self.channel_2.chat_message_input)
self.channel_2.chat_element_by_text(message_with_hashtag).message_body.wait_for_visibility_of_element(30)
self.channel_2.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate(
rel_x=0.2, rel_y=0.5)
self.home_2.jump_to_communities_home()
self.home_2.get_to_community_channel_from_home(community_name, dogs_channel)
self.channel_2.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
if not self.channel_2.chat_element_by_text(cats_message).is_element_displayed(30):
self.errors.append("Receiver was not navigated to the cats channel")
self.home_1.just_fyi("Device 1 clicks on the message with hashtag in the community channel")
self.channel_1.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate(
rel_x=0.2, rel_y=0.5)
self.channel_1.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
if not self.channel_1.chat_element_by_text(cats_message).is_element_displayed(30):
self.errors.append("Sender was not navigated to the cats channel")
@@ -1201,15 +1208,12 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
self.home_1.just_fyi("Device 1 clicks on the message with hashtag in 1-1 chat")
self.home_1.get_chat(self.username_2).click()
self.chat_1.chat_element_by_text(message_with_hashtag).message_body.wait_for_visibility_of_element(30)
self.chat_1.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate(
rel_x=0.2, rel_y=0.5)
self.chat_1.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
if self.chat_1.chat_element_by_text(control_message_1_1_chat).is_element_disappeared():
self.errors.append("Receiver was navigated out of 1-1 chat")
self.home_2.just_fyi("Device 2 clicks on the message with hashtag in 1-1 chat")
self.chat_2.chat_element_by_text(message_with_hashtag).message_body.click_inside_element_by_coordinate(
rel_x=0.2, rel_y=0.5)
self.chat_2.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
if self.chat_2.chat_element_by_text(control_message_1_1_chat).is_element_disappeared():
self.errors.append("Sender was navigated out of 1-1 chat")
@@ -168,7 +168,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.channel_1.send_message(self.text_message)
self.community_1, self.community_2 = self.home_1.get_community_view(), self.home_2.get_community_view()
self.community_1.send_invite_to_community(self.community_name, self.username_2)
self.community_1.share_community(self.community_name, self.username_2)
self.home_1.get_to_community_channel_from_home(self.community_name)
self.chat_2 = self.home_2.get_chat(self.username_1).click()
@@ -321,8 +321,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
self.channel_name = "dogs"
self.home_1.create_community(community_type="closed")
self.home_1.reopen_app()
community_element = self.home_1.get_chat(community_name, community=True)
self.community_1.share_community(community_element, self.username_2)
self.community_1.share_community(community_name, self.username_2)
self.home_2.just_fyi("Request access to community")
self.home_2.jump_to_messages_home()
+17 -8
View File
@@ -604,19 +604,28 @@ class BaseView(object):
sign_in_view = self.get_sign_in_view()
sign_in_view.sign_in(password)
def jump_to_messages_home(self):
def click_on_floating_jump_to(self):
self.hide_keyboard_if_shown()
self.jump_to_button.click()
self.chats_tab.click_until_presence_of_element(self.jump_to_button)
if self.chat_floating_screen.is_element_displayed(1):
Button(self.driver, xpath='//*[@content-desc="%s"]//*[@content-desc="%s"]' %
(self.chat_floating_screen.accessibility_id, self.jump_to_button.accessibility_id)).click()
elif self.community_floating_screen.is_element_displayed(1):
Button(self.driver, xpath='//*[@content-desc="%s"]//*[@content-desc="%s"]' %
(self.community_floating_screen.accessibility_id,
self.jump_to_button.accessibility_id)).click()
else:
self.jump_to_button.click()
def jump_to_messages_home(self):
self.click_on_floating_jump_to()
self.chats_tab.click()
def jump_to_communities_home(self):
self.hide_keyboard_if_shown()
self.jump_to_button.click()
self.communities_tab.click_until_presence_of_element(self.jump_to_button)
self.click_on_floating_jump_to()
self.communities_tab.click()
def jump_to_card_by_text(self, text: str):
self.hide_keyboard_if_shown()
self.jump_to_button.click()
self.click_on_floating_jump_to()
self.element_by_text(text).click()
def reopen_app(self, password=common_password, sign_in=True):
+11 -2
View File
@@ -183,6 +183,10 @@ class ChatElementByText(Text):
xpath="//%s//android.widget.TextView[contains(@text,'%s')]" % (self.chat_item_locator, self.message_text)
)
def click_on_link_inside_message_body(self):
self.message_body.wait_for_visibility_of_element(30)
self.message_body.click_inside_element_by_coordinate(rel_x=0.1, rel_y=0.9)
def wait_for_sent_state(self, wait_time=30):
return BaseElement(self.driver, prefix=self.locator,
xpath="//*[@content-desc='message-sent']").is_element_displayed(wait_time)
@@ -458,6 +462,7 @@ class CommunityView(HomeView):
Button(self.driver, xpath="//*[starts-with(@text,'%s')]%s" % (username, decline_suffix)).click()
self.close_button.click()
# Should not be used anymore, outdated flow
def send_invite_to_community(self, community_name, user_names_to_invite):
if isinstance(user_names_to_invite, str):
user_names_to_invite = [user_names_to_invite]
@@ -474,11 +479,15 @@ class CommunityView(HomeView):
self.share_invite_button.click_until_presence_of_element(self.invite_button)
self.back_button.click_until_presence_of_element(self.plus_button)
def share_community(self, coummunity_element, user_names_to_share):
def share_community(self, community_name, user_names_to_share):
if isinstance(user_names_to_share, str):
user_names_to_share = [user_names_to_share]
self.driver.info("Share to %s community" % ', '.join(map(str, user_names_to_share)))
coummunity_element.long_press_until_element_is_shown(self.share_community_button)
self.jump_to_communities_home()
home = self.get_home_view()
community_element = home.get_chat(community_name, community=True)
# community_element.long_press_until_element_is_shown(self.view_members_button)
community_element.long_press_until_element_is_shown(self.share_community_button)
self.share_community_button.click()
for user_name in user_names_to_share:
user_contact = self.element_by_text_part(user_name)
+4 -2
View File
@@ -7,6 +7,8 @@ communities = {
'member_closed': 'test_comm_enc',
'member_pending': 'RC1 testing community'
}
# contacts = ['Test_contact', 'MyCustomNickname'] # enable back when https://github.com/status-im/status-mobile/issues/15500 is fixed
contacts = ['Used Bulky Wirehair', 'Vengeful Healthy Arcticseal']
#contacts = ['Test_contact', 'MyCustomNickname'] # enable back when https://github.com/status-im/status-mobile/issues/15500 is fixed
contacts = ['zQ3...rLSpUs', 'zQ3...mxAZUU']
blocked_user = 'Clear Flat Milkweedbug'
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

-1
View File
@@ -303,7 +303,6 @@ class HomeView(BaseView):
# New UI
self.new_chat_button = Button(self.driver, accessibility_id="new-chat-button")
self.jump_to_button = Button(self.driver, accessibility_id="jump-to")
self.discover_communities_button = Button(self.driver, accessibility_id="communities-home-discover-card")
# New UI bottom sheet