Refactor `toast` component to use theme context (#16711)

This commit refactors the "Toast" component to use theme context for consistency across the codebase.

Each toast will have its theme provider, which will help the children to use the context properly without interfering with other toast's context.

The following components are refactored to use with-theme / theme-context as it is used in the "Toast":

- "text" component
- "user-avatar" component
- "icon" component
- "circle-timer" component

This commit also updates the icon keyword used in the ":toasts/upsert" event dispatch to respect icon guidelines.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
This commit is contained in:
Mohamed Javid 2023-07-25 23:06:02 +08:00 committed by GitHub
parent ec6800216b
commit 1721b40b3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 148 additions and 121 deletions

View File

@ -41,7 +41,7 @@
:border-radius dimensions}))
(defn initials-avatar
[size draw-ring? customization-color]
[size draw-ring? customization-color theme]
(let [outer-dimensions (get-in sizes [size :outer])
inner-dimensions (get-in sizes [size (if draw-ring? :inner :outer)])]
{:position :absolute
@ -52,7 +52,7 @@
:border-radius inner-dimensions
:justify-content :center
:align-items :center
:background-color (colors/custom-color-by-theme customization-color 50 60)}))
:background-color (colors/custom-color-by-theme customization-color 50 60 nil nil theme)}))
(def initials-avatar-text
{:color colors/white-opa-70})
@ -67,7 +67,7 @@
:background-color background}))
(defn dot
[size ring?]
[size ring? theme]
(let [dimensions (get-in sizes [size :status-indicator])
border-width (get-in sizes [size :status-indicator-border])
right (case size
@ -89,5 +89,5 @@
:height dimensions
:border-width border-width
:border-radius dimensions
:background-color (colors/theme-colors colors/white colors/neutral-100)
:border-color (colors/theme-colors colors/white colors/neutral-100)}))
:background-color (colors/theme-colors colors/white colors/neutral-100 theme)
:border-color (colors/theme-colors colors/white colors/neutral-100 theme)}))

View File

@ -1,17 +1,18 @@
(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))
(defn initials-avatar
[{:keys [full-name size draw-ring? customization-color]}]
[{:keys [full-name size draw-ring? customization-color theme]}]
(let [font-size (get-in style/sizes [size :font-size])
amount-initials (if (#{:xs :xxs :xxxs} size) 1 2)]
[rn/view
{:accessibility-label :initials-avatar
:style (style/initials-avatar size draw-ring? customization-color)}
:style (style/initials-avatar size draw-ring? customization-color theme)}
[text/text
{:style style/initials-avatar-text
:size font-size
@ -20,12 +21,12 @@
(def valid-ring-sizes #{:big :medium :small})
(defn user-avatar
(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?]
customization-color static? muted? theme]
:or {status-indicator? true
online? true
size :big
@ -49,11 +50,14 @@
{:full-name full-name
:size size
:draw-ring? draw-ring?
:customization-color customization-color}])
:customization-color customization-color
:theme theme}])
(when status-indicator?
[rn/view
{:accessibility-label :status-indicator
:style (style/dot size draw-ring?)}
:style (style/dot size draw-ring? theme)}
[rn/view
{:accessibility-label :inner-status-indicator-dot
:style (style/inner-dot size online?)}]])]))
(def user-avatar (quo.theme/with-theme user-avatar-internal))

View File

@ -3,6 +3,7 @@
[quo2.components.icons.icons :as icons]
[quo2.components.icons.svg :as icons.svg]
[quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme]
[react-native.core :as rn]))
(defn- valid-color?
@ -12,11 +13,10 @@
(not (string/blank? color)))))
(defn memo-icon-fn
[icon-name
{:keys [color color-2 no-color
container-style size accessibility-label]
[{:keys [color color-2 no-color
container-style size accessibility-label theme]
:or {accessibility-label :icon}}
_]
icon-name]
(let [size (or size 20)]
^{:key icon-name}
(if-let [svg-icon (icons.svg/get-icon icon-name size)]
@ -34,15 +34,15 @@
(when (not no-color)
{:tint-color (if (and (string? color) (not (string/blank? color)))
color
(colors/theme-colors colors/neutral-100 colors/white))})
(colors/theme-colors colors/neutral-100 colors/white theme))})
container-style)
:accessibility-label accessibility-label
:source (icons/icon-source (str (name icon-name) size))}])))
(def themed-icon (memoize memo-icon-fn))
(def ^:private themed-icon (memoize (quo.theme/with-theme memo-icon-fn)))
(defn icon
([icon-name] (icon icon-name nil))
([icon-name params]
(themed-icon icon-name params (colors/dark?))))
(themed-icon params icon-name)))

View File

@ -1,12 +1,12 @@
(ns quo2.components.markdown.text
(:require [quo2.foundations.colors :as colors]
[quo2.foundations.typography :as typography]
[quo2.theme :as theme]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn text-style
[{:keys [size align weight style]}]
[{:keys [size align weight style theme]}]
(merge (case (or weight :regular)
:regular typography/font-regular
:medium typography/font-medium
@ -25,14 +25,23 @@
{:text-align (or align :auto)}
(if (:color style)
style
(assoc style :color (if (= (theme/get-theme) :dark) colors/white colors/neutral-100)))))
(assoc style
:color
(if (= (or theme (quo.theme/get-theme)) :dark) colors/white colors/neutral-100)))))
(defn- text-view-internal
[props & children]
(let [style (text-style props)]
(into [rn/text
(merge {:style style}
(dissoc props :style :size :align :weight :color :theme))]
children)))
(def ^:private text-view (quo.theme/with-theme text-view-internal))
(defn text
[]
(let [this (reagent/current-component)
props (reagent/props this)
style (text-style props)]
(into [rn/text
(merge {:style style}
(dissoc props :style :size :align :weight :color))]
(reagent/children this))))
(let [this (reagent/current-component)
props (reagent/props this)
children (reagent/children this)]
(into [text-view props] children)))

View File

@ -1,7 +1,7 @@
(ns quo2.components.notifications.count-down-circle
(:require [goog.string :as gstring]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[quo2.theme :as quo.theme]
[react-native.core :as rn]
[react-native.svg :as svg]
[reagent.core :as reagent]))
@ -48,8 +48,8 @@
{:color {:dark colors/neutral-80-opa-40
:light colors/white-opa-40}})
(defn circle-timer
[{:keys [color duration size stroke-width trail-color rotation initial-remaining-time]}]
(defn- circle-timer-internal
[{:keys [color duration size stroke-width trail-color rotation initial-remaining-time theme]}]
(let [rotation (or rotation :clockwise)
duration (or duration 4)
stroke-width (or stroke-width 1)
@ -98,8 +98,10 @@
[svg/path
{:d path
:fill :none
:stroke (or color (get-in themes [:color (theme/get-theme)]))
:stroke (or color (get-in themes [:color theme]))
:stroke-linecap :square
:stroke-width stroke-width
:stroke-dasharray path-length
:stroke-dashoffset (linear-ease @display-time 0 path-length duration)}])]])})))
(def circle-timer (quo.theme/with-theme circle-timer-internal))

View File

@ -3,10 +3,12 @@
[quo2.foundations.colors :as colors]
[quo2.foundations.shadows :as shadows]))
(def box-container
{:margin-horizontal 12
:border-radius 12
:overflow :hidden})
(defn box-container
[theme]
(merge (shadows/get 1 theme)
{:margin-horizontal 12
:border-radius 12
:overflow :hidden}))
(def blur-container
{:height "100%"
@ -19,35 +21,33 @@
(defn content-container
[theme]
(merge
(shadows/get 1 theme)
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
:flex-direction :row
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12}))
{:background-color (colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
:flex-direction :row
:justify-content :space-between
:padding-vertical 8
:padding-left 10
:padding-right 8
:border-radius 12})
(defn title
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
[theme]
{:color (colors/theme-colors colors/white colors/neutral-100 theme)})
(defn text
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)})
[theme]
{:color (colors/theme-colors colors/white colors/neutral-100 theme)})
(defn icon
[override-theme]
{:color (colors/theme-colors colors/white colors/neutral-100 override-theme)
[theme]
{:color (colors/theme-colors colors/white colors/neutral-100 theme)
:container-style {:width 20 :height 20}})
(def left-side-container {:padding 2})
(def right-side-container {:padding 4 :flex 1})
(defn action-container
[override-theme]
{:background-color (colors/theme-colors colors/white-opa-5 colors/neutral-80-opa-5 override-theme)
[theme]
{:background-color (colors/theme-colors colors/white-opa-5 colors/neutral-80-opa-5 theme)
:flex-direction :row
:padding-vertical 3
:padding-horizontal 8

View File

@ -4,33 +4,40 @@
[quo2.components.markdown.text :as text]
[quo2.components.notifications.count-down-circle :as count-down-circle]
[quo2.components.notifications.toast.style :as style]
[quo2.theme :as theme]
[quo2.theme :as quo.theme]
[react-native.blur :as blur]
[react-native.core :as rn]
[utils.i18n :as i18n]))
(defn toast-action-container
[{:keys [on-press style]} & children]
[{:keys [on-press style theme]} & children]
[rn/touchable-highlight
{:on-press on-press
:underlay-color :transparent}
[into
[rn/view
{:style (merge (style/action-container (theme/get-theme)) style)}]
{:style (merge (style/action-container theme) style)}]
children]])
(defn toast-undo-action
[duration on-press override-theme]
[toast-action-container {:on-press on-press :accessibility-label :toast-undo-action}
(defn toast-undo-action-internal
[{:keys [undo-duration undo-on-press theme]}]
[toast-action-container
{:on-press undo-on-press
:accessibility-label :toast-undo-action
:theme theme}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[count-down-circle/circle-timer {:duration undo-duration}]]
[text/text
{:size :paragraph-2 :weight :medium :style (style/text override-theme)}
{:size :paragraph-2
:weight :medium
:style (style/text theme)}
[i18n/label :t/undo]]])
(defn- toast-container
[{:keys [left title text right container-style override-theme]}]
[rn/view {:style (merge style/box-container container-style)}
(def ^:private toast-undo-action (quo.theme/with-theme toast-undo-action-internal))
(defn- toast-container-internal
[{:keys [left title text right container-style theme]}]
[rn/view {:style (merge (style/box-container theme) container-style)}
[blur/view
{:style style/blur-container
:blur-amount 13
@ -38,7 +45,7 @@
:blur-type :transparent
:overlay-color :transparent}]
[rn/view {:style (style/content-container override-theme)}
[rn/view {:style (style/content-container theme)}
[rn/view {:style style/left-side-container}
left]
[rn/view {:style style/right-side-container}
@ -46,34 +53,39 @@
[text/text
{:size :paragraph-1
:weight :semi-bold
:style (style/title override-theme)
:style (style/title theme)
:accessibility-label :toast-title}
title])
(when text
[text/text
{:size :paragraph-2
:weight :medium
:style (style/text override-theme)
:style (style/text theme)
:accessibility-label :toast-content}
text])]
right]])
(def ^:private toast-container (quo.theme/with-theme toast-container-internal))
(defn toast
[{:keys [icon icon-color title text action undo-duration undo-on-press container-style
override-theme user]}]
[toast-container
{:left (cond icon
[icon/icon icon
(cond-> (style/icon override-theme)
icon-color
(assoc :color icon-color))]
theme user]}]
(let [context-theme (or theme (quo.theme/get-theme))]
[quo.theme/provider {:theme context-theme}
[toast-container
{:left (cond icon
[icon/icon icon
(cond-> (style/icon context-theme)
icon-color
(assoc :color icon-color))]
user
[user-avatar/user-avatar user])
:title title
:text text
:right (if undo-duration
[toast-undo-action undo-duration undo-on-press override-theme]
action)
:container-style container-style
:override-theme override-theme}])
user
[user-avatar/user-avatar user])
:title title
:text text
:right (if undo-duration
[toast-undo-action
{:undo-duration undo-duration
:undo-on-press undo-on-press}]
action)
:container-style container-style}]]))

View File

@ -262,11 +262,14 @@
suffix-light 50/60
suffix-dark 50/60
opacity-light 0-100 (optional)
opacity-dark 0-100 (optional)"
opacity-dark 0-100 (optional)
theme :light/:dark (optional)"
([color suffix-light suffix-dark]
(custom-color-by-theme color suffix-light suffix-dark nil nil))
(custom-color-by-theme color suffix-light suffix-dark nil nil (theme/get-theme)))
([color suffix-light suffix-dark opacity-light opacity-dark]
(if (theme/dark?)
(custom-color-by-theme color suffix-light suffix-dark opacity-light opacity-dark (theme/get-theme)))
([color suffix-light suffix-dark opacity-light opacity-dark theme]
(if (= theme :dark)
(custom-color color suffix-dark opacity-dark)
(custom-color color suffix-light opacity-light))))

View File

@ -12,7 +12,7 @@
:on-allowed on-allowed
:on-denied #(rf/dispatch
[:toasts/upsert
{:icon :i/info
:icon-color colors/danger-50
:override-theme :light
:text (i18n/label :t/camera-permission-denied)}])}]))
{:icon :i/info
:icon-color colors/danger-50
:theme :dark
:text (i18n/label :t/camera-permission-denied)}])}]))

View File

@ -217,7 +217,7 @@
(rf/dispatch [:hide-bottom-sheet])
(rf/dispatch [:toasts/upsert
{:id :remove-nickname
:icon :correct
:icon :i/correct
:icon-color (colors/theme-colors colors/success-60
colors/success-50)
:text (i18n/label

View File

@ -352,7 +352,7 @@
:t/channel-unmuted-successfully))))]
{:db (assoc-in db [:chats chat-id :muted-till] muted-till)
:dispatch [:toasts/upsert
{:icon :correct
{:icon :i/correct
:icon-color (colors/theme-colors colors/success-60
colors/success-50)
:text (mute-duration-text (when (some? muted-till)

View File

@ -57,7 +57,7 @@
uri
#(rf/dispatch [:toasts/upsert
{:id :random-id
:icon :correct
:icon :i/correct
:icon-color colors/success-50
:container-style {:bottom (when platform/android? 20)}
:text (i18n/label :t/photo-saved)}])))}]]]))

View File

@ -107,7 +107,7 @@
[[:toasts/close :delete-message-for-everyone]
[:toasts/upsert
{:id :delete-message-for-everyone
:icon :info
:icon :i/info
:icon-color colors/danger-50-opa-40
:message-deleted-for-everyone-count toast-count
:message-deleted-for-everyone-undos existing-undos

View File

@ -62,7 +62,7 @@
:dispatch-n [[:toasts/close :delete-message-for-me]
[:toasts/upsert
{:id :delete-message-for-me
:icon :info
:icon :i/info
:icon-color colors/danger-50-opa-40
:message-deleted-for-me-count toast-count
:message-deleted-for-me-undos existing-undos

View File

@ -23,7 +23,7 @@
[]
(rf/dispatch [:toasts/upsert
{:id :random-id
:icon :info
:icon :i/info
:icon-color colors/danger-50-opa-40
:container-style {:top (when platform/ios? 20)}
:text (i18n/label :t/only-6-images)}]))

View File

@ -35,7 +35,7 @@
:undo-duration 4
:undo-on-press #(do
(rf/dispatch [:toasts/upsert
{:icon :correct
{:icon :i/correct
:icon-color colors/success-50-opa-40
:text "Undo pressed"}])
(rf/dispatch [:toasts/close
@ -54,7 +54,7 @@
#(do
(rf/dispatch
[:toasts/upsert
{:icon :correct :icon-color colors/success-50-opa-40 :text "Undo pressed"}])
{:icon :i/correct :icon-color colors/success-50-opa-40 :text "Undo pressed"}])
(rf/dispatch [:toasts/close "Toast: with undo action"]))}])
(defn toast-button-30s-duration
@ -79,7 +79,7 @@
#(rf/dispatch
[:toasts/upsert
{:id "Toast: 30s duration"
:icon :info
:icon :i/info
:icon-color colors/danger-50-opa-40
:text (str "This is an updated example toast" " - " (swap! suffix inc))
:duration 3000}])}

View File

@ -8,16 +8,15 @@
[]
(let [unread-count (rf/sub [:activity-center/unread-count])]
[quo/action-drawer
[[{:icon :i/mark-as-read
:override-theme :dark
:label (i18n/label :t/mark-all-notifications-as-read)
:disabled? (zero? unread-count)
:on-press (fn []
(rf/dispatch [:activity-center.notifications/mark-all-as-read-locally
(fn []
{:icon :up-to-date
:icon-color colors/success-50
:text (i18n/label :t/notifications-marked-as-read
{:count unread-count})
:override-theme :dark})])
(rf/dispatch [:hide-bottom-sheet]))}]]]))
[[{:icon :i/mark-as-read
:label (i18n/label :t/mark-all-notifications-as-read)
:disabled? (zero? unread-count)
:on-press (fn []
(rf/dispatch [:activity-center.notifications/mark-all-as-read-locally
(fn []
{:icon :up-to-date
:icon-color colors/success-50
:text (i18n/label :t/notifications-marked-as-read
{:count unread-count})
:theme :dark})])
(rf/dispatch [:hide-bottom-sheet]))}]]]))

View File

@ -28,7 +28,6 @@
:type :blur-bg
:size 32
:accessibility-label :close-activity-center
:override-theme :dark
:on-press #(rf/dispatch [:navigate-back])}
:i/close]
[quo/button
@ -36,10 +35,9 @@
:type :blur-bg
:size 32
:accessibility-label :activity-center-open-more
:override-theme :dark
:on-press #(rf/dispatch [:show-bottom-sheet
{:content drawer/options
:override-theme :dark}])}
{:content drawer/options
:theme :dark}])}
:i/options]]
[quo/text
{:size :heading-1

View File

@ -253,10 +253,10 @@
connection-string]
300)
(rf/dispatch [:toasts/upsert
{:icon :i/info
:icon-color colors/danger-50
:override-theme :light
:text (i18n/label :t/error-this-is-not-a-sync-qr-code)}]))))
{:icon :i/info
:icon-color colors/danger-50
:theme :dark
:text (i18n/label :t/error-this-is-not-a-sync-qr-code)}]))))
(defn render-camera
[show-camera? torch-mode qr-view-finder camera-ref on-read-code]

View File

@ -122,7 +122,7 @@
{:on-press (fn []
(clipboard/set-string @code)
(rf/dispatch [:toasts/upsert
{:icon :correct
{:icon :i/correct
:icon-color colors/success-50
:text (i18n/label
:t/sharing-copied-to-clipboard)}]))