Follow-up quo2 reaction selector components (#17304)

* ref: refactored react/react-selector/reactions-selector

feat: added preview multi-select descriptor

feat: finished component

ref: fixed linting

feat: added pinned styles to all reactions

lint: fixed linting

ref: preview customizer for reactions-selector

lint: fixed linting

fix: preview select bg

ref: destructured reaction

* feat: added pinned prop in chat messages

* fix: removed status_im2 require inside quo2 component

* fix: addressed review comments

* lint: fixed linting

* fix: added missing theme arg to theme-color

* chore: removed unnecessary FIXME

* fix: message reactions not working on press
This commit is contained in:
Lungu Cristian 2023-10-09 12:44:12 +03:00 committed by GitHub
parent b432aab701
commit 265d9be6c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 476 additions and 221 deletions

View File

@ -1,43 +0,0 @@
(ns quo2.components.reactions.reaction
(:require [quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.components.reactions.resource :as resource]
[quo2.components.reactions.style :as style]
[quo2.foundations.colors :as colors]
[quo2.theme :as theme]
[react-native.core :as rn]))
(defn- add-reaction-internal
[{:keys [on-press theme]}]
[rn/touchable-opacity
{:on-press on-press
:accessibility-label :emoji-reaction-add
:style (style/add-reaction theme)}
[icons/icon :i/add-reaction
{:size 20
:color (colors/theme-colors colors/neutral-50
colors/neutral-40
theme)}]])
(def add-reaction (theme/with-theme add-reaction-internal))
(defn reaction-internal
"Add your emoji as a param here"
[{:keys [emoji clicks neutral? on-press accessibility-label on-long-press theme]}]
(let [numeric-value (int clicks)]
[rn/touchable-opacity
{:on-press on-press
:on-long-press on-long-press
:accessibility-label accessibility-label
:style (style/reaction neutral? theme)}
[rn/image
{:style {:width 16 :height 16}
:accessibility-label :emoji
:source (resource/get-reaction emoji)}]
[text/text
{:size :paragraph-2
:weight :semi-bold
:style style/reaction-count}
(str (if (pos? numeric-value) numeric-value 1))]]))
(def reaction (theme/with-theme reaction-internal))

View File

@ -1,33 +0,0 @@
(ns quo2.components.reactions.style
(:require [quo2.foundations.colors :as colors]))
(def reaction-styling
{:flex-direction :row
:justify-content :center
:align-items :center
:padding-horizontal 8
:border-radius 8
:height 24})
(defn add-reaction
[theme]
(merge reaction-styling
{:padding-horizontal 8
:border-width 1
:border-color (colors/theme-colors colors/neutral-20
colors/neutral-70
theme)}))
(defn reaction
[neutral? theme]
(merge reaction-styling
{:border-color (colors/theme-colors colors/neutral-20
colors/neutral-80
theme)
:border-width 1
:background-color (if neutral?
(colors/theme-colors colors/neutral-10
colors/neutral-80-opa-40)
:transparent)}))
(def reaction-count {:margin-left 4})

View File

@ -0,0 +1,12 @@
(ns quo2.components.selectors.react.style)
(def container
{:flex-direction :row
:justify-content :flex-start
:flex 1
:flex-wrap :wrap
:margin-bottom -6})
(def reaction-container
{:margin-bottom 6
:margin-right 6})

View File

@ -0,0 +1,26 @@
(ns quo2.components.selectors.react.view
(:require [quo2.components.selectors.react-selector.view :as react-selector]
[quo2.components.selectors.react.style :as style]
[react-native.core :as rn]))
(defn view
[{:keys [reactions on-press on-long-press add-reaction? on-press-add use-case container-style]}]
[rn/view {:style (merge style/container container-style)}
(for [emoji-reaction reactions
:let [{:keys [emoji emoji-id emoji-reaction-id quantity own]} emoji-reaction]]
[react-selector/view
{:key emoji-reaction-id
:emoji emoji
:state (if own :pressed :not-pressed)
:use-case use-case
:container-style style/reaction-container
:clicks quantity
:on-press #(on-press emoji-reaction)
:on-long-press #(on-long-press emoji-reaction)
:accessibility-label (str "emoji-reaction-" emoji-id)}])
(when add-reaction?
[react-selector/view
{:on-press on-press-add
:state :add-reaction
:use-case use-case
:accessibility-label (str "emoji-add-reaction")}])])

View File

@ -0,0 +1,44 @@
(ns quo2.components.selectors.react-selector.style
(:require [quo2.foundations.colors :as colors]))
(defn add-reaction
[pinned? theme]
(let [border-color (if pinned?
(colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)
(colors/theme-colors colors/neutral-20 colors/neutral-70 theme))]
(cond-> {:justify-content :center
:align-items :center
:padding-horizontal 7
:border-radius 8
:border-width 1
:height 24
:border-color border-color})))
(defn reaction
[pressed? pinned? theme]
(let [background-color (cond
(not pressed?) :transparent
pinned? (colors/theme-colors colors/neutral-80-opa-5
colors/white-opa-5
theme)
:else (colors/theme-colors colors/neutral-10
colors/neutral-80-opa-40
theme))
border-color (if pinned?
(colors/theme-colors colors/neutral-80-opa-5
colors/white-opa-5
theme)
(colors/theme-colors colors/neutral-20
colors/neutral-80
theme))]
{:flex-direction :row
:justify-content :center
:align-items :center
:padding-horizontal 8
:border-radius 8
:height 24
:border-width 1
:background-color background-color
:border-color border-color}))
(def reaction-count {:margin-left 4})

View File

@ -0,0 +1,46 @@
(ns quo2.components.selectors.react-selector.view
(:require [quo2.components.markdown.text :as text]
[quo2.components.selectors.reaction-resource :as reaction.resource]
[quo2.components.selectors.react-selector.style :as style]
[quo2.theme :as quo.theme]
[quo2.foundations.colors :as colors]
[quo2.components.icon :as icons]
[react-native.core :as rn]))
(defn- view-internal
[{:keys [emoji clicks state use-case on-press accessibility-label on-long-press container-style
theme]}]
(let [numeric-value (int clicks)
icon-color (if (= :pinned use-case)
(colors/theme-colors colors/neutral-80-opa-70 colors/white-opa-70 theme)
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))]
(if (= :add-reaction state)
[rn/touchable-opacity
{:on-press on-press
:accessibility-label :emoji-reaction-add
:style (style/add-reaction
(= :pinned use-case)
theme)}
[icons/icon :i/add-reaction
{:size 20
:color icon-color}]]
[rn/touchable-opacity
{:on-press on-press
:on-long-press on-long-press
:accessibility-label accessibility-label
:style (merge (style/reaction (= :pressed state)
(= :pinned use-case)
theme)
container-style)}
[rn/image
{:style {:width 15 :height 15}
:accessibility-label :emoji
:source (reaction.resource/get-reaction emoji)}]
[text/text
{:size :paragraph-2
:weight :semi-bold
:style style/reaction-count}
(str (if (pos? numeric-value) numeric-value 1))]])))
(def view (quo.theme/with-theme view-internal))

View File

@ -1,4 +1,4 @@
(ns quo2.components.reactions.resource (ns quo2.components.selectors.reaction-resource
(:require [clojure.java.io :as io] (:require [clojure.java.io :as io]
[clojure.string :as string])) [clojure.string :as string]))

View File

@ -1,5 +1,5 @@
(ns quo2.components.reactions.resource (ns quo2.components.selectors.reaction-resource
(:require-macros [quo2.components.reactions.resource :refer [resolve-all-reactions]])) (:require-macros [quo2.components.selectors.reaction-resource :refer [resolve-all-reactions]]))
(def ^:private reactions (def ^:private reactions
(resolve-all-reactions)) (resolve-all-reactions))

View File

@ -1,25 +0,0 @@
(ns quo2.components.selectors.reactions.view
(:require [quo2.components.reactions.resource :as reactions.resource]
[quo2.components.selectors.reactions.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[_ {:keys [start-pressed?]}]
(let [pressed? (reagent/atom start-pressed?)]
(fn [emoji
{:keys [container-style on-press
accessibility-label]
:or {accessibility-label :reaction}}]
[rn/touchable-without-feedback
{:accessibility-label accessibility-label
:on-press (fn [e]
(swap! pressed? not)
(when on-press
(on-press e)))}
[rn/view
{:style (merge (style/container @pressed?)
container-style)}
[rn/image
{:source (reactions.resource/get-reaction emoji)
:style {:width 20 :height 20}}]]])))

View File

@ -1,23 +1,26 @@
(ns quo2.components.selectors.reactions.component-spec (ns quo2.components.selectors.reactions-selector.component-spec
(:require [quo2.components.selectors.reactions.view :as view] (:require [quo2.components.selectors.reactions-selector.view :as view]
[test-helpers.component :as h])) [test-helpers.component :as h]))
(h/describe "Selectors > Reactions" (h/describe "Selectors > Reactions"
(h/test "renders component" (h/test "renders component"
(h/render [view/view :reaction/sad]) (h/render [view/view {:emoji :reaction/sad}])
(h/is-truthy (h/get-by-label-text :reaction))) (h/is-truthy (h/get-by-label-text :reaction)))
(h/describe "on-press event" (h/describe "on-press event"
(h/test "starts with released state" (h/test "starts with released state"
(let [on-press (h/mock-fn)] (let [on-press (h/mock-fn)]
(h/render [view/view :reaction/love {:on-press on-press}]) (h/render [view/view
{:emoji :reaction/love
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :reaction)) (h/fire-event :press (h/get-by-label-text :reaction))
(h/was-called on-press))) (h/was-called on-press)))
(h/test "starts with pressed state" (h/test "starts with pressed state"
(let [on-press (h/mock-fn)] (let [on-press (h/mock-fn)]
(h/render [view/view :reaction/love (h/render [view/view
{:on-press on-press {:emoji :reaction/love
:on-press on-press
:start-pressed? true}]) :start-pressed? true}])
(h/fire-event :press (h/get-by-label-text :reaction)) (h/fire-event :press (h/get-by-label-text :reaction))
(h/was-called on-press))))) (h/was-called on-press)))))

View File

@ -1,4 +1,4 @@
(ns quo2.components.selectors.reactions.style (ns quo2.components.selectors.reactions-selector.style
(:require [quo2.foundations.colors :as colors])) (:require [quo2.foundations.colors :as colors]))
(defn container (defn container

View File

@ -0,0 +1,23 @@
(ns quo2.components.selectors.reactions-selector.view
(:require [quo2.components.selectors.reaction-resource :as reactions.resource]
[quo2.components.selectors.reactions-selector.style :as style]
[react-native.core :as rn]
[reagent.core :as reagent]))
(defn view
[{:keys [start-pressed?]}]
(let [pressed? (reagent/atom start-pressed?)]
(fn [{:keys [emoji container-style on-press
accessibility-label]
:or {accessibility-label :reaction}}]
[rn/pressable
{:accessibility-label accessibility-label
:style (merge (style/container @pressed?)
container-style)
:on-press (fn [e]
(swap! pressed? not)
(when on-press
(on-press e)))}
[rn/image
{:source (reactions.resource/get-reaction emoji)
:style {:width 20 :height 20}}]])))

View File

@ -99,12 +99,13 @@
quo2.components.profile.profile-card.view quo2.components.profile.profile-card.view
quo2.components.profile.select-profile.view quo2.components.profile.select-profile.view
quo2.components.profile.showcase-nav.view quo2.components.profile.showcase-nav.view
quo2.components.reactions.reaction
quo2.components.record-audio.record-audio.view quo2.components.record-audio.record-audio.view
quo2.components.record-audio.soundtrack.view quo2.components.record-audio.soundtrack.view
quo2.components.selectors.disclaimer.view quo2.components.selectors.disclaimer.view
quo2.components.selectors.filter.view quo2.components.selectors.filter.view
quo2.components.selectors.reactions.view quo2.components.selectors.reactions-selector.view
quo2.components.selectors.react.view
quo2.components.selectors.react-selector.view
quo2.components.selectors.selectors.view quo2.components.selectors.selectors.view
quo2.components.settings.accounts.view quo2.components.settings.accounts.view
quo2.components.settings.data-item.view quo2.components.settings.data-item.view
@ -307,10 +308,6 @@
(def select-profile quo2.components.profile.select-profile.view/view) (def select-profile quo2.components.profile.select-profile.view/view)
(def showcase-nav quo2.components.profile.showcase-nav.view/view) (def showcase-nav quo2.components.profile.showcase-nav.view/view)
;;;; Reactions
(def reaction quo2.components.reactions.reaction/reaction)
(def add-reaction quo2.components.reactions.reaction/add-reaction)
;;;; Record Audio ;;;; Record Audio
(def record-audio quo2.components.record-audio.record-audio.view/record-audio) (def record-audio quo2.components.record-audio.record-audio.view/record-audio)
(def soundtrack quo2.components.record-audio.soundtrack.view/f-soundtrack) (def soundtrack quo2.components.record-audio.soundtrack.view/f-soundtrack)
@ -319,7 +316,9 @@
(def author quo2.components.messages.author.view/author) (def author quo2.components.messages.author.view/author)
(def disclaimer quo2.components.selectors.disclaimer.view/view) (def disclaimer quo2.components.selectors.disclaimer.view/view)
(def filter quo2.components.selectors.filter.view/view) (def filter quo2.components.selectors.filter.view/view)
(def reactions quo2.components.selectors.reactions.view/view) (def reactions-selector quo2.components.selectors.reactions-selector.view/view)
(def react quo2.components.selectors.react.view/view)
(def react-selector quo2.components.selectors.react-selector.view/view)
(def checkbox quo2.components.selectors.selectors.view/checkbox) (def checkbox quo2.components.selectors.selectors.view/checkbox)
(def toggle quo2.components.selectors.selectors.view/toggle) (def toggle quo2.components.selectors.selectors.view/toggle)
(def radio quo2.components.selectors.selectors.view/radio) (def radio quo2.components.selectors.selectors.view/radio)

View File

@ -59,7 +59,7 @@
[quo2.components.record-audio.soundtrack.component-spec] [quo2.components.record-audio.soundtrack.component-spec]
[quo2.components.selectors.disclaimer.component-spec] [quo2.components.selectors.disclaimer.component-spec]
[quo2.components.selectors.filter.component-spec] [quo2.components.selectors.filter.component-spec]
[quo2.components.selectors.reactions.component-spec] [quo2.components.selectors.reactions-selector.component-spec]
[quo2.components.selectors.selectors.component-spec] [quo2.components.selectors.selectors.component-spec]
[quo2.components.settings.reorder-item.component-spec] [quo2.components.settings.reorder-item.component-spec]
[quo2.components.settings.settings-item.component-spec] [quo2.components.settings.settings-item.component-spec]

View File

@ -23,7 +23,6 @@
(def ^:const content-type-link 101) (def ^:const content-type-link 101)
(def ^:const content-type-album 102) (def ^:const content-type-album 102)
(def ^:const contact-request-state-none 0) (def ^:const contact-request-state-none 0)
(def ^:const contact-request-state-mutual 1) (def ^:const contact-request-state-mutual 1)
(def ^:const contact-request-state-sent 2) (def ^:const contact-request-state-sent 2)

View File

@ -1,13 +1,12 @@
(ns status-im2.contexts.chat.messages.content.reactions.view (ns status-im2.contexts.chat.messages.content.reactions.view
(:require [status-im2.constants :as constants] (:require [quo2.core :as quo]
[quo2.core :as quo] [status-im2.constants :as constants]
[react-native.core :as rn]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[status-im2.contexts.chat.messages.drawers.view :as drawers] [status-im2.contexts.chat.messages.drawers.view :as drawers]
[quo2.theme :as quo.theme])) [quo2.theme :as quo.theme]))
(defn- on-press (defn- on-press
[own message-id emoji-id emoji-reaction-id] [{:keys [own message-id emoji-id emoji-reaction-id]}]
(if own (if own
(rf/dispatch [:models.reactions/send-emoji-reaction-retraction (rf/dispatch [:models.reactions/send-emoji-reaction-retraction
{:message-id message-id {:message-id message-id
@ -18,7 +17,7 @@
:emoji-id emoji-id}]))) :emoji-id emoji-id}])))
(defn- on-long-press (defn- on-long-press
[{:keys [message-id emoji-id user-message-content reactions theme]}] [{:keys [message-id emoji-id user-message-content reactions-order theme]}]
(rf/dispatch (rf/dispatch
[:chat.ui/emoji-reactions-by-message-id [:chat.ui/emoji-reactions-by-message-id
{:message-id message-id {:message-id message-id
@ -33,41 +32,14 @@
[:chat/clear-emoji-reaction-author-details])) [:chat/clear-emoji-reaction-author-details]))
:content (fn [] :content (fn []
[drawers/reaction-authors [drawers/reaction-authors
{:reactions-order reactions {:reactions-order reactions-order
:theme theme}]) :theme theme}])
:selected-item (fn [] :selected-item (fn []
user-message-content) user-message-content)
:padding-bottom-override 0}]))}])) :padding-bottom-override 0}]))}]))
(defn- view-internal (defn- on-press-add
[{:keys [message-id chat-id theme]} user-message-content] [{:keys [chat-id message-id user-message-content]}]
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])]
[:<>
(when (seq reactions)
[rn/scroll-view
{:shows-horizontal-scroll-indicator false
:horizontal true
:style {:margin-left 44
:margin-top 8
:flex-direction :row}}
(for [{:keys [own emoji-id quantity emoji-reaction-id]
:as emoji-reaction} reactions]
^{:key emoji-reaction}
[rn/view {:style {:margin-right 6}}
[quo/reaction
{:emoji (get constants/reactions emoji-id)
:neutral? own
:clicks quantity
:on-press #(on-press own message-id emoji-id emoji-reaction-id)
:on-long-press #(on-long-press
{:message-id message-id
:emoji-id emoji-id
:user-message-content user-message-content
:reactions (map :emoji-id reactions)
:theme theme})
:accessibility-label (str "emoji-reaction-" emoji-id)}]])
[quo/add-reaction
{:on-press (fn []
(rf/dispatch [:dismiss-keyboard]) (rf/dispatch [:dismiss-keyboard])
(rf/dispatch (rf/dispatch
[:show-bottom-sheet [:show-bottom-sheet
@ -75,6 +47,32 @@
{:chat-id chat-id {:chat-id chat-id
:message-id message-id}]) :message-id message-id}])
:selected-item (fn [] :selected-item (fn []
user-message-content)}]))}]])])) user-message-content)}]))
(defn- add-emoji-key
[reaction]
(assoc reaction
:emoji
(get constants/reactions (:emoji-id reaction))))
(defn- view-internal
[{:keys [message-id chat-id pinned-by theme]} user-message-content]
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])]
[:<>
(when (seq reactions)
[quo/react
{:container-style {:margin-left 44
:margin-top 8}
:reactions (map add-emoji-key reactions)
:add-reaction? true
:use-case (when pinned-by :pinned)
:on-press #(on-press (assoc % :message-id message-id))
:on-long-press #(on-long-press (assoc %
:message-id message-id
:theme theme
:reactions-order (map :emoji-id reactions)))
:on-press-add #(on-press-add {:chat-id chat-id
:message-id message-id
:user-message-content user-message-content})}])]))
(def message-reactions-row (quo.theme/with-theme view-internal)) (def message-reactions-row (quo.theme/with-theme view-internal))

View File

@ -10,7 +10,7 @@
[status-im2.common.contact-list-item.view :as contact-list-item] [status-im2.common.contact-list-item.view :as contact-list-item]
[status-im2.contexts.chat.messages.drawers.style :as style] [status-im2.contexts.chat.messages.drawers.style :as style]
[react-native.gesture :as gesture] [react-native.gesture :as gesture]
[quo2.components.reactions.resource :as reactions.resource])) [quo2.components.selectors.reaction-resource :as reactions.resource]))
(defn contact-list-item-fn (defn contact-list-item-fn
[{:keys [from compressed-key]}] [{:keys [from compressed-key]}]
@ -185,8 +185,9 @@
(for [[id reaction-name] constants/reactions (for [[id reaction-name] constants/reactions
:let [emoji-reaction-id (get own-reactions id)]] :let [emoji-reaction-id (get own-reactions id)]]
^{:key id} ^{:key id}
[quo/reactions reaction-name [quo/reactions-selector
{:start-pressed? (boolean emoji-reaction-id) {:emoji reaction-name
:start-pressed? (boolean emoji-reaction-id)
:accessibility-label (str "reaction-" (name reaction-name)) :accessibility-label (str "reaction-" (name reaction-name))
:on-press :on-press
(fn [] (fn []

View File

@ -14,7 +14,6 @@
[status-im2.contexts.quo-preview.avatars.group-avatar :as group-avatar] [status-im2.contexts.quo-preview.avatars.group-avatar :as group-avatar]
[status-im2.contexts.quo-preview.avatars.icon-avatar :as icon-avatar] [status-im2.contexts.quo-preview.avatars.icon-avatar :as icon-avatar]
[status-im2.contexts.quo-preview.avatars.user-avatar :as user-avatar] [status-im2.contexts.quo-preview.avatars.user-avatar :as user-avatar]
[status-im2.contexts.quo-preview.selectors.reactions :as selector-reactions]
[status-im2.contexts.quo-preview.avatars.wallet-user-avatar :as [status-im2.contexts.quo-preview.avatars.wallet-user-avatar :as
wallet-user-avatar] wallet-user-avatar]
[status-im2.contexts.quo-preview.banners.banner :as banner] [status-im2.contexts.quo-preview.banners.banner :as banner]
@ -119,11 +118,13 @@
[status-im2.contexts.quo-preview.profile.profile-card :as profile-card] [status-im2.contexts.quo-preview.profile.profile-card :as profile-card]
[status-im2.contexts.quo-preview.profile.select-profile :as select-profile] [status-im2.contexts.quo-preview.profile.select-profile :as select-profile]
[status-im2.contexts.quo-preview.profile.showcase-nav :as showcase-nav] [status-im2.contexts.quo-preview.profile.showcase-nav :as showcase-nav]
[status-im2.contexts.quo-preview.reactions.react :as react]
[status-im2.contexts.quo-preview.record-audio.record-audio :as record-audio] [status-im2.contexts.quo-preview.record-audio.record-audio :as record-audio]
[status-im2.contexts.quo-preview.selectors.disclaimer :as disclaimer] [status-im2.contexts.quo-preview.selectors.disclaimer :as disclaimer]
[status-im2.contexts.quo-preview.selectors.filter :as filter] [status-im2.contexts.quo-preview.selectors.filter :as filter]
[status-im2.contexts.quo-preview.selectors.selectors :as selectors] [status-im2.contexts.quo-preview.selectors.selectors :as selectors]
[status-im2.contexts.quo-preview.selectors.reactions-selector :as reactions-selector]
[status-im2.contexts.quo-preview.selectors.react-selector :as react-selector]
[status-im2.contexts.quo-preview.selectors.react :as react]
[status-im2.contexts.quo-preview.settings.accounts :as accounts] [status-im2.contexts.quo-preview.settings.accounts :as accounts]
[status-im2.contexts.quo-preview.settings.data-item :as data-item] [status-im2.contexts.quo-preview.settings.data-item :as data-item]
[status-im2.contexts.quo-preview.settings.settings-item :as settings-item] [status-im2.contexts.quo-preview.settings.settings-item :as settings-item]
@ -365,8 +366,6 @@
:component select-profile/view} :component select-profile/view}
{:name :showcase-nav {:name :showcase-nav
:component showcase-nav/view}] :component showcase-nav/view}]
:reactions [{:name :react
:component react/view}]
:record-audio [{:name :record-audio :record-audio [{:name :record-audio
:component record-audio/view}] :component record-audio/view}]
:selectors [{:name :disclaimer :selectors [{:name :disclaimer
@ -375,8 +374,12 @@
:component filter/view} :component filter/view}
{:name :selectors {:name :selectors
:component selectors/view} :component selectors/view}
{:name :select-reactions {:name :reactions-selector
:component selector-reactions/view}] :component reactions-selector/preview}
{:name :react-selector
:component (react-selector/preview-react-selector)}
{:name :react
:component react/preview-react}]
:settings [{:name :privacy-option :settings [{:name :privacy-option
:component privacy-option/preview-options} :component privacy-option/preview-options}
{:name :accounts {:name :accounts

View File

@ -170,6 +170,86 @@
:field-value field-value}] :field-value field-value}]
[customizer-select-button {:open open :selected-option selected-option}]]])))) [customizer-select-button {:open open :selected-option selected-option}]]]))))
(defn- customizer-multi-select-modal
[{:keys [open-atom options selected-keys-atom]}]
[rn/modal
{:visible @open-atom
:on-request-close #(reset! open-atom 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}
(let [checked? (boolean (some #(= k %) @selected-keys-atom))
remove-key (fn [v] (filterv #(not= % k) v))
on-press (fn []
(swap! selected-keys-atom
(if checked? remove-key conj)
k))]
[rn/pressable
{:style (style/multi-select-option)
:on-press on-press}
[rn/text {:style (style/field-text false)} v]
[quo/checkbox
{:checked? checked?
:on-change on-press}]])))]
[rn/view {:style (style/footer)}
[rn/pressable
{:style (style/select-button)
:on-press (fn []
(reset! selected-keys-atom nil)
(reset! open-atom 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-atom false)}
[rn/text {:style (style/field-text false)}
"Close"]]]]]])
(defn filter-by-keys
[items ks]
(filter (fn [item]
(some #(= (:key item) %) ks))
items))
(defn- customizer-multi-select-button
[{:keys [open selected-options]}]
[rn/pressable
{:style (style/select-container)
:on-press #(reset! open true)}
[rn/text
{:style (style/field-select)
:number-of-lines 1}
(if (seq selected-options)
(string/join ", " (map :value selected-options))
"Select options")]
[rn/view
[quo/icon :i/chevron-right]]])
(defn- customizer-multi-select
[]
(let [open (reagent/atom nil)]
(fn [{:keys [label state options] :as args}]
(let [label (or label (key->text-label (:key args)))
selected-keys (reagent/cursor state [(:key args)])
selected-options (filter-by-keys options @selected-keys)]
[rn/view {:style style/field-row}
[label-view state label]
[rn/view {:style style/field-column}
[customizer-multi-select-modal
{:open-atom open
:selected-keys-atom selected-keys
:options options}]
[customizer-multi-select-button {:open open :selected-options selected-options}]]]))))
(defn customizer (defn customizer
[state descriptors] [state descriptors]
[rn/view [rn/view
@ -185,6 +265,7 @@
:text [customizer-text descriptor] :text [customizer-text descriptor]
:number [customizer-number descriptor] :number [customizer-number descriptor]
:select [customizer-select descriptor] :select [customizer-select descriptor]
:multi-select [customizer-multi-select descriptor]
nil)]))]) nil)]))])
(defn customization-color-option (defn customization-color-option

View File

@ -1,31 +0,0 @@
(ns status-im2.contexts.quo-preview.reactions.react
(:require [clojure.string :as string]
[quo2.core :as quo]
[reagent.core :as reagent]
[status-im2.constants :as constants]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Count"
:key :clicks
:type :text}
{:key :emoji
:type :select
:options (for [reaction (vals constants/reactions)]
{:key reaction
:value (string/capitalize (name reaction))})}
{:key :neutral? :type :boolean}])
(defn view
[]
(let [state (reagent/atom {:emoji :reaction/love})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:component-container-style {:padding-bottom 50
:flex-direction :row
:align-items :center
:justify-content :center}}
[quo/reaction @state]
[quo/add-reaction]])))

View File

@ -0,0 +1,75 @@
(ns status-im2.contexts.quo-preview.selectors.react
(:require [clojure.string :as string]
[quo2.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[quo2.foundations.colors :as colors]
[status-im2.constants :as constants]
[status-im2.contexts.quo-preview.preview :as preview]))
(defn- gen-quantity
[max-count _]
(rand-int max-count))
(def ^:private memo-gen-quantity (memoize gen-quantity))
(def ^:private descriptor
[{:key :add-reaction?
:type :boolean}
{:label "Reactions"
:key :reaction-ids
:type :multi-select
:options (for [[reaction-id reaction] constants/reactions]
{:key reaction-id
:value (string/capitalize
(last
(string/split (name reaction) #"/")))})}
{:label "Max rand. reactions (helper)"
:key :max-count
:type :number}
{:key :use-case
:type :select
:options [{:key :default
:value "Default"}
{:key :pinned
:value "Pinned"}]}])
(defn preview-react
[]
(let [state (reagent/atom {:add-reaction? true
:max-count 1000
:reaction-ids [1 2 3]
:use-case :default})
pressed-reactions (reagent/atom #{1})]
(fn []
(let [reactions (mapv (fn [reaction-id]
{:emoji-reaction-id reaction-id
:emoji-id reaction-id
:emoji (get constants/reactions reaction-id)
:quantity (memo-gen-quantity (:max-count @state) reaction-id)
:own (contains? @pressed-reactions reaction-id)})
(:reaction-ids @state))]
[preview/preview-container
{:state state
:descriptor descriptor}
[rn/view
{:padding-bottom 150
:padding-vertical 60
:padding-horizontal 20
:border-radius 16
:background-color (when (= :pinned (:use-case @state))
(colors/custom-color :blue 50 10))
:align-items :flex-start}
[quo/react
{:reactions reactions
:add-reaction? (:add-reaction? @state)
:use-case (:use-case @state)
:on-press (fn [reaction]
(let [reaction-id (:emoji-id reaction)
change-pressed (partial swap! pressed-reactions)]
(if (contains? @pressed-reactions reaction-id)
(change-pressed disj reaction-id)
(change-pressed conj reaction-id))))
:on-long-press identity
:on-press-new identity}]]]))))

View File

@ -0,0 +1,58 @@
(ns status-im2.contexts.quo-preview.selectors.react-selector
(:require [clojure.string :as string]
[quo2.core :as quo]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.constants :as constants]
[status-im2.contexts.quo-preview.preview :as preview]
[quo2.foundations.colors :as colors]))
(def descriptor
[{:key :clicks
:type :text}
{:key :emoji
:type :select
:options (for [reaction (vals constants/reactions)]
{:key reaction
:value (string/capitalize (name reaction))})}
{:key :state
:type :select
:options [{:key :not-pressed
:value "Not pressed by me"}
{:key :pressed
:value "Pressed by me"}
{:key :add-reaction
:value "Add reaction"}]}
{:key :use-case
:type :select
:options [{:key :default
:value "Default"}
{:key :pinned
:value "Pinned"}]}])
(defn preview-react-selector
[]
(let [state (reagent/atom {:emoji :reaction/love
:state :not-pressed
:use-case :default})]
(fn []
(println @state)
[preview/preview-container
{:state state
:descriptor descriptor}
[rn/view
{:padding-bottom 150
:align-items :center}
[rn/view
{:width 100
:padding-vertical 60
:border-radius 16
:background-color (when (= :pinned (:use-case @state))
(colors/custom-color
:blue
50
10))
:justify-content :space-evenly
:flex-direction :row
:align-items :center}
[quo/react-selector @state]]]])))

View File

@ -1,18 +0,0 @@
(ns status-im2.contexts.quo-preview.selectors.reactions
(:require [quo2.core :as quo]
[react-native.core :as rn]
[status-im2.contexts.quo-preview.preview :as preview]
[status-im2.constants :as constants]))
(defn view
[]
[preview/preview-container
{:component-container-style {:flex 1
:padding-top 20
:flex-direction :row
:justify-content :center
:align-items :center}}
[rn/view {:flex-direction :row}
(for [emoji (vals constants/reactions)]
^{:key emoji}
[quo/reactions emoji {:container-style {:margin-right 5}}])]])

View File

@ -0,0 +1,27 @@
(ns status-im2.contexts.quo-preview.selectors.reactions-selector
(:require [quo2.core :as quo]
[clojure.string :as string]
[status-im2.contexts.quo-preview.preview :as preview]
[reagent.core :as r]
[react-native.core :as rn]
[status-im2.constants :as constants]))
(def descriptor
[{:key :emoji
:type :select
:options (for [reaction (vals constants/reactions)]
{:key reaction
:value (string/capitalize (name reaction))})}])
(defn preview
[]
(let [state (r/atom {:emoji :reaction/love})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor}
[rn/view
{:style {:margin-top 40
:align-items :center}}
[quo/reactions-selector {:emoji (:emoji @state)}]]])))

View File

@ -55,6 +55,16 @@
{:flex-shrink 1 {:flex-shrink 1
:padding-top 12}) :padding-top 12})
(defn multi-select-option
[]
(merge (field-container false)
{:justify-content :space-between
:align-items :space-between
:flex 1
:flex-direction :row
:margin-vertical 4
:background-color (field-default-bg-color)}))
(defn select-container (defn select-container
[] []
(merge (field-container false) (merge (field-container false)