Bottom sheet missing actions (#14332)

* feat: bottom sheets
This commit is contained in:
Omar Basem 2022-11-11 17:02:39 +04:00 committed by GitHub
parent 8fc853373b
commit 57526a45ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 333 additions and 138 deletions

View File

@ -1,8 +1,8 @@
(ns quo2.components.drawers.action-drawers
(:require [react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.icon :as icon]
[quo2.foundations.colors :as colors]))
(:require [react-native.core :as rn]
[quo2.components.markdown.text :as text]
[quo2.components.icon :as icon]
[quo2.foundations.colors :as colors]))
(defn- get-icon-color [danger?]
(if danger?
@ -14,47 +14,48 @@
sub-label
right-icon
danger?
on-press]}]
[rn/touchable-opacity {:on-press on-press}
[rn/view {:style
{:height (if sub-label 56 47)
:margin-horizontal 20
:flex-direction :row}}
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:margin-right 12
:width 20}}
[icon/icon icon
{:color (get-icon-color danger?)
:size 20}]]
[rn/view
{:style
{:flex 1
:justify-content :center}}
[text/text
{:size :paragraph-1
:weight :medium
:style {:color
(when danger?
(colors/theme-colors colors/danger-50 colors/danger-60))}}
label]
(when sub-label
[text/text
{:size :paragraph-2
:style {:color
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
sub-label])]
(when right-icon
on-press] :as action-props}]
(when action-props
[rn/touchable-opacity {:on-press on-press}
[rn/view {:style
{:height (if sub-label 56 47)
:margin-horizontal 20
:flex-direction :row}}
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:width 20}}
[icon/icon right-icon
:margin-right 12
:width 20}}
[icon/icon icon
{:color (get-icon-color danger?)
:size 20}]])]])
:size 20}]]
[rn/view
{:style
{:flex 1
:justify-content :center}}
[text/text
{:size :paragraph-1
:weight :medium
:style {:color
(when danger?
(colors/theme-colors colors/danger-50 colors/danger-60))}}
label]
(when sub-label
[text/text
{:size :paragraph-2
:style {:color
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
sub-label])]
(when right-icon
[rn/view {:style
{:height 20
:margin-top :auto
:margin-bottom :auto
:width 20}}
[icon/icon right-icon
{:color (get-icon-color danger?)
:size 20}]])]]))
(defn divider []
[rn/view {:style {:border-top-width 1

View File

@ -4,38 +4,41 @@
[status-im.chat.models.pin-message :as models.pin-message]
[status-im.i18n.i18n :as i18n]
[status-im.constants :as constants]
[status-im.utils.handlers :refer [<sub >evt]]
[status-im.utils.re-frame :as rf]
[quo2.components.drawers.action-drawers :as drawer]))
(defn- entry [icon label on-press danger?]
(defn- entry [{:keys [icon label on-press danger? sub-label chevron?]}]
{:pre [(keyword? icon)
(string? label)
(fn? on-press)
(boolean? danger?)]}
{:icon icon
:label label
:on-press on-press
:danger? danger?})
(boolean? danger?)
(boolean? chevron?)]}
{:icon icon
:label label
:on-press on-press
:danger? danger?
:sub-label sub-label
:right-icon (when chevron? :i/chevron-right)})
(defn hide-sheet-and-dispatch [event]
(>evt [:bottom-sheet/hide])
(>evt event))
(rf/dispatch [:bottom-sheet/hide])
(rf/dispatch event))
(defn show-profile-action [chat-id]
(hide-sheet-and-dispatch [:chat.ui/show-profile chat-id])
(>evt [::models.pin-message/load-pin-messages chat-id]))
(hide-sheet-and-dispatch [:chat.ui/show-profile chat-id])
(rf/dispatch [::models.pin-message/load-pin-messages chat-id]))
(defn mark-all-read-action [chat-id]
(hide-sheet-and-dispatch [:chat/mark-all-as-read chat-id]))
(hide-sheet-and-dispatch [:chat/mark-all-as-read chat-id]))
(defn edit-nickname-action [chat-id]
(hide-sheet-and-dispatch [:chat.ui/edit-nickname chat-id]))
(hide-sheet-and-dispatch [:chat.ui/edit-nickname chat-id]))
(defn mute-chat-action [chat-id]
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id true]))
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id true]))
(defn unmute-chat-action [chat-id]
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id false]))
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id false]))
(defn clear-history-action [chat-id]
(hide-sheet-and-dispatch [:chat.ui/clear-history-pressed chat-id]))
@ -43,75 +46,256 @@
(defn delete-chat-action [chat-id]
(hide-sheet-and-dispatch [:chat.ui/remove-chat-pressed chat-id]))
(defn mute-chat-entry [muted? chat-id]
(entry :i/muted
(i18n/label
(if muted?
:unmute-chat
:mute-chat))
(if muted?
#(unmute-chat-action chat-id)
#(mute-chat-action chat-id))
false))
(defn leave-group-action [chat-id]
(hide-sheet-and-dispatch [:group-chats.ui/leave-chat-pressed chat-id]))
(defn mute-chat-entry [chat-id]
(let [muted? (rf/sub [:chats/muted chat-id])]
(entry {:icon :i/muted
:label (i18n/label
(if muted?
:unmute-chat
:mute-chat))
:on-press (if muted?
#(unmute-chat-action chat-id)
#(mute-chat-action chat-id))
:danger? false
:sub-label nil
:chevron? true})))
(defn mark-as-read-entry [chat-id]
(entry :i/check
(i18n/label :mark-as-read)
#(mark-all-read-action chat-id)
false))
(entry {:icon :i/correct
:label (i18n/label :t/mark-as-read)
:on-press #(mark-all-read-action chat-id)
:danger? false
:sub-label nil
:chevron? false}))
(defn clear-history-entry [chat-id]
(entry :i/delete
(i18n/label :clear-history)
#(clear-history-action chat-id)
true))
(entry {:icon :i/delete
:label (i18n/label :t/clear-history)
:on-press #(clear-history-action chat-id)
:danger? true
:sub-label nil
:chevron? false}))
(defn delete-chat-entry [chat-id]
(entry :i/delete
(i18n/label :delete-chat)
#(delete-chat-action chat-id)
true))
(entry {:icon :i/delete
:label (i18n/label :t/delete-chat)
:on-press #(delete-chat-action chat-id)
:danger? true
:sub-label nil
:chevron? false}))
(defn leave-group-entry [chat-id]
(entry {:icon :i/log-out
:label (i18n/label :t/leave-group)
:on-press #(leave-group-action chat-id)
:danger? true
:sub-label nil
:chevron? false}))
(defn view-profile-entry [chat-id]
(entry :i/friend
(i18n/label :view-profile)
#(show-profile-action chat-id)
false))
(entry {:icon :i/friend
:label (i18n/label :t/view-profile)
:on-press #(show-profile-action chat-id)
:danger? false
:sub-label nil
:chevron? false}))
(defn edit-nickname-entry [chat-id]
(entry :i/edit
(i18n/label :edit-nickname)
#(edit-nickname-action chat-id)
false))
(entry {:icon :i/edit
:label (i18n/label :t/edit-nickname)
:on-press #(edit-nickname-action chat-id)
:danger? false
:sub-label nil
:chevron? false}))
(defn destructive-actions [chat-id]
(defn notifications-entry []
(entry {:icon :i/notifications
:label (i18n/label :t/notifications)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label "All messages" ; TODO: placeholder
:chevron? true}))
(defn fetch-messages-entry []
(entry {:icon :i/save
:label (i18n/label :t/fetch-messages)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? true}))
(defn pinned-messages-entry []
(entry {:icon :i/pin
:label (i18n/label :t/pinned-messages)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? true}))
(defn remove-from-contacts-entry [contact]
(entry {:icon :i/remove-user
:label (i18n/label :t/remove-from-contacts)
:on-press #(hide-sheet-and-dispatch [:contact.ui/remove-contact-pressed contact])
:danger? false
:sub-label nil
:chevron? false}))
(defn rename-entry []
(entry {:icon :i/edit
:label (i18n/label :t/rename)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? false}))
(defn show-qr-entry []
(entry {:icon :i/qr-code
:label (i18n/label :t/show-qr)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? false
:sub-label nil
:chevron? false}))
(defn share-profile-entry []
(entry {:icon :i/share
:label (i18n/label :t/share-profile)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(defn share-group-entry []
(entry {:icon :i/share
:label (i18n/label :t/share)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(defn mark-untrustworthy-entry []
(entry {:icon :i/alert
:label (i18n/label :t/mark-untrustworthy)
:on-press #(js/alert "TODO: to be implemented, probably requires status-go impl. and design input")
:danger? true
:sub-label nil
:chevron? false}))
(defn block-user-entry []
(entry {:icon :i/block
:label (i18n/label :t/block-user)
:on-press #(js/alert "TODO: to be implemented, requires design input")
:danger? true
:sub-label nil
:chevron? false}))
(defn group-details-entry [chat-id]
(entry {:icon :i/members
:label (i18n/label :t/group-details)
:on-press #(hide-sheet-and-dispatch [:show-group-chat-profile chat-id])
:danger? false
:sub-label nil
:chevron? false}))
(defn add-members-entry []
(entry {:icon :i/add-user
:label (i18n/label :t/add-members)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(defn manage-members-entry []
(entry {:icon :i/add-user
:label (i18n/label :t/manage-members)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(defn edit-group-entry []
(entry {:icon :i/edit
:label (i18n/label :t/edit-name-and-image)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(defn group-privacy-entry []
(entry {:icon :i/privacy
:label (i18n/label :t/change-group-privacy)
:on-press #(js/alert "TODO: to be implemented")
:danger? false
:sub-label nil
:chevron? false}))
(defn destructive-actions [chat-id group-chat]
[(clear-history-entry chat-id)
(delete-chat-entry chat-id)])
(if group-chat
(leave-group-entry chat-id)
(delete-chat-entry chat-id))])
(defn notification-actions [muted? chat-id]
[(mute-chat-entry muted? chat-id)
(mark-as-read-entry chat-id)])
(defn notification-actions [{:keys [chat-id group-chat public?]} inside-chat?]
[(mark-as-read-entry chat-id)
(mute-chat-entry chat-id)
(notifications-entry)
(if inside-chat?
(fetch-messages-entry)
(pinned-messages-entry))
(when (or (not group-chat) public?)
(show-qr-entry))
(when-not group-chat
(share-profile-entry))
(when public?
(share-group-entry))])
(defn one-to-one-actions [muted? chat-id]
(defn group-actions [{:keys [chat-id admins]} inside-chat?]
(let [current-pk (rf/sub [:multiaccount/public-key])
admin? (get admins current-pk)]
[(group-details-entry chat-id)
(when inside-chat?
(if admin?
(manage-members-entry)
(add-members-entry)))
(when (and admin? inside-chat?) (edit-group-entry))
(when (and admin? inside-chat?) (group-privacy-entry))]))
(defn one-to-one-actions [{:keys [chat-id group-chat] :as item} inside-chat?]
[drawer/action-drawer [[(view-profile-entry chat-id)
(edit-nickname-entry chat-id)]
(notification-actions muted? chat-id)
(destructive-actions chat-id)]])
(notification-actions item inside-chat?)
(destructive-actions chat-id group-chat)]])
(defn public-chat-actions [muted? chat-id]
[drawer/action-drawer [(notification-actions muted? chat-id)
(destructive-actions chat-id)]])
(defn public-chat-actions [{:keys [chat-id group-chat] :as item} inside-chat?]
[drawer/action-drawer [[(group-details-entry chat-id)
(when inside-chat?
(add-members-entry))]
(notification-actions item inside-chat?)
(destructive-actions chat-id group-chat)]])
(defn private-group-chat-actions [muted? chat-id]
[drawer/action-drawer [(notification-actions muted? chat-id)
(destructive-actions chat-id)]])
(defn private-group-chat-actions [{:keys [chat-id group-chat] :as item} inside-chat?]
[drawer/action-drawer [(group-actions item inside-chat?)
(notification-actions item inside-chat?)
(destructive-actions chat-id group-chat)]])
(defn contact-actions [{:keys [public-key] :as contact}]
[drawer/action-drawer [[(view-profile-entry public-key)
(remove-from-contacts-entry contact)
(rename-entry)
(show-qr-entry)
(share-profile-entry)]
[(mark-untrustworthy-entry)
(block-user-entry)]]])
(defn actions [{:keys [chat-type] :as item} inside-chat?]
(case chat-type
constants/one-to-one-chat-type
[one-to-one-actions item inside-chat?]
constants/public-chat-type
[public-chat-actions item inside-chat?]
constants/private-group-chat-type
[private-group-chat-actions item inside-chat?]
[contact-actions item]))
(defn actions [chat-type chat-id]
(let [muted? (<sub [:chats/muted chat-id])]
(case chat-type
constants/one-to-one-chat-type
[one-to-one-actions muted? chat-id]
constants/public-chat-type
[public-chat-actions muted? chat-id]
constants/private-group-chat-type
[private-group-chat-actions muted? chat-id])))

View File

@ -1,29 +1,32 @@
(ns status-im.ui2.screens.chat.components.contact-item.view
(:require [status-im.utils.handlers :refer [<sub >evt]]
[quo2.foundations.typography :as typography]
(:require [quo2.foundations.typography :as typography]
[quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo.react-native :as rn]
[status-im.utils.utils :refer [get-shortened-address]]
[status-im.utils.utils :as utils]
[quo.platform :as platform]
[quo2.components.markdown.text :as text]
[status-im.ui2.screens.chat.components.message-home-item.style :as style]))
[status-im.ui2.screens.chat.components.message-home-item.style :as style]
[status-im.utils.re-frame :as rf]
[status-im.ui2.screens.chat.actions :as actions]))
(defn open-chat [chat-id]
(>evt [:dismiss-keyboard])
(rf/dispatch [:dismiss-keyboard])
(if platform/android?
(>evt [:chat.ui/navigate-to-chat-nav2 chat-id])
(>evt [:chat.ui/navigate-to-chat chat-id]))
(>evt [:search/home-filter-changed nil])
(>evt [:accept-all-activity-center-notifications-from-chat chat-id]))
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(rf/dispatch [:chat.ui/navigate-to-chat chat-id]))
(rf/dispatch [:search/home-filter-changed nil])
(rf/dispatch [:accept-all-activity-center-notifications-from-chat chat-id]))
(defn contact-item [item]
(let [{:keys [public-key ens-verified added? images]} item
display-name (first (<sub [:contacts/contact-two-names-by-identity public-key]))
photo-path (if-not (empty? images) (<sub [:chats/photo-path public-key]) nil)]
[rn/touchable-opacity (merge {:style (style/container)
:on-press #(open-chat public-key)})
display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))
photo-path (when (seq images) (rf/sub [:chats/photo-path public-key]))]
[rn/touchable-opacity (merge {:style (style/container)
:on-press #(open-chat public-key)
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item])}])})
[user-avatar/user-avatar {:full-name display-name
:profile-picture photo-path
:status-indicator? true
@ -43,7 +46,7 @@
[icons/icon :i/contact {:no-color true :size 12 :color (colors/theme-colors colors/primary-50 colors/primary-60)}]]))]
[text/text {:size :paragraph-1
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
(get-shortened-address public-key)]]
(utils/get-shortened-address public-key)]]
[rn/touchable-opacity {:style {:position :absolute
:right 20}
:active-opacity 1} ; TODO: on-long-press to be added when contact bottom sheet is implemented

View File

@ -1,14 +1,14 @@
(ns status-im.ui2.screens.chat.components.message-home-item.view
(:require [clojure.string :as string]
[status-im.utils.handlers :refer [<sub >evt]]
[status-im.utils.re-frame :as rf]
[status-im.utils.datetime :as time]
[quo2.foundations.typography :as typography]
[quo2.components.notifications.info-count :refer [info-count]]
[quo2.components.icon :as icons]
[quo2.foundations.colors :as colors]
[quo2.components.avatars.user-avatar :as user-avatar]
[quo.react-native :as rn]
[quo.platform :as platform]
[quo2.core :as quo2]
[quo2.components.markdown.text :as text]
[status-im.ui2.screens.chat.actions :as actions]
[status-im.ui2.screens.chat.components.message-home-item.style :as style]))
@ -34,7 +34,7 @@
children)
"mention"
{:components [rn/text (<sub [:contacts/contact-name-by-identity literal])]
{:components [rn/text (rf/sub [:contacts/contact-name-by-identity literal])]
:length 4} ;; we can't predict name length so take the smallest possible
"status-tag"
@ -107,19 +107,19 @@
name
unviewed-mentions-count
unviewed-messages-count]} item
display-name (if-not group-chat (first (<sub [:contacts/contact-two-names-by-identity chat-id])) name)
contact (when-not group-chat (<sub [:contacts/contact-by-address chat-id]))
photo-path (when-not (empty? (:images contact)) (<sub [:chats/photo-path chat-id]))]
display-name (if-not group-chat (first (rf/sub [:contacts/contact-two-names-by-identity chat-id])) name)
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]))]
[rn/touchable-opacity (merge {:style (style/container)
:on-press (fn []
(>evt [:dismiss-keyboard])
(rf/dispatch [:dismiss-keyboard])
(if platform/android?
(>evt [:chat.ui/navigate-to-chat-nav2 chat-id])
(>evt [:chat.ui/navigate-to-chat chat-id]))
(>evt [:search/home-filter-changed nil])
(>evt [:accept-all-activity-center-notifications-from-chat chat-id]))
:on-long-press #(>evt [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item])}])})
(rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(rf/dispatch [:chat.ui/navigate-to-chat chat-id]))
(rf/dispatch [:search/home-filter-changed nil])
(rf/dispatch [:accept-all-activity-center-notifications-from-chat chat-id]))
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [actions/actions item false])}])})
[display-pic-view group-chat color display-name photo-path]
[rn/view {:style {:margin-left 8}}
[display-name-view display-name contact timestamp]
@ -129,7 +129,7 @@
(get-in last-message [:content :text])]
[render-subheader (get-in last-message [:content :parsed-text])])]
(if (> unviewed-mentions-count 0)
[info-count unviewed-mentions-count {:top 16}]
[quo2/info-count unviewed-mentions-count {:top 16}]
(when (> unviewed-messages-count 0)
[rn/view {:style (style/count-container)}]))]))

View File

@ -579,7 +579,7 @@
"community-private-key": "Community private key",
"failed": "Failed",
"faq": "Frequently asked questions",
"fetch-messages": "Fetch messages",
"fetch-messages": "Fetch messages",
"fetch-timeline": "↓ Fetch",
"find": "Find",
"finish": "Finish",
@ -1841,5 +1841,12 @@
"pending-requests": "Pending requests",
"received": "Received",
"sent": "Sent",
"and": "and"
"and": "and",
"rename": "Rename",
"mark-untrustworthy": "Mark as Untrustworthy",
"block-user": "Block User",
"group-details": "Group details",
"edit-name-and-image": "Edit name and image",
"change-group-privacy": "Change group privacy",
"manage-members": "Manage members"
}