Improve chat Avatar (#15036)
This commit is contained in:
parent
aec1b5fafa
commit
7d9709ee67
Binary file not shown.
After Width: | Height: | Size: 989 B |
|
@ -1,6 +1,5 @@
|
|||
(ns quo2.components.avatars.user-avatar
|
||||
(:require [clojure.string :refer [blank? split upper-case]]
|
||||
[quo2.components.icon :as icons]
|
||||
(:require [clojure.string :as string]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.theme :refer [dark?]]
|
||||
|
@ -40,115 +39,100 @@
|
|||
:font-size :label}})
|
||||
|
||||
(defn dot-indicator
|
||||
[size status-indicator? online? ring? dark?]
|
||||
(when status-indicator?
|
||||
(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 (if ring?
|
||||
-2
|
||||
-2)
|
||||
0)]
|
||||
[rn/view
|
||||
{:style {:background-color (if online?
|
||||
colors/success-50
|
||||
colors/neutral-40)
|
||||
:width dimensions
|
||||
:height dimensions
|
||||
:border-width border-width
|
||||
:border-radius dimensions
|
||||
:border-color (if dark?
|
||||
colors/neutral-100
|
||||
colors/white)
|
||||
:position :absolute
|
||||
:bottom bottom
|
||||
:right right}}])))
|
||||
[{:keys [size online? ring? dark?]}]
|
||||
(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)]
|
||||
[rn/view
|
||||
{:style {:background-color (if online?
|
||||
colors/success-50
|
||||
colors/neutral-40)
|
||||
:width dimensions
|
||||
:height dimensions
|
||||
:border-width border-width
|
||||
:border-radius dimensions
|
||||
:border-color (if dark?
|
||||
colors/neutral-100
|
||||
colors/white)
|
||||
:position :absolute
|
||||
:bottom bottom
|
||||
:right right}}]))
|
||||
|
||||
(defn container-styling
|
||||
(defn initials-style
|
||||
[inner-dimensions outer-dimensions]
|
||||
{:width inner-dimensions
|
||||
:position :absolute
|
||||
:top (/ (- outer-dimensions inner-dimensions) 2)
|
||||
:left (/ (- outer-dimensions inner-dimensions) 2)
|
||||
:height inner-dimensions
|
||||
:border-radius inner-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
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/custom-color-by-theme :turquoise 50 60)})
|
||||
|
||||
(defn container
|
||||
[inner-dimensions outer-dimensions & children]
|
||||
[rn/view
|
||||
{:style (merge {:background-color (colors/custom-color-by-theme :turquoise 50 60)
|
||||
:justify-content :center
|
||||
:align-items :center}
|
||||
(container-styling inner-dimensions outer-dimensions))}
|
||||
children])
|
||||
(defn outer-styles
|
||||
[outer-dimensions]
|
||||
{:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:border-radius outer-dimensions})
|
||||
|
||||
(def small-sizes #{:xs :xxs :xxxs})
|
||||
(def identicon-sizes #{:big :medium :small})
|
||||
(def one-initial-letter-sizes #{:xs :xxs :xxxs})
|
||||
(def valid-ring-sizes #{:big :medium :small})
|
||||
|
||||
(defn initials-avatar
|
||||
[{:keys [full-name size inner-dimensions outer-dimensions]}]
|
||||
(let [amount-initials (if (one-initial-letter-sizes size) 1 2)
|
||||
initials (as-> full-name $
|
||||
(string/split $ " ")
|
||||
(map (comp string/upper-case first) $)
|
||||
(take amount-initials $)
|
||||
(string/join $))
|
||||
font-size (get-in sizes [size :font-size])]
|
||||
[rn/view {:style (initials-style inner-dimensions outer-dimensions)}
|
||||
[text/text
|
||||
{:style {:color colors/white-opa-70}
|
||||
:weight :semi-bold
|
||||
:size font-size}
|
||||
initials]]))
|
||||
|
||||
(defn user-avatar
|
||||
[{:keys [ring?
|
||||
online?
|
||||
size
|
||||
status-indicator?
|
||||
profile-picture
|
||||
full-name]
|
||||
:or {full-name "empty name"
|
||||
status-indicator? true
|
||||
"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 over it."
|
||||
[{:keys [full-name status-indicator? online? size profile-picture ring-background]
|
||||
:or {status-indicator? true
|
||||
online? true
|
||||
size :big
|
||||
ring? true}}]
|
||||
(let [initials (if full-name
|
||||
(reduce str (map first (split full-name " ")))
|
||||
"")
|
||||
first-initial-letter (if full-name
|
||||
(or (first full-name) "")
|
||||
"")
|
||||
identicon? (contains? identicon-sizes size)
|
||||
small? (contains? small-sizes size)
|
||||
outer-dimensions (get-in sizes [size :outer])
|
||||
inner-dimensions (get-in sizes
|
||||
[size
|
||||
(if ring?
|
||||
:inner
|
||||
:outer)])
|
||||
font-size (get-in sizes [size :font-size])
|
||||
icon-text (if-not (or (blank? first-initial-letter)
|
||||
(blank? initials))
|
||||
(if small?
|
||||
first-initial-letter
|
||||
initials)
|
||||
"")]
|
||||
size :big}}]
|
||||
(let [full-name (or full-name "empty name")
|
||||
draw-ring? (and ring-background (valid-ring-sizes size))
|
||||
outer-dimensions (get-in sizes [size :outer])
|
||||
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
|
||||
[rn/view
|
||||
{:accessibility-label :user-avatar
|
||||
:style {:width outer-dimensions
|
||||
:height outer-dimensions
|
||||
:border-radius outer-dimensions}}
|
||||
(when (and false (and ring? identicon?)) ;;TODO not implemented yet
|
||||
[icons/icon :i/identicon-ring
|
||||
{:size outer-dimensions
|
||||
:no-color true}])
|
||||
(if profile-picture
|
||||
;; display image
|
||||
{:style (outer-styles outer-dimensions)
|
||||
:accessibility-label :user-avatar}
|
||||
;; The `profile-picture` already has the ring in it
|
||||
(when-let [image (or profile-picture ring-background)]
|
||||
[fast-image/fast-image
|
||||
{:source profile-picture
|
||||
:style (container-styling inner-dimensions outer-dimensions)}]
|
||||
;; else display initials
|
||||
[container inner-dimensions outer-dimensions
|
||||
^{:key :icon-text}
|
||||
[text/text
|
||||
{:weight :semi-bold
|
||||
:size font-size
|
||||
:style {:color colors/white-opa-70}}
|
||||
(upper-case icon-text)]])
|
||||
[dot-indicator size status-indicator? online? ring? (dark?)]]))
|
||||
{:style (outer-styles outer-dimensions)
|
||||
:source image}])
|
||||
(when-not profile-picture
|
||||
[initials-avatar
|
||||
{:full-name full-name
|
||||
:size size
|
||||
:inner-dimensions inner-dimensions
|
||||
:outer-dimensions outer-dimensions}])
|
||||
(when status-indicator?
|
||||
[dot-indicator
|
||||
{:size size
|
||||
:online? online?
|
||||
:ring? draw-ring?
|
||||
:dark? (dark?)}])]))
|
||||
|
|
|
@ -49,8 +49,7 @@
|
|||
:profile-picture photo-path
|
||||
:status-indicator? true
|
||||
:online? online?
|
||||
:size :small
|
||||
:ring? false}]
|
||||
:size :small}]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
[author/author
|
||||
{:primary-name primary-name
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
:profile-picture profile-picture
|
||||
:override-theme :dark
|
||||
:size :medium
|
||||
:status-indicator? false
|
||||
:ring? true}]
|
||||
:status-indicator? false}]
|
||||
[button/button
|
||||
{:size 32
|
||||
:type :blur-bg
|
||||
|
|
|
@ -24,29 +24,31 @@
|
|||
(let [internal-selected? (reagent/atom (or default-selected? false))]
|
||||
(fn [{:keys [selected?
|
||||
profile-picture
|
||||
ring-background
|
||||
name
|
||||
customization-color
|
||||
on-change]
|
||||
:or {customization-color :turquoise}}]
|
||||
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
|
||||
(reset! internal-selected? selected?))
|
||||
[rn/touchable-opacity
|
||||
{:style (style/container customization-color @internal-selected?)
|
||||
:on-press #(on-change-handler internal-selected? on-change)
|
||||
:active-opacity 1
|
||||
:accessibility-label :select-profile}
|
||||
[rn/view {:style style/header}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name name
|
||||
:profile-picture profile-picture
|
||||
:status-indicator? false
|
||||
:ring? true
|
||||
:size :medium}]
|
||||
[rn/view {:style (style/select-radio @internal-selected?)}
|
||||
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
|
||||
[text/text
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
:style style/profile-name
|
||||
} name]])))
|
||||
(let [avatar-image-key (if profile-picture :profile-picture :ring-background)
|
||||
picture (or profile-picture ring-background)]
|
||||
(when (and (not (nil? selected?)) (not= @internal-selected? selected?))
|
||||
(reset! internal-selected? selected?))
|
||||
[rn/touchable-opacity
|
||||
{:style (style/container customization-color @internal-selected?)
|
||||
:on-press #(on-change-handler internal-selected? on-change)
|
||||
:active-opacity 1
|
||||
:accessibility-label :select-profile}
|
||||
[rn/view {:style style/header}
|
||||
[user-avatar/user-avatar
|
||||
{:full-name name
|
||||
:status-indicator? false
|
||||
:size :medium
|
||||
avatar-image-key picture}]
|
||||
[rn/view {:style (style/select-radio @internal-selected?)}
|
||||
(when @internal-selected? [rn/view {:style style/select-radio-inner}])]]
|
||||
[text/text
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
:style style/profile-name}
|
||||
name]]))))
|
||||
|
||||
|
|
|
@ -69,7 +69,8 @@
|
|||
:user-picture-male5 (js/require "../resources/images/mock/user_picture_male5.png")
|
||||
:coinbase (js/require "../resources/images/mock/coinbase.png")
|
||||
:small-opt-card-icon (js/require "../resources/images/mock/small_opt_card_icon.png")
|
||||
:small-opt-card-main (js/require "../resources/images/mock/small_opt_card_main.png")})
|
||||
:small-opt-card-main (js/require "../resources/images/mock/small_opt_card_main.png")
|
||||
:ring (js/require "../resources/images/mock/ring.png")})
|
||||
|
||||
(defn get-theme-image
|
||||
[k]
|
||||
|
|
|
@ -52,10 +52,7 @@
|
|||
new-notifications? (pos? notif-count)
|
||||
notification-indicator :unread-dot
|
||||
counter-label "0"]
|
||||
[rn/view
|
||||
{:style (merge
|
||||
{:height 56}
|
||||
style)}
|
||||
[rn/view {:style (assoc style :height 56)}
|
||||
;; Left Section
|
||||
[rn/touchable-without-feedback {:on-press open-profile}
|
||||
[rn/view
|
||||
|
@ -64,8 +61,7 @@
|
|||
:top 12}}
|
||||
[quo/user-avatar
|
||||
(merge
|
||||
{:ring? true
|
||||
:status-indicator? true
|
||||
{:status-indicator? true
|
||||
:size :small}
|
||||
avatar)]]]
|
||||
;; Right Section
|
||||
|
|
|
@ -102,33 +102,39 @@
|
|||
(datetime/to-short-str timestamp)]])
|
||||
|
||||
(defn avatar-view
|
||||
[group-chat color display-name photo-path chat-id]
|
||||
(if group-chat
|
||||
[{:keys [contact chat-id full-name color]}]
|
||||
(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)]
|
||||
[quo/user-avatar
|
||||
{:full-name full-name
|
||||
:size :small
|
||||
:online? online?
|
||||
image-key photo-path}])
|
||||
[quo/group-avatar
|
||||
{:color color
|
||||
:size :medium}]
|
||||
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])]
|
||||
[quo/user-avatar
|
||||
{:full-name display-name
|
||||
:online? online?
|
||||
:profile-picture photo-path
|
||||
:size :small}])))
|
||||
:size :medium}]))
|
||||
|
||||
(defn chat-list-item
|
||||
[item]
|
||||
(let [{:keys [chat-id color group-chat last-message timestamp name unviewed-mentions-count
|
||||
unviewed-messages-count]}
|
||||
item
|
||||
display-name
|
||||
(if group-chat name (first (rf/sub [:contacts/contact-two-names-by-identity 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]))]
|
||||
[{:keys [chat-id group-chat color name unviewed-messages-count unviewed-mentions-count
|
||||
timestamp last-message]
|
||||
:as item}]
|
||||
(let [display-name (if group-chat
|
||||
name
|
||||
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id])))
|
||||
contact (when-not group-chat
|
||||
(rf/sub [:contacts/contact-by-address chat-id]))]
|
||||
[rn/touchable-opacity
|
||||
(merge {:style (style/container)
|
||||
:on-press (open-chat chat-id)
|
||||
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [actions/chat-actions item false])}])})
|
||||
[avatar-view group-chat color display-name photo-path chat-id]
|
||||
{:style (style/container)
|
||||
:on-press (open-chat chat-id)
|
||||
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn [] [actions/chat-actions item false])}])}
|
||||
[avatar-view
|
||||
{:contact contact
|
||||
:chat-id chat-id
|
||||
:full-name display-name
|
||||
:color color}]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
[name-view display-name contact timestamp]
|
||||
(if (string/blank? (get-in last-message [:content :parsed-text]))
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
{:full-name display-name
|
||||
:profile-picture profile-picture
|
||||
:status-indicator? false
|
||||
:ring? false
|
||||
:size :xxxs}]]
|
||||
[quo/author {:primary-name display-name}]
|
||||
[quo/text
|
||||
|
|
|
@ -39,8 +39,7 @@
|
|||
:profile-picture photo-path
|
||||
:status-indicator? true
|
||||
:online? online?
|
||||
:size :small
|
||||
:ring? false}]]])
|
||||
:size :small}]]])
|
||||
[rn/view {:padding-top 2 :width 32}]))
|
||||
|
||||
(defn author
|
||||
|
|
|
@ -32,19 +32,22 @@
|
|||
(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]))]
|
||||
contact (when-not group-chat
|
||||
(rf/sub [:contacts/contact-by-address chat-id]))
|
||||
photo-path (rf/sub [:chats/photo-path chat-id])
|
||||
avatar-image-key (if (seq (:images contact))
|
||||
:profile-picture
|
||||
:ring-background)]
|
||||
[quo/page-nav
|
||||
{:align-mid? true
|
||||
|
||||
:mid-section (if group-chat
|
||||
{:type :text-only
|
||||
:main-text display-name}
|
||||
{:type :user-avatar
|
||||
:avatar {:full-name display-name
|
||||
:online? online?
|
||||
:profile-picture photo-path
|
||||
:size :medium}
|
||||
:size :medium
|
||||
avatar-image-key photo-path}
|
||||
:main-text display-name
|
||||
:on-press #(debounce/dispatch-and-chill [:chat.ui/show-profile chat-id]
|
||||
1000)})
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
{:label "Status Indicator"
|
||||
:key :status-indicator?
|
||||
:type :boolean}
|
||||
{:label "Identicon Ring"
|
||||
{:label "Identicon Ring (applies only when there's no profile picture)"
|
||||
:key :ring?
|
||||
:type :boolean}
|
||||
{:label "Full name separated by space"
|
||||
|
@ -49,8 +49,7 @@
|
|||
(let [state (reagent/atom {:full-name "A Y"
|
||||
:status-indicator? true
|
||||
:online? true
|
||||
:size :medium
|
||||
:ring? true})]
|
||||
:size :medium})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
|
@ -60,7 +59,12 @@
|
|||
{:padding-vertical 60
|
||||
:flex-direction :row
|
||||
:justify-content :center}
|
||||
[quo2/user-avatar @state]]]])))
|
||||
(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])]]])))
|
||||
|
||||
(defn preview-user-avatar
|
||||
[]
|
||||
|
|
|
@ -109,8 +109,7 @@
|
|||
(case type
|
||||
shell.constants/one-to-one-chat-card
|
||||
[quo/user-avatar
|
||||
(merge {:ring? false
|
||||
:size :medium
|
||||
(merge {:size :medium
|
||||
:status-indicator? false}
|
||||
avatar-params)]
|
||||
|
||||
|
|
Loading…
Reference in New Issue