Implementation of switcher cards (#13854)

This commit is contained in:
Parvesh Monu 2022-09-19 15:01:13 +05:30 committed by GitHub
parent 552c85d6c7
commit 0c83801209
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 532 additions and 66 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -7,7 +7,7 @@
(defn channel-avatar [{:keys [big? lock-status emoji-background-color emoji]}]
(let [locked? (= :locked lock-status)
lock-exists? (not= :none lock-status)
lock-exists? (and lock-status (not= :none lock-status))
dark? (theme/dark?)]
[rn/view {:style {:width (if big? 32 24)
:height (if big? 32 24)

View File

@ -19,15 +19,16 @@
"type: default, secondary, grey
outline: true, false
value: integer"
[{:keys [type outline]} value]
[{:keys [type outline override-text-color override-bg-color]} value]
(let [type (or type :default)
text-color (if (or
text-color (or override-text-color
(if (or
(= (theme/get-theme) :dark)
(and
(= type :default)
(not outline)))
colors/white
colors/black)
colors/black))
value (if (integer? value)
value
(js/parseInt value))
@ -48,7 +49,9 @@
:border-color (get-color (or type :default))})
(not outline)
(assoc :background-color (get-color (or type :default)))
(assoc :background-color
(or override-bg-color
(get-color (or type :default))))
(> value 99)
(assoc :padding-left 0.5))}

View File

@ -3,6 +3,7 @@
[status-im.i18n.i18n :as i18n]
[quo2.foundations.colors :as colors]
[quo2.components.icon :as quo2.icons]
[status-im.ui.components.fast-image :as fast-image]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.markdown.text :as quo2.text]))
@ -26,16 +27,20 @@
:hole-y -1}})
;; TODO - Add avatar components for other types once implemented
(defn avatar [item type size]
(defn avatar [item type size border-radius]
(case type
:user [user-avatar/user-avatar
(merge {:ring? false
:status-indicator? false
:size (case size 32 :small 24 :xs 16 :xxxs)}
item)]))
item)]
(:photo :collectible) [fast-image/fast-image {:source (:source item)
:style {:width size
:height size
:border-radius border-radius}}]))
(defn list-item [index type size item list-size margin-left
hole-size hole-radius hole-x hole-y]
hole-size hole-radius hole-x hole-y border-radius]
(let [last-item? (= index (- list-size 1))]
[rn/hole-view {:style {:margin-left (if (= index 0) 0 margin-left)}
:holes (if last-item? []
@ -44,14 +49,14 @@
:width hole-size
:height hole-size
:borderRadius hole-radius}])}
[avatar item type size]]))
[avatar item type size border-radius]]))
(defn get-overflow-color [transparent? transparent-color light-color dark-color]
(defn get-overflow-color [transparent? transparent-color light-color dark-color override-theme]
(if transparent?
transparent-color
(colors/theme-colors light-color dark-color)))
(colors/theme-colors light-color dark-color override-theme)))
(defn overflow-label [label size transparent? border-radius margin-left]
(defn overflow-label [label size transparent? border-radius margin-left override-theme]
[rn/view {:style {:width size
:height size
:margin-left margin-left
@ -62,21 +67,24 @@
transparent?
colors/white-opa-10
colors/neutral-20
colors/neutral-70)}}
colors/neutral-70
override-theme)}}
(if (= size 16)
[quo2.icons/icon :main-icons2/more {:size 12
:color (get-overflow-color
transparent?
colors/white-opa-70
colors/neutral-50
colors/neutral-40)}]
colors/neutral-40
override-theme)}]
[quo2.text/text {:size (if (= size 32) :paragraph-2 :label)
:weight :medium
:style {:color (get-overflow-color
transparent?
colors/white-opa-70
colors/neutral-60
colors/neutral-40)
colors/neutral-40
override-theme)
:margin-left -2}}
;; If overflow label is below 100, show label as +label (ex. +30), else just show 99+
(if (< label 100)
@ -85,7 +93,7 @@
(defn border-type [type]
(case type
(:account :collectible) :rounded
(:account :collectible :photo) :rounded
:circular))
(defn preview-list
@ -97,7 +105,7 @@
:transparent? overflow-label transparent?}
items preview list items (only 4 items is required for preview)
"
[{:keys [type size list-size transparent?]} items]
[{:keys [type size list-size transparent? override-theme]} items]
(let [items-arr (into [] items)
list-size (or list-size (count items))
margin-left (get-in params [size :margin-left])
@ -110,6 +118,6 @@
(for [index (range (if (> list-size 4) 3 list-size))]
^{:key (str index list-size)}
[list-item index type size (get items-arr index) list-size
margin-left hole-size hole-radius hole-x hole-y])
margin-left hole-size hole-radius hole-x hole-y border-radius])
(when (> list-size 4)
[overflow-label (- list-size 3) size transparent? border-radius margin-left])]))
[overflow-label (- list-size 3) size transparent? border-radius margin-left override-theme])]))

View File

@ -0,0 +1,131 @@
(ns quo2.components.switcher.styles
(:require [quo2.foundations.colors :as colors]))
(def colors-map
{:secondary-container-bg-color colors/neutral-95
:title-color colors/white
:subtitle-color colors/neutral-40
:last-message-text-color colors/white
:close-button-bg-color colors/neutral-80-opa-40
:close-button-icon-color colors/white
:community-channel colors/white})
(defn base-container [background-color]
{:width 160
:height 160
:border-radius 16
:background-color (colors/alpha background-color 0.4)})
(defn secondary-container []
{:width 160
:height 120
:border-radius 16
:bottom 0
:position :absolute
:background-color (:secondary-container-bg-color colors-map)})
(defn title []
{:position :absolute
:top 28
:margin-horizontal 12
:color (:title-color colors-map)})
(defn title-props []
{:size :paragraph-1
:weight :semi-bold
:number-of-lines 1
:ellipsize-mode :tail
:style (title)})
(defn subtitle []
{:position :absolute
:top 50
:margin-horizontal 12
:color (:subtitle-color colors-map)})
(defn subtitle-props []
{:size :paragraph-2
:weight :medium
:style (subtitle)})
(defn content-container [notification?]
{:position :absolute
:max-width (if notification? 108 136)
:flex-shrink 1
:bottom 12
:margin-left 12
:margin-right (if notification? 8 12)})
(defn notification-container []
{:position :absolute
:width 20
:height 20
:bottom 12
:right 12
:justify-content :center
:align-items :center})
(defn last-message-text []
{:color (:last-message-text-color colors-map)})
(defn last-message-text-props []
{:size :paragraph-2
:weight :regular
:number-of-lines 1
:ellipsize-mode :tail
:style (last-message-text)})
(defn close-button []
{:position :absolute
:right 8
:top 8
:background-color (:close-button-bg-color colors-map)
:icon-color (:close-button-icon-color colors-map)})
(defn close-button-props [on-press]
{:size 24
:type :grey
:icon true
:on-press on-press
:override-theme :dark
:style (close-button)})
(defn avatar-container []
{:width 48
:height 48
:left 12
:top 12
:position :absolute})
(defn unread-dot [background-color]
{:width 8
:height 8
:border-radius 4
:background-color background-color})
;; Supporting Components
(defn sticker []
{:width 24
:height 24})
(defn gif []
{:width 24
:height 24
:border-radius 8})
(defn community-avatar []
{:width 48
:height 48
:border-radius 24})
(defn community-channel []
{:margin-left 8
:color (:community-channel colors-map)})
(defn community-channel-props []
{:size :paragraph-2
:weight :medium
:number-of-lines 1
:ellipsize-mode :tail
:style (community-channel)})

View File

@ -0,0 +1,135 @@
(ns quo2.components.switcher.switcher-cards
(:require [quo.react-native :as rn]
[status-im.i18n.i18n :as i18n]
[quo2.foundations.colors :as colors]
[quo2.components.markdown.text :as text]
[quo2.components.buttons.button :as button]
[quo2.components.switcher.styles :as styles]
[quo2.components.counter.counter :as counter]
[quo2.components.tags.status-tags :as status-tags]
[status-im.ui.components.fast-image :as fast-image]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo2.components.avatars.group-avatar :as group-avatar]
[quo2.components.list-items.preview-list :as preview-list]
[quo2.components.avatars.channel-avatar :as channel-avatar]))
;; Supporting Components
(defn content-container [{:keys [content-type data notification? color-50]}]
[rn/view {:style (styles/content-container notification?)}
(case content-type
:text [text/text (styles/last-message-text-props) data]
:photo [preview-list/preview-list {:type :photo
:size 24
:override-theme :dark} data]
:sticker [fast-image/fast-image {:source (:source data)
:style (styles/sticker)}]
:gif [fast-image/fast-image {:source (:source data)
:style (styles/gif)}]
:channel [rn/view {:style {:flex-direction :row
:align-items :center}}
[channel-avatar/channel-avatar
{:emoji (:emoji data)
:emoji-background-color (colors/alpha color-50 0.1)}]
[text/text (styles/community-channel-props) (:channel-name data)]]
:community-info (case (:type data)
:pending [status-tags/status-tag
{:status :pending
:size :small
:override-theme :dark}]
:kicked [status-tags/status-tag
{:status :negative
:size :small
:override-theme :dark
:label (i18n/label :t/kicked)}]
(:count :permission) [:<>]) ;; Add components for these cases
(:audio :community :link :code) ;; Components not available
[:<>])])
(defn notification-container [{:keys [notification-type counter-label color-60]}]
[rn/view {:style (styles/notification-container)}
(if (= notification-type :counter)
[counter/counter {:outline false
:override-text-color colors/white
:override-bg-color color-60} counter-label]
[rn/view {:style (styles/unread-dot color-60)}])])
(defn bottom-container [{:keys [notification?] :as content}]
[:<>
[content-container content]
(when notification?
[notification-container content])])
(defn avatar [avatar-params type customization-color]
(case type
:messaging [user-avatar/user-avatar
(merge {:ring? false
:size :medium
:status-indicator? false}
avatar-params)]
:group-messaging [group-avatar/group-avatar {:color customization-color
:size :large
:override-theme :dark}]
:community-card [fast-image/fast-image {:source (:source avatar-params)
:style (styles/community-avatar)}]))
(defn subtitle [{:keys [content-type data]}]
(case content-type
:text (i18n/label :t/message)
:photo (i18n/label :t/n-photos {:count (count data)})
:sticker (i18n/label :t/sticker)
:gif (i18n/label :t/gif)
:audio (i18n/label :t/audio-message)
:community (i18n/label :t/link-to-community)
:link (i18n/label :t/external-link)
:code (i18n/label :t/code-snippet)
:channel (i18n/label :t/community-channel)
:community-info (i18n/label :t/community)))
;; Screens Card
(defn screens-card [{:keys [avatar-params title type customization-color
on-press on-close content banner]}]
(let [color-50 (colors/custom-color customization-color 50)
color-60 (colors/custom-color customization-color 60)]
[rn/touchable-without-feedback {:on-press on-press}
[rn/view {:style (styles/base-container color-50)}
(when banner
[rn/image {:source (:source banner)
:style {:width 160}}])
[rn/view {:style (styles/secondary-container)}
[text/text (styles/title-props) title]
[text/text (styles/subtitle-props) (subtitle content)]
[bottom-container (merge {:color-50 color-50 :color-60 color-60} content)]]
(when avatar
[rn/view {:style (styles/avatar-container)}
[avatar avatar-params type customization-color]])
[button/button (styles/close-button-props on-close) :main-icons2/close]]]))
;; browser Card
(defn browser-card [_]
[:<>])
;; Wallet Cards
(defn wallet-card [_]
[:<>])
(defn wallet-collectible [_]
[:<>])
(defn wallet-graph [_]
[:<>])
;; Home Card
(defn communities-discover [_]
[:<>])
(defn card [type data]
(case type
:communities-discover [communities-discover data] ;; Home Card
:messaging [screens-card data] ;; Screens Card
:group-messaging [screens-card data] ;; Screens Card
:community-card [screens-card data] ;; Screens Card
:browser-card [browser-card data] ;; Browser Card
:wallet-card [wallet-card data] ;; Wallet Card
:wallet-collectible [wallet-collectible data] ;; Wallet Card
:wallet-graph [wallet-graph data])) ;; Wallet Card

View File

@ -50,18 +50,16 @@
:style {:padding-left 5
:color text-color}} label]]])))
(defn positive [_ _]
(fn [size theme]
(defn positive [size theme label]
[base-tag {:size size
:background-color colors/success-50-opa-10
:icon :verified
:border-color colors/success-50-opa-20
:text-color (if (= theme :light) colors/success-50
colors/success-60)
:label (i18n/label :positive)}]))
:label (or label (i18n/label :positive))}])
(defn negative [_ _]
(fn [size theme]
(defn negative [size theme label]
[base-tag {:size size
:icon :untrustworthy
:background-color colors/danger-50-opa-10
@ -69,10 +67,9 @@
:text-color (if (= theme :light)
colors/danger-50
colors/danger-60)
:label (i18n/label :negative)}]))
:label (or label (i18n/label :negative))}])
(defn pending [_ _]
(fn [size theme]
(defn pending [size theme label]
[base-tag {:size size
:icon :pending
:background-color (if (= theme :light)
@ -82,13 +79,13 @@
colors/neutral-20
colors/neutral-70)
:text-color colors/neutral-50
:label (i18n/label :pending)}]))
:label (or label (i18n/label :pending))}])
(defn status-tag [_]
(fn [{:keys [status size override-theme]}]
(fn [{:keys [status size override-theme label]}]
(let [theme (or override-theme (quo.theme/get-theme))]
[(case status
:positive positive
:negative negative
:pending pending
nil) size theme])))
nil) size theme label])))

View File

@ -46,6 +46,7 @@
;;80 with transparency
(def neutral-80-opa-5 (alpha neutral-80 0.05))
(def neutral-80-opa-10 (alpha neutral-80 0.1))
(def neutral-80-opa-40 (alpha neutral-80 0.4))
(def neutral-80-opa-60 (alpha neutral-80 0.6))
(def neutral-80-opa-70 (alpha neutral-80 0.7))
(def neutral-80-opa-80 (alpha neutral-80 0.8))

View File

@ -3,6 +3,7 @@
[reagent.core :as reagent]
[quo.previews.preview :as preview]
[quo2.foundations.colors :as colors]
[status-im.react-native.resources :as resources]
[quo2.components.list-items.preview-list :as quo2]))
(def descriptor [{:label "Size:"
@ -14,17 +15,33 @@
:value "24"}
{:key 16
:value "16"}]}
{:label "Type:"
:key :type
:type :select
:options [{:key :user
:value "User"}
{:key :photo
:value "Photo"}]}
{:label "List Size"
:key :list-size
:default 10
:type :text}])
(def user-list-mock
;; Mocked list items
(def user-list
[{:full-name "ABC DEF"}
{:full-name "GHI JKL"}
{:full-name "MNO PQR"}
{:full-name "STU VWX"}])
(def photos-list
[{:source (resources/get-mock-image :photo1)}
{:source (resources/get-mock-image :photo2)}
{:source (resources/get-mock-image :photo3)}
{:source (resources/get-mock-image :photo4)}
{:source (resources/get-mock-image :photo5)}
{:source (resources/get-mock-image :photo6)}])
(defn cool-preview []
(let [state (reagent/atom {:type :user
:size 32
@ -37,9 +54,9 @@
[rn/view {:padding-vertical 60
:align-items :center}
[quo2/preview-list @state
;; Mocked list items
(case @type
:user user-list-mock)]]])))
:user user-list
:photo photos-list)]]])))
(defn preview-preview-lists []
[rn/view {:background-color (colors/theme-colors colors/white colors/neutral-90)

View File

@ -33,6 +33,7 @@
[quo2.screens.list-items.preview-lists :as preview-lists]
[quo2.screens.info.lowest-price :as lowest-price]
[quo2.screens.avatars.channel-avatar :as channel-avatar]
[quo2.screens.switcher.switcher-cards :as switcher-cards]
[re-frame.core :as re-frame]))
(def screens-categories
@ -113,7 +114,10 @@
:component token-overview/preview-token-overview}]
:list-items [{:name :preview-lists
:insets {:top false}
:component preview-lists/preview-preview-lists}]})
:component preview-lists/preview-preview-lists}]
:switcher [{:name :switcher-cards
:insets {:top false}
:component switcher-cards/preview-switcher-cards}]})
(def screens (flatten (map val screens-categories)))

View File

@ -0,0 +1,147 @@
(ns quo2.screens.switcher.switcher-cards
(:require [quo.react-native :as rn]
[reagent.core :as reagent]
[quo.previews.preview :as preview]
[quo2.foundations.colors :as colors]
[status-im.react-native.resources :as resources]
[quo2.components.switcher.switcher-cards :as switcher-cards]))
(def descriptor [{:label "Type:"
:key :type
:type :select
:options [{:key :communities-discover
:value "Communities Discover"}
{:key :messaging
:value "Messaging"}
{:key :group-messaging
:value "Group Messaging"}
{:key :community-card
:value "Community Card"}
{:key :browser-card
:value "Browser Card"}
{:key :wallet-card
:value "Wallet Card"}
{:key :wallet-collectible
:value "Wallet Collectible"}
{:key :wallet-graph
:value "Wallet Graph"}]}
{:label "Title"
:key :title
:type :text}
{:label "Notification?:"
:key :notification?
:type :boolean}
{:label "Banner?:"
:key :banner?
:type :boolean}
{:label "Notification Type"
:key :notification-type
:type :select
:options [{:key :counter
:value :counter}
{:key :unread
:value :unread}]}
{:label "Counter Label"
:key :counter-label
:type :text}
{:label "Content Type"
:key :content-type
:type :select
:options [{:key :text
:value :text}
{:key :photo
:value :photo}
{:key :sticker
:value :sticker}
{:key :gif
:value :gif}
{:key :audio
:value :audio}
{:key :community
:value :community}
{:key :link
:value :link}
{:key :code
:value :code}
{:key :channel
:value :channel}
{:key :community-info
:value :community-info}]}
{:label "Last Message"
:key :last-message
:type :text}
{:label "Customization"
:key :customization-color
:type :select
:options
(map
(fn [c]
{:key c
:value c})
(keys colors/customization))}])
;; Mocked Data
(def banner {:source (resources/get-mock-image :community-banner)})
(def sticker {:source (resources/get-mock-image :sticker)})
(def community-avatar {:source (resources/get-mock-image :community-logo)})
(def gif {:source (resources/get-mock-image :gif)})
(def photos-list
[{:source (resources/get-mock-image :photo1)}
{:source (resources/get-mock-image :photo2)}
{:source (resources/get-mock-image :photo3)}
{:source (resources/get-mock-image :photo4)}
{:source (resources/get-mock-image :photo5)}
{:source (resources/get-mock-image :photo6)}])
(defn get-mock-content [data]
(case (:content-type data)
:text (:last-message data)
:photo photos-list
:sticker sticker
:gif gif
:channel {:emoji "🍑" :channel-name "# random"}
:community-info {:type :kicked}
(:audio :community :link :code) nil))
(defn get-mock-data [data]
(merge
data
{:banner (when (:banner? data) banner)
:content {:notification? (:notification? data)
:notification-type (:notification-type data)
:counter-label (:counter-label data)
:content-type (:content-type data)
:data (get-mock-content data)}}
(case (:type data)
:messaging {:avatar-params {:full-name (:title data)}}
:group-messaging {}
:community-card {:avatar-params community-avatar}
{})))
(defn cool-preview []
(let [state (reagent/atom {:type :group-messaging
:title "Alisher Yakupov"
:customization-color :turquoise
:notification? true
:banner? false
:notification-type :counter
:counter-label 2
:content-type :text
:last-message "This is fantastic! Ethereum"})]
(fn []
[rn/view {:margin-bottom 50
:padding 16}
[preview/customizer state descriptor]
[rn/view {:padding-vertical 60
:align-items :center}
[switcher-cards/card (:type @state) (get-mock-data @state)]]])))
(defn preview-switcher-cards []
[rn/view {:background-color (colors/theme-colors colors/white colors/neutral-100)
:flex 1}
[rn/flat-list {:flex 1
:keyboardShouldPersistTaps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -54,6 +54,15 @@
:music (js/require "../resources/images/ui/music.png")
:podcasts (js/require "../resources/images/ui/podcasts.png")})
(def mock-images
{:photo1 (js/require "../resources/images/mock/photo1.png")
:photo2 (js/require "../resources/images/mock/photo2.png")
:photo3 (js/require "../resources/images/mock/photo3.png")
:community-banner (js/require "../resources/images/mock/community-banner.png")
:community-logo (js/require "../resources/images/mock/community-logo.png")
:gif (js/require "../resources/images/mock/gif.png")
:sticker (js/require "../resources/images/mock/sticker.png")})
(defn get-theme-image [k]
(get ui (when (colors/dark?) (keyword (str (name k) "-dark"))) (get ui k)))
@ -65,6 +74,12 @@
(get (swap! loaded-images assoc k
(get ui k)) k)))
(defn get-mock-image [k]
(if (contains? @loaded-images k)
(get @loaded-images k)
(get (swap! loaded-images assoc k
(get mock-images k)) k)))
(def reactions
{:love (js/require "../resources/images/reactions/love.png")
:angry (js/require "../resources/images/reactions/angry.png")

View File

@ -603,6 +603,7 @@
"get-started": "Get started",
"get-status-at": "Get Status at http://status.im",
"get-stickers": "Get Stickers",
"gif": "GIF",
"go-to-settings": "Go to Settings...",
"got-it": "Got it",
"group-chat": "Group chat",
@ -1437,6 +1438,7 @@
"system": "System",
"give-permissions-camera": "Give permission\nto access camera",
"photos": "Photos",
"n-photos": "{{count}} photos",
"image": "Image",
"sign-anyway": "Sign anyway",
"tx-fail-description1": "This transaction is likely to fail. Sign at your own risk using custom network fee.",
@ -1458,6 +1460,7 @@
"audio-recorder-max-ms-reached": "Maximum recording time reached",
"audio-recorder-permissions-error": "You have to give permission to send audio messages",
"audio": "Audio",
"audio-message": "Audio message",
"update-to-see-image": "Update to latest version to see a nice image here!",
"update-to-listen-audio": "Update to latest version to listen to an audio message here!",
"update-to-see-sticker": "Update to latest version to see a nice sticker here!",
@ -1594,6 +1597,7 @@
"community-message-preview": "Invitation to join {{community-name}}",
"non-contacts": "Non contacts",
"community": "Community",
"community-channel": "Community channel",
"verified-community": "✓ Verified community",
"community-info-not-found": "Community information not found",
"community-info": "Community info",
@ -1781,6 +1785,10 @@
"lifestyle": "Lifestyle",
"podcasts": "Podcasts",
"NFT":"NFT",
"new-messages-header": "New Messages"
"new-messages-header": "New Messages",
"link-to-community": "Link to community",
"external-link": "External link",
"code-snippet": "Code snippet",
"kicked": "Kicked"
}