diff --git a/src/quo2/components/avatars/group_avatar.cljs b/src/quo2/components/avatars/group_avatar.cljs index 15fe1d79a7..6b773ad48f 100644 --- a/src/quo2/components/avatars/group_avatar.cljs +++ b/src/quo2/components/avatars/group_avatar.cljs @@ -15,18 +15,12 @@ (defn group-avatar [_] (fn [{:keys [color size]}] (let [container-size (get-in sizes [:container size]) - icon-size (get-in sizes [:icon size]) - ;; theme (or override-theme (if (colors/dark?) :dark :light)) - ] + icon-size (get-in sizes [:icon size])] [rn/view {:width container-size :height container-size :align-items :center :justify-content :center :border-radius (/ container-size 2) - :background-color color - ;; :background-color (if (= theme :light) TODO: colors/custom-color method here is not working for some reason. - ;; (colors/custom-color color 50) - ;; (colors/custom-color color 60)) - } + :background-color (colors/theme-alpha color 0.5 0.6)} [icon/icon :i/group {:size icon-size ; TODO: group icon sizes 12 and 20 (small and large) are missing :color colors/white-opa-70}]]))) diff --git a/src/react_native/core.cljs b/src/react_native/core.cljs index 553cb9f6c5..162e253e1f 100644 --- a/src/react_native/core.cljs +++ b/src/react_native/core.cljs @@ -1,7 +1,8 @@ (ns react-native.core (:require [reagent.core :as reagent] ["react-native" :as react-native] - [react-native.flat-list :as flat-list])) + [react-native.flat-list :as flat-list] + [react-native.section-list :as section-list])) (def app-state ^js (.-AppState ^js react-native)) @@ -9,7 +10,7 @@ (def scroll-view (reagent/adapt-react-class (.-ScrollView ^js react-native))) (def image (reagent/adapt-react-class (.-Image ^js react-native))) (def text (reagent/adapt-react-class (.-Text ^js react-native))) -(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native))) +(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native))) (def touchable-opacity (reagent/adapt-react-class (.-TouchableOpacity ^js react-native))) (def touchable-highlight (reagent/adapt-react-class (.-TouchableHighlight ^js react-native))) @@ -17,6 +18,8 @@ (def flat-list flat-list/flat-list) +(def section-list section-list/section-list) + (def activity-indicator (reagent/adapt-react-class (.-ActivityIndicator ^js react-native))) (def modal (reagent/adapt-react-class (.-Modal ^js react-native))) diff --git a/src/react_native/section_list.cljs b/src/react_native/section_list.cljs new file mode 100644 index 0000000000..7a96a73a2f --- /dev/null +++ b/src/react_native/section_list.cljs @@ -0,0 +1,40 @@ +(ns react-native.section-list + (:require [reagent.core :as reagent] + [react-native.flat-list :as flat-list] + ["react-native" :as react-native])) + +(def section-list-class (reagent/adapt-react-class (.-SectionList react-native))) + +(def memo-wrap-render-fn + (memoize + (fn [f render-data] + (fn [^js data] + (reagent/as-element [f (.-item data) (.-index data) (.-separators data) render-data]))))) + +(defn- wrap-render-section-header-fn [f] + (fn [^js data] + (let [^js section (.-section data)] + (reagent/as-element [f {:title (.-title section) + :data (.-data section)}])))) + +(defn- wrap-per-section-render-fn [props] + (update + (if-let [f (:render-fn props)] + (assoc (dissoc props :render-fn :render-data) :renderItem (memo-wrap-render-fn f (:render-data props))) + props) + :data to-array)) + +(defn section-list + "A wrapper for SectionList. + To render something on empty sections, use renderSectionFooter and conditionaly + render on empty data + See https://facebook.github.io/react-native/docs/sectionlist.html" + [{:keys [sections render-section-header-fn render-section-footer-fn style] :as props}] + [section-list-class + (merge (flat-list/base-list-props props) + props + (when render-section-footer-fn + {:renderSectionFooter (wrap-render-section-header-fn render-section-footer-fn)}) + {:sections (clj->js (map wrap-per-section-render-fn sections)) + :renderSectionHeader (wrap-render-section-header-fn render-section-header-fn) + :style style})]) diff --git a/src/status_im/i18n/i18n_test.cljs b/src/status_im/i18n/i18n_test.cljs index 41034ff711..e967376e5b 100644 --- a/src/status_im/i18n/i18n_test.cljs +++ b/src/status_im/i18n/i18n_test.cljs @@ -110,7 +110,7 @@ :blank-keycard-title :block :block-contact - :block-user-confirmation + :block-contact-details :blocked-users :bootnode-address :bootnode-details diff --git a/src/status_im/ui/screens/profile/components/sheets.cljs b/src/status_im/ui/screens/profile/components/sheets.cljs index 3d09c4a341..2be57aaf25 100644 --- a/src/status_im/ui/screens/profile/components/sheets.cljs +++ b/src/status_im/ui/screens/profile/components/sheets.cljs @@ -12,7 +12,7 @@ in-progress? (reagent/atom false)] [react/view {:style {:padding-top 16 :padding-horizontal 24 :padding-bottom 8}} [react/text {:style styles/sheet-text} - (i18n/label :t/block-user-confirmation)] + (i18n/label :t/block-contact-details)] [react/view {:align-items :center :margin-top 16} [quo/button {:theme :negative :disabled @in-progress? diff --git a/src/status_im/ui/screens/screens.cljs b/src/status_im/ui/screens/screens.cljs index c1cb301b59..9252dd5034 100644 --- a/src/status_im/ui/screens/screens.cljs +++ b/src/status_im/ui/screens/screens.cljs @@ -114,7 +114,8 @@ [status-im.ui.screens.wallet.buy-crypto.views :as wallet.buy-crypto] [status-im.ui.screens.wallet.recipient.views :as recipient] [status-im.ui.screens.wallet.send.views :as wallet.send] - [status-im.ui.screens.wallet.manage-connections.views :as manage-all-connections])) + [status-im.ui.screens.wallet.manage-connections.views :as manage-all-connections] + [status-im.ui2.screens.chat.group-details.view :as group-details])) (defn right-button-options [id icon] {:id id @@ -211,10 +212,9 @@ :component pin-messages/pinned-messages} {:name :group-chat-profile - :insets {:top false} ;;TODO animated-header :options {:topBar {:visible false}} - :component profile.group-chat/group-chat-profile} + :component group-details/group-details} {:name :group-chat-invite ;;TODO parameter in the event :options {:topBar {:visible false}} diff --git a/src/status_im/ui2/screens/chat/actions.cljs b/src/status_im/ui2/screens/chat/actions.cljs index 03f5d1ec0d..2d43cddda0 100644 --- a/src/status_im/ui2/screens/chat/actions.cljs +++ b/src/status_im/ui2/screens/chat/actions.cljs @@ -72,7 +72,7 @@ (defn block-user-action [{:keys [public-key] :as item}] (hide-sheet-and-dispatch [:bottom-sheet/show-sheet {:content (fn [] (common/alert {:title (i18n/label :t/block-user?) - :description (i18n/label :t/block-user-confirmation) + :description (i18n/label :t/block-contact-details) :context item :button-text (i18n/label :t/block-user) :on-press #(hide-sheet-and-dispatch [:contact.ui/block-contact-confirmed public-key])}))}])) @@ -262,8 +262,8 @@ :sub-label nil :chevron? false})) -(defn destructive-actions [{:keys [chat-id group-chat] :as item}] - [(clear-history-entry chat-id) +(defn destructive-actions [{:keys [group-chat] :as item}] + [(clear-history-entry item) (if group-chat (leave-group-entry item) (delete-chat-entry item))]) @@ -311,12 +311,13 @@ (notification-actions item inside-chat?) (destructive-actions item)]]) -(defn contact-actions [{:keys [public-key] :as contact}] +(defn contact-actions [{:keys [public-key added] :as contact}] [drawer/action-drawer [[(view-profile-entry public-key) - (remove-from-contacts-entry contact) - (rename-entry) - (show-qr-entry) - (share-profile-entry)] + (when added + (remove-from-contacts-entry contact) + (rename-entry) + (show-qr-entry) + (share-profile-entry))] [(mark-untrustworthy-entry) (block-user-entry contact)]]]) diff --git a/src/status_im/ui2/screens/chat/components/contact_item/view.cljs b/src/status_im/ui2/screens/chat/components/contact_item/view.cljs index ef4e7ff832..595757243f 100644 --- a/src/status_im/ui2/screens/chat/components/contact_item/view.cljs +++ b/src/status_im/ui2/screens/chat/components/contact_item/view.cljs @@ -22,11 +22,13 @@ (defn contact-item [item] (let [{:keys [public-key ens-verified added? images]} item 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]))] + photo-path (when (seq images) (rf/sub [:chats/photo-path public-key])) + current-pk (rf/sub [:multiaccount/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])}])}) + :on-long-press #(when-not (= current-pk public-key) + (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 @@ -44,11 +46,14 @@ (when added? [rn/view {:style {:margin-left 5 :margin-top 4}} [icons/icon :i/contact {:no-color true :size 12 :color (colors/theme-colors colors/primary-50 colors/primary-60)}]]))] - [text/text {:size :paragraph-1 + [text/text {:size :paragraph-1 :style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}} (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 - [icons/icon :i/options {:size 20 :color (colors/theme-colors colors/primary-50 colors/primary-60)}]]])) + (when-not (= current-pk public-key) + [rn/touchable-opacity {:style {:position :absolute + :right 20} + :active-opacity 1 + :on-press #(rf/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [actions/actions item])}])} + [icons/icon :i/options {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]])])) diff --git a/src/status_im/ui2/screens/chat/group_details/style.cljs b/src/status_im/ui2/screens/chat/group_details/style.cljs new file mode 100644 index 0000000000..0654f7247d --- /dev/null +++ b/src/status_im/ui2/screens/chat/group_details/style.cljs @@ -0,0 +1,20 @@ +(ns status-im.ui2.screens.chat.group-details.style + (:require [quo2.foundations.colors :as colors])) + +(defn actions-view [] + {:flex-direction :row + :justify-content :space-between + :margin-vertical 20 + :padding-horizontal 20}) + +(defn action-container [color] + {:background-color (colors/theme-alpha color 0.1 0.1) + :flex 0.29 + :border-radius 16 + :padding 12}) + +(defn count-container [] + {:width 16 + :height 16 + :border-radius 6 + :background-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5)}) diff --git a/src/status_im/ui2/screens/chat/group_details/view.cljs b/src/status_im/ui2/screens/chat/group_details/view.cljs new file mode 100644 index 0000000000..544e1bfcb8 --- /dev/null +++ b/src/status_im/ui2/screens/chat/group_details/view.cljs @@ -0,0 +1,90 @@ +(ns status-im.ui2.screens.chat.group-details.view + (:require [react-native.core :as rn] + [quo2.foundations.colors :as colors] + [status-im.ui2.screens.chat.group-details.style :as style] + [quo2.core :as quo2] + [utils.re-frame :as rf] + [i18n.i18n :as i18n] + [status-im.ui2.screens.chat.components.contact-item.view :as contact-item])) + +(defn back-button [] + [quo2/button {:type :grey + :size 32 + :width 32 + :style {:margin-left 20} + :accessibility-label :back-button + :on-press #(rf/dispatch [:navigate-back])} + [quo2/icon :i/arrow-left {:color (colors/theme-colors colors/neutral-100 colors/white)}]]) + +(defn options-button [] + [quo2/button {:type :grey + :size 32 + :width 32 + :style {:margin-right 20} + :accessibility-label :options-button} + [quo2/icon :i/options {:color (colors/theme-colors colors/neutral-100 colors/white)}]]) + +(defn count-container [count] + [rn/view {:style (style/count-container)} + [quo2/text {:size :label + :weight :medium + :style {:text-align :center}} count]]) + +(defn prepare-members [members] + (let [admins (filter :admin? members) + online (filter #(and (not (:admin? %)) (:online? %)) members) + offline (filter #(and (not (:admin? %)) (not (:online? %))) members)] + (vals (cond-> {} + (seq admins) (assoc :owner {:title "Owner" :data admins}) + (seq online) (assoc :online {:title "Online" :data online}) + (seq offline) (assoc :offline {:title "Offline" :data offline}))))) + +(defn contacts-section-header [{:keys [title]}] + [rn/view {:style {:padding-horizontal 20 :border-top-width 1 :border-top-color colors/neutral-20 :padding-vertical 8 :margin-top 8}} + [quo2/text {:size :paragraph-2 + :weight :medium + :style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}} title]]) + +(defn group-details [] + (let [{:keys [admins chat-id chat-name color public?]} (rf/sub [:chats/current-chat]) + members (rf/sub [:contacts/current-chat-contacts]) + sectioned-members (prepare-members members) + pinned-messages (rf/sub [:chats/pinned chat-id]) + current-pk (rf/sub [:multiaccount/public-key]) + admin? (get admins current-pk)] + [rn/view {:style {:flex 1 + :background-color (colors/theme-colors colors/white colors/neutral-95)}} + [quo2/header {:left-component [back-button] + :right-component [options-button] + :background (colors/theme-colors colors/white colors/neutral-95)}] + [rn/view {:style {:flex-direction :row + :margin-top 12 + :padding-horizontal 20}} + [quo2/group-avatar {:color color + :size :medium}] + [quo2/text {:weight :semi-bold + :size :heading-1 + :style {:margin-horizontal 8}} chat-name] + [rn/view {:style {:margin-top 8}} + [quo2/icon (if public? :i/world :i/privacy) {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]] + [rn/view {:style (style/actions-view)} + [rn/touchable-opacity {:style (style/action-container color)} + [rn/view {:style {:flex-direction :row + :justify-content :space-between}} + [quo2/icon :i/pin {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] + [count-container (count pinned-messages)]] + [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label :t/pinned-messages-2)]] + [rn/touchable-opacity {:style (style/action-container color)} + [quo2/icon :i/activity-center {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] + [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label :t/mute-group)]] + [rn/touchable-opacity {:style (style/action-container color)} + [rn/view {:style {:flex-direction :row + :justify-content :space-between}} + [quo2/icon :i/add-user {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] + [count-container (count members)]] + [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label (if admin? :t/manage-members :t/add-members))]]] + [rn/section-list {:key-fn :title + :sticky-section-headers-enabled false + :sections sectioned-members + :render-section-header-fn contacts-section-header + :render-fn contact-item/contact-item}]])) diff --git a/src/status_im/ui2/screens/chat/home.cljs b/src/status_im/ui2/screens/chat/home.cljs index 6af3939c60..f0eb7ef5ad 100644 --- a/src/status_im/ui2/screens/chat/home.cljs +++ b/src/status_im/ui2/screens/chat/home.cljs @@ -21,7 +21,8 @@ [quo2.components.markdown.text :as quo2.text] [status-im.qr-scanner.core :as qr-scanner] [status-im.ui.components.chat-icon.styles :as chat-icon.styles] - [quo.react-native :as rn] + [react-native.core :as rn] + [quo.react-native :as quo.rn] [quo.react] [quo2.foundations.colors :as colors] [quo2.foundations.typography :as typography] @@ -279,7 +280,7 @@ :render-fn messages-home-item}] [rn/view {:style {:flex 1}} (when (> (count requests) 0) [contact-requests requests]) - [list/section-list + [rn/section-list {:key-fn :title :sticky-section-headers-enabled false :sections contacts @@ -355,9 +356,9 @@ [:f> (fn [] (quo.react/effect! #(re-frame/dispatch [:get-activity-center-notifications])) - [rn/keyboard-avoiding-view {:style {:flex 1 - :background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)} - :ignore-offset true} + [quo.rn/keyboard-avoiding-view {:style {:flex 1 + :background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)} + :ignore-offset true} [topbar/topbar {:navigation :none :use-insets true :background (colors/theme-colors colors/neutral-5 colors/neutral-95) diff --git a/src/status_im2/setup/i18n_test.cljs b/src/status_im2/setup/i18n_test.cljs index 9cdf1a63eb..4bdff45c71 100644 --- a/src/status_im2/setup/i18n_test.cljs +++ b/src/status_im2/setup/i18n_test.cljs @@ -108,7 +108,7 @@ :blank-keycard-title :block :block-contact - :block-user-confirmation + :block-contact-details :blocked-users :bootnode-address :bootnode-details diff --git a/translations/en.json b/translations/en.json index c495c311c2..f77bf8d0ef 100644 --- a/translations/en.json +++ b/translations/en.json @@ -90,7 +90,7 @@ "block": "Block", "unblock": "Unblock", "block-contact": "Block this user", - "block-user-confirmation": "Blocking will delete this user's previous messages and stop new ones from reaching you", + "block-contact-details": "Blocking will delete this user's previous messages and stop new ones from reaching you", "blocked-users": "Blocked users", "bootnode-address": "Bootnode address", "bootnode-details": "Bootnode details", @@ -1673,6 +1673,7 @@ "accept-and-continue": "Accept and continue", "empty-activity-center": "Your chat notifications\nwill appear here", "pinned-messages": "Pinned messages", + "pinned-messages-2": "Pinned \nmessages", "pinned-a-message": "pinned a message", "pin": "Pin", "unpin": "Unpin", @@ -1856,6 +1857,7 @@ "edit-name-and-image": "Edit name and image", "change-group-privacy": "Change group privacy", "manage-members": "Manage members", + "mute-group": "Mute group", "delete-chat?": "Delete Chat?", "mark-user-untrustworthy": "Mark {{username}} as untrustworthy", "leave-group?": "Leave Group?",